Hello community,
here is the log from the commit of package forkstat for openSUSE:Factory checked in at 2017-06-27 10:21:47
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/forkstat (Old)
and /work/SRC/openSUSE:Factory/.forkstat.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "forkstat"
Tue Jun 27 10:21:47 2017 rev:4 rq:506335 version:0.02.00
Changes:
--------
--- /work/SRC/openSUSE:Factory/forkstat/forkstat.changes 2017-06-26 15:53:32.992775741 +0200
+++ /work/SRC/openSUSE:Factory/.forkstat.new/forkstat.changes 2017-06-27 10:21:54.329825789 +0200
@@ -1,0 +2,24 @@
+Sun Jun 25 19:12:00 UTC 2017 - mardnh@gmx.de
+
+- update to version 0.02.00
+ * Makefile: update version and change codename
+ * Minor tweaks to the manual, cosmetic changes
+ * Move arrays to end of stacks to help avoid any stack smashing
+ * Minor source clean-up
+ * Avoid TOCTOU race on stat + open
+ * Use alternative ptrace pid info
+ * Add -x extra UID and TTY information option
+ * Add uid/sid event tracing
+ * Display name of events on -e option when invalid event used
+ * Add ptrace event spying
+ * Fix realtime flag opts mask
+ * Fix -r help option
+ * Add extra spacing in heading as it is offset by one after PID
+ * Remove old set_priority code now that -r replaces it
+ * Manpage: fix pdf warning:
+ * Makefile: add pdf man page rule and add .PHONEYs
+ * Add Philipp Gesang to the man page for kudos for contributions.
+ * Add -r real time scheduling option
+ * Put help options into one large printf statement
+
+-------------------------------------------------------------------
Old:
----
forkstat-0.01.19.tar.gz
New:
----
forkstat-0.02.00.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ forkstat.spec ++++++
--- /var/tmp/diff_new_pack.Sc9sQb/_old 2017-06-27 10:21:54.889746653 +0200
+++ /var/tmp/diff_new_pack.Sc9sQb/_new 2017-06-27 10:21:54.889746653 +0200
@@ -18,7 +18,7 @@
Name: forkstat
-Version: 0.01.19
+Version: 0.02.00
Release: 0
Summary: Process fork/exec/exit monitoring tool
License: GPL-2.0+
++++++ forkstat-0.01.19.tar.gz -> forkstat-0.02.00.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/forkstat-0.01.19/Makefile new/forkstat-0.02.00/Makefile
--- old/forkstat-0.01.19/Makefile 2017-06-21 18:59:39.000000000 +0200
+++ new/forkstat-0.02.00/Makefile 2017-06-24 21:43:28.000000000 +0200
@@ -16,9 +16,9 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
-VERSION=0.01.19
+VERSION=0.02.00
#
-# Version "Frantic Forking Finder"
+# Version "Perspicacious Process Peeker"
#
CFLAGS += -Wall -Wextra -DVERSION='"$(VERSION)"' -O2
@@ -43,6 +43,7 @@
forkstat.8.gz: forkstat.8
gzip -c $< > $@
+.PHONEY: dist
dist:
rm -rf forkstat-$(VERSION)
mkdir forkstat-$(VERSION)
@@ -51,10 +52,17 @@
tar -zcf forkstat-$(VERSION).tar.gz forkstat-$(VERSION)
rm -rf forkstat-$(VERSION)
+.PHONEY: pdf
+pdf:
+ man -t ./forkstat.8 | ps2pdf - > forkstat.pdf
+
+.PHONEY: clean
clean:
rm -f forkstat forkstat.o forkstat.8.gz
rm -f forkstat-$(VERSION).tar.gz
+ rm -f forkstat.pdf
+.PHONEY: install
install: forkstat forkstat.8.gz
mkdir -p ${DESTDIR}${BINDIR}
cp forkstat ${DESTDIR}${BINDIR}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/forkstat-0.01.19/forkstat.8 new/forkstat-0.02.00/forkstat.8
--- old/forkstat-0.01.19/forkstat.8 2017-06-21 18:59:39.000000000 +0200
+++ new/forkstat-0.02.00/forkstat.8 2017-06-24 21:43:28.000000000 +0200
@@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1)
-.TH FORKSTAT 8 "21 June, 2017"
+.TH FORKSTAT 8 "24 June, 2017"
.\" Please adjust this date whenever revising the manpage.
.\"
.\" Some roff macros, for reference:
@@ -26,9 +26,11 @@
.RI [ \-e ]
.RI [ \-h ]
.RI [ \-l ]
+.RI [ \-r ]
.RI [ \-s ]
.RI [ \-S ]
.RI [ \-q ]
+.RI [ \-x ]
.br
.SH DESCRIPTION
@@ -43,12 +45,12 @@
Forkstat will display several columns of process related information:
.TS
-l lw(5i).
+l l.
\fBTitle Description\fR
Time When the fork/exec/exit event occurred.
Event Type of event.
PID Process or thread ID.
-Info Parent or child if a fork, or exit value.
+Info Parent or child if a fork, or process exit(2) value.
Duration T{
On exit, the duration the command ran for in seconds.
Process The process name. The name will be in [ ] brackets if it is a kernel thread.
@@ -67,7 +69,7 @@
specify events to trace as a comma seperated list. By default the fork, exec and exit
events are traced. Available events are:
.TS
-l lw(5i).
+l lw(4i).
\fBEvent Description\fR
fork forks
exec execs
@@ -75,12 +77,22 @@
core core dumps
comm process name changes in comm field
clone clone (normally on thread creation)
+ptrce ptrace attach or detach
+uid uid/gid events
+sid sid events
all all the events above
.TE
.TP
.B \-h
show brief help summary.
.TP
+.B \-l
+set stdout to line-buffered mode.
+.TP
+.B \-r
+run with real time FIFO scheduling with maximum priority to keep up with high volumes
+of process events.
+.TP
.B \-s
show short process name information.
.TP
@@ -90,8 +102,8 @@
.B \-q
run quietly and enable the \-S option.
.TP
-.B \-l
-set stdout to line-buffered mode.
+.B \-x
+show extra process related information: user ID and TTY of the process.
.SH EXAMPLES
.LP
Show process activity with short process names and directory base path stripped off:
@@ -121,7 +133,8 @@
.SH SEE ALSO
.BR vmstat (8)
.SH AUTHOR
-forkstat was written by Colin King
+forkstat was written by Colin King . Thanks also
+for contributions from Philipp Gesang.
.PP
This manual page was written by Colin King ,
for the Ubuntu project (but may be used by others).
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/forkstat-0.01.19/forkstat.c new/forkstat-0.02.00/forkstat.c
--- old/forkstat-0.01.19/forkstat.c 2017-06-21 18:59:39.000000000 +0200
+++ new/forkstat-0.02.00/forkstat.c 2017-06-24 21:43:28.000000000 +0200
@@ -39,6 +39,7 @@
#include
#include
#include
+#include
#include
#include
@@ -52,24 +53,32 @@
#include
#define APP_NAME "forkstat"
-#define MAX_PIDS (32769) /* Hash Max PIDs */
+#define MAX_PIDS (32769) /* Hash Max PIDs */
-#define NULL_PID (-1)
-
-#define OPT_CMD_LONG (0x00000001)
-#define OPT_CMD_SHORT (0x00000002)
-#define OPT_CMD_DIRNAME_STRIP (0x00000004)
-#define OPT_STATS (0x00000008)
-#define OPT_QUIET (0x00000010)
-
-#define OPT_EV_FORK (0x00000100)
-#define OPT_EV_EXEC (0x00000200)
-#define OPT_EV_EXIT (0x00000400)
-#define OPT_EV_CORE (0x00000800)
-#define OPT_EV_COMM (0x00001000)
-#define OPT_EV_CLNE (0x00002000)
-#define OPT_EV_MASK (0x00003f00)
-#define OPT_EV_ALL (OPT_EV_MASK)
+#define NULL_PID (pid_t)(-1)
+#define NULL_UID (uid_t)(-1)
+#define NULL_GID (gid_t)(-1)
+#define NULL_TTY (dev_t)(-1)
+
+#define OPT_CMD_LONG (0x00000001) /* Long command line info */
+#define OPT_CMD_SHORT (0x00000002) /* Short command line info */
+#define OPT_CMD_DIRNAME_STRIP (0x00000004) /* Strip dirpath from command */
+#define OPT_STATS (0x00000008) /* Show stats at end of run */
+#define OPT_QUIET (0x00000010) /* Run quietly */
+#define OPT_REALTIME (0x00000020) /* Run with Real Time scheduling */
+#define OPT_EXTRA (0x00000040) /* Show extra stats */
+
+#define OPT_EV_FORK (0x00000100) /* Fork event */
+#define OPT_EV_EXEC (0x00000200) /* Exec event */
+#define OPT_EV_EXIT (0x00000400) /* Exit event */
+#define OPT_EV_CORE (0x00000800) /* Coredump event */
+#define OPT_EV_COMM (0x00001000) /* Comm proc info event */
+#define OPT_EV_CLNE (0x00002000) /* Clone event */
+#define OPT_EV_PTRC (0x00004000) /* Ptrace event */
+#define OPT_EV_UID (0x00008000) /* UID event */
+#define OPT_EV_SID (0x00010000) /* SID event */
+#define OPT_EV_MASK (0x0001ff00) /* Event mask */
+#define OPT_EV_ALL (OPT_EV_MASK) /* All events */
#define GOT_TGID (0x01)
#define GOT_PPID (0x02)
@@ -79,11 +88,13 @@
#define LINUX_VERSION_CODE KERNEL_VERSION(2,0,0)
#endif
-
/* /proc info cache */
typedef struct proc_info {
struct proc_info *next; /* next proc info in hashed linked list */
pid_t pid; /* Process ID */
+ uid_t uid; /* User ID */
+ gid_t gid; /* GUID */
+ dev_t tty; /* TTY dev */
char *cmdline; /* /proc/pid/cmdline text */
bool kernel_thread; /* true if a kernel thread */
struct timeval start; /* time when process started */
@@ -96,13 +107,16 @@
} kernel_task_info;
typedef enum {
- STAT_FORK = 0,
- STAT_EXEC,
- STAT_EXIT,
- STAT_CORE,
- STAT_COMM,
- STAT_CLNE,
- STAT_LAST
+ STAT_FORK = 0, /* Fork */
+ STAT_EXEC, /* Exec */
+ STAT_EXIT, /* Exit */
+ STAT_CORE, /* Core dump */
+ STAT_COMM, /* Proc comm field change */
+ STAT_CLNE, /* Clone */
+ STAT_PTRC, /* Ptrace */
+ STAT_UID, /* UID change */
+ STAT_SID, /* SID change */
+ STAT_LAST /* Always last sentinal */
} event_t;
typedef struct proc_stats {
@@ -127,6 +141,9 @@
{ "core", "Coredump", OPT_EV_CORE, STAT_CORE },
{ "comm", "Comm", OPT_EV_COMM, STAT_COMM },
{ "clone","Clone", OPT_EV_CLNE, STAT_CLNE },
+ { "ptrce","Ptrace", OPT_EV_PTRC, STAT_PTRC },
+ { "uid", "Uid", OPT_EV_UID, STAT_UID },
+ { "sid", "Sid", OPT_EV_SID, STAT_SID },
{ "all", "", OPT_EV_ALL, 0 },
{ NULL, NULL, 0, 0 }
};
@@ -144,6 +161,7 @@
/* Default void no process info struct */
static proc_info_t no_info = {
.pid = NULL_PID,
+ .uid = NULL_UID,
.cmdline = "<unknown>",
.kernel_thread = false,
.start = { 0, 0 },
@@ -206,6 +224,102 @@
static proc_info_t *proc_info_get(pid_t pid);
/*
+ * get_username()
+ * get username from a given user id
+ */
+static char *get_username(const uid_t uid)
+{
+ struct passwd *pwd;
+ static char buf[12];
+
+ pwd = getpwuid(uid);
+ if (pwd)
+ return pwd->pw_name;
+
+ snprintf(buf, sizeof(buf), "%d", uid);
+ return buf;
+}
+
+/*
+ * get_tty()
+ * get a TTY name with device ID dev
+ */
+static char *get_tty(const dev_t dev)
+{
+ DIR *dir;
+ struct dirent *dirent;
+ static char tty[16];
+
+ strncpy(tty, "?", sizeof(tty));
+
+ dir = opendir("/dev/pts");
+ if (!dir)
+ goto err;
+
+ while ((dirent = readdir(dir))) {
+ struct stat buf;
+ char path[PATH_MAX];
+
+ if (dirent->d_name[0] == '.')
+ continue;
+
+ snprintf(path, sizeof(path), "/dev/pts/%s", dirent->d_name);
+ if (stat(path, &buf) < 0)
+ continue;
+
+ if (buf.st_rdev == dev) {
+ snprintf(tty, sizeof(tty), "pts/%s", dirent->d_name);
+ break;
+ }
+ }
+
+ (void)closedir(dir);
+err:
+ return tty;
+}
+
+/*
+ * get_extra()
+ * quick and dirty way to get UID and GID from a PID,
+ * note that this does not cater of changes
+ * because of use of an effective ID.
+ */
+static void get_extra(const pid_t pid, proc_info_t *info)
+{
+ ssize_t ret;
+ long dev;
+ int fd;
+ char path[PATH_MAX];
+ char buffer[4096];
+ struct stat buf;
+
+ info->uid = NULL_UID;
+ info->gid = NULL_GID;
+ info->tty = NULL_TTY;
+
+ if (!(opt_flags & OPT_EXTRA))
+ return;
+
+ snprintf(path, sizeof(path), "/proc/%u/stat", pid);
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return;
+
+ if (fstat(fd, &buf) == 0) {
+ info->uid = buf.st_uid;
+ info->gid = buf.st_gid;
+ }
+
+ ret = read(fd, buffer, sizeof(buffer));
+ (void)close(fd);
+ if (ret < 0)
+ return;
+
+ if (sscanf(buffer, "%*d %*s %*s %*d %*d %*d %ld", &dev) == 1)
+ info->tty = (dev_t)dev;
+}
+
+/*
* pid_max_digits()
* determine (or guess) maximum digits of pids
*/
@@ -249,14 +363,15 @@
static pid_t get_parent_pid(const pid_t pid, bool *is_thread)
{
FILE *fp;
- char path[PATH_MAX];
- char buffer[4096];
pid_t tgid = 0, ppid = 0;
unsigned int got = 0;
+ char path[PATH_MAX];
+ char buffer[4096];
*is_thread = false;
snprintf(path, sizeof(path), "/proc/%u/status", pid);
- if ((fp = fopen(path, "r")) == NULL)
+ fp = fopen(path, "r");
+ if (!fp)
return 0;
while (((got & GOT_ALL) != GOT_ALL) &&
@@ -300,10 +415,10 @@
*/
static bool sane_proc_pid_info(void)
{
- FILE *fp;
static const char pattern[] = "container=";
- const char *ptr = pattern;
+ FILE *fp;
bool ret = true;
+ const char *ptr = pattern;
fp = fopen("/proc/1/environ", "r");
if (!fp)
@@ -344,7 +459,7 @@
} else {
/* In side a container, make a guess at kernel threads */
int i;
- pid_t pgid = getpgid(id);
+ const pid_t pgid = getpgid(id);
/* This fails for kernel threads inside a container */
if (pgid >= 0)
@@ -397,7 +512,7 @@
static int tty_height(void)
{
#ifdef TIOCGWINSZ
- int fd = 0;
+ const int fd = 0;
struct winsize ws;
/* if tty and we can get a sane width, return it */
@@ -423,8 +538,9 @@
pid_size = pid_max_digits();
- printf("Time Event %*.*s Info Duration Process\n",
- pid_size, pid_size, "PID");
+ printf("Time Event %*.*s %sInfo Duration Process\n",
+ pid_size, pid_size, "PID",
+ (opt_flags & OPT_EXTRA) ? " UID TTY " : "");
}
/*
@@ -433,7 +549,7 @@
*/
static void row_increment(void)
{
- int tty_rows = tty_height();
+ const int tty_rows = tty_height();
row++;
if ((tty_rows > 2) && (row >= tty_rows)) {
@@ -504,11 +620,11 @@
stats = stats->next;
}
stats = calloc(1, sizeof(*stats));
- if (stats == NULL)
+ if (!stats)
return; /* silently ignore */
stats->name = strdup(name);
- if (stats->name == NULL) {
+ if (!stats->name) {
free(stats);
return;
}
@@ -560,7 +676,7 @@
printf(" Total Process\n");
sorted = calloc(n, sizeof(proc_stats_t *));
- if (sorted == NULL) {
+ if (!sorted) {
fprintf(stderr, "Cannot sort statistics, out of memory.\n");
return;
}
@@ -609,9 +725,9 @@
*/
static char *proc_comm(const pid_t pid)
{
- char buffer[4096];
int fd;
ssize_t ret;
+ char buffer[4096];
snprintf(buffer, sizeof(buffer), "/proc/%d/comm", pid);
if ((fd = open(buffer, O_RDONLY)) < 0) {
@@ -632,17 +748,17 @@
*/
static char *proc_cmdline(const pid_t pid)
{
- char buffer[4096];
char *ptr;
int fd;
ssize_t ret;
+ char buffer[4096];
snprintf(buffer, sizeof(buffer), "/proc/%d/cmdline", pid);
if ((fd = open(buffer, O_RDONLY)) < 0) {
return proc_comm(pid);
}
- memset(buffer, 0, sizeof(buffer));
+ (void)memset(buffer, 0, sizeof(buffer));
if ((ret = read(fd, buffer, sizeof(buffer) - 1)) <= 0) {
(void)close(fd);
return proc_comm(pid);
@@ -686,11 +802,11 @@
*/
static proc_info_t *proc_info_get(const pid_t pid)
{
- size_t i = proc_info_hash(pid);
+ const size_t i = proc_info_hash(pid);
proc_info_t *info = proc_info[i];
while (info) {
- if (proc_info[i]->pid == pid)
+ if (info->pid == pid)
return info;
info = info->next;
}
@@ -703,12 +819,14 @@
*/
static void proc_info_free(const pid_t pid)
{
- size_t i = proc_info_hash(pid);
+ const size_t i = proc_info_hash(pid);
proc_info_t *info = proc_info[i];
while (info) {
if (info->pid == pid) {
info->pid = NULL_PID;
+ info->uid = NULL_UID;
+ info->gid = NULL_GID;
free(info->cmdline);
info->cmdline = NULL;
return;
@@ -748,7 +866,8 @@
if (info == &no_info)
return &no_info;
- if ((newcmd = proc_cmdline(pid)) == NULL)
+ newcmd = proc_cmdline(pid);
+ if (!newcmd)
return &no_info;
free(info->cmdline);
@@ -763,7 +882,7 @@
*/
static proc_info_t *proc_info_add(const pid_t pid, struct timeval *tv)
{
- size_t i = proc_info_hash(pid);
+ const size_t i = proc_info_hash(pid);
proc_info_t *info;
char *cmdline;
@@ -779,8 +898,9 @@
info = info->next;
}
- if (info == NULL) {
- if ((info = calloc(1, sizeof(proc_info_t))) == NULL) {
+ if (!info) {
+ info = calloc(1, sizeof(proc_info_t));
+ if (!info) {
fprintf(stderr, "Cannot allocate all proc info\n");
free(cmdline);
return NULL;
@@ -790,6 +910,7 @@
}
info->cmdline = cmdline;
info->pid = pid;
+ get_extra(pid, info);
info->kernel_thread = pid_a_kernel_thread(cmdline, pid);
if (tv)
@@ -814,7 +935,8 @@
snprintf(path, sizeof(path), "/proc/%i/task", pid);
- if ((dir = opendir(path)) == NULL)
+ dir = opendir(path);
+ if (!dir)
return;
while ((dirent = readdir(dir))) {
@@ -840,7 +962,8 @@
DIR *dir;
struct dirent *dirent;
- if ((dir = opendir("/proc")) == NULL)
+ dir = opendir("/proc");
+ if (!dir)
return -1;
while ((dirent = readdir(dir))) {
@@ -860,6 +983,24 @@
return 0;
}
+static char *extra_info(const uid_t uid)
+{
+ static char buf[20];
+
+ *buf = '\0';
+ if (opt_flags & OPT_EXTRA) {
+ const proc_info_t *info = proc_info_get(uid);
+
+ if (info && info->uid != NULL_UID)
+ snprintf(buf, sizeof(buf), "%6d %-6.6s ", info->uid, get_tty(info->tty));
+ else
+ snprintf(buf, sizeof(buf), "%14s", "");
+ }
+
+ return buf;
+}
+
+
/*
* handle_sig()
* catch signal and flag a stop
@@ -887,7 +1028,7 @@
return -1;
}
- memset(&addr, 0, sizeof(addr));
+ (void)memset(&addr, 0, sizeof(addr));
addr.nl_pid = getpid();
addr.nl_family = AF_NETLINK;
addr.nl_groups = CN_IDX_PROC;
@@ -908,19 +1049,19 @@
*/
static int netlink_listen(const int sock)
{
- struct iovec iov[3];
+ enum proc_cn_mcast_op op;
struct nlmsghdr nlmsghdr;
struct cn_msg cn_msg;
- enum proc_cn_mcast_op op;
+ struct iovec iov[3];
- memset(&nlmsghdr, 0, sizeof(nlmsghdr));
+ (void)memset(&nlmsghdr, 0, sizeof(nlmsghdr));
nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(cn_msg) + sizeof(op));
nlmsghdr.nlmsg_pid = getpid();
nlmsghdr.nlmsg_type = NLMSG_DONE;
iov[0].iov_base = &nlmsghdr;
iov[0].iov_len = sizeof(nlmsghdr);
- memset(&cn_msg, 0, sizeof(cn_msg));
+ (void)memset(&cn_msg, 0, sizeof(cn_msg));
cn_msg.id.idx = CN_IDX_PROC;
cn_msg.id.val = CN_VAL_PROC;
cn_msg.len = sizeof(enum proc_cn_mcast_op);
@@ -935,34 +1076,6 @@
}
/*
- * set_prioity
- * set high priority to try and get netlink activty
- * before short lived processes die
- */
-static void set_priority(void)
-{
- int max;
- struct sched_param param;
- int sched;
-
-#if defined(SCHED_DEADLINE)
- sched = SCHED_DEADLINE;
-#elif defined(SCHED_SCHED_FIFO)
- sched = SCHED_FIFO;
-#elif defined(SCHED_RR)
- sched = SCHED_FIFO;
-#else
- sched = SCHED_OTHER; /* Oh well */
-#endif
- if ((max = sched_get_priority_max(sched)) < 0)
- return;
-
- memset(¶m, 0, sizeof(param));
- param.sched_priority = max;
- (void)sched_setscheduler(getpid(), sched, ¶m);
-}
-
-/*
* monitor()
* monitor system activity
*/
@@ -972,7 +1085,6 @@
const int pid_size = pid_max_digits();
print_heading();
- set_priority();
while (!stop_recv) {
ssize_t len;
@@ -982,7 +1094,8 @@
return 0;
}
if (len == -1) {
- int err = errno;
+ const int err = errno;
+
switch (err) {
case EINTR:
return 0;
@@ -1020,7 +1133,7 @@
struct tm tm;
char when[10];
time_t now;
- pid_t ppid;
+ pid_t pid, ppid;
bool is_thread;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
@@ -1059,32 +1172,35 @@
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
case PROC_EVENT_FORK:
ppid = get_parent_pid(proc_ev->event_data.fork.child_pid, &is_thread);
+ pid = proc_ev->event_data.fork.child_pid;
proc_stats_account(proc_ev->event_data.fork.parent_pid,
is_thread ? STAT_CLNE : STAT_FORK);
if (gettimeofday(&tv, NULL) < 0) {
- memset(&tv, 0, sizeof tv);
+ (void)memset(&tv, 0, sizeof tv);
}
info1 = proc_info_get(ppid);
- info2 = proc_info_add(proc_ev->event_data.fork.child_pid, &tv);
+ info2 = proc_info_add(pid, &tv);
if (!(opt_flags & OPT_QUIET) &&
(((opt_flags & OPT_EV_FORK) && !is_thread) ||
((opt_flags & OPT_EV_CLNE) && is_thread))) {
if (info1 != NULL && info2 != NULL) {
char *type = is_thread ? "clone" : "fork";
row_increment();
- printf("%s %-5.5s %*d parent %8s %s%s%s\n",
+ printf("%s %-5.5s %*d %sparent %8s %s%s%s\n",
when,
type,
pid_size, ppid,
+ extra_info(ppid),
"",
info1->kernel_thread ? "[" : "",
info1->cmdline,
info1->kernel_thread ? "]" : "");
row_increment();
- printf("%s %-5.5s %*d %-6.6s %8s %s%s%s\n",
+ printf("%s %-5.5s %*d %s%6.6s %8s %s%s%s\n",
when,
type,
- pid_size, proc_ev->event_data.fork.child_pid,
+ pid_size, pid,
+ extra_info(pid),
is_thread ? "thread" : "child",
"",
info1->kernel_thread ? "[" : "",
@@ -1095,12 +1211,14 @@
break;
case PROC_EVENT_EXEC:
proc_stats_account(proc_ev->event_data.exec.process_pid, STAT_EXEC);
- info1 = proc_info_update(proc_ev->event_data.exec.process_pid);
+ pid = proc_ev->event_data.exec.process_pid;
+ info1 = proc_info_update(pid);
if (!(opt_flags & OPT_QUIET) && (opt_flags & OPT_EV_EXEC)) {
row_increment();
- printf("%s exec %*d %8s %s%s%s\n",
+ printf("%s exec %*d %s %8s %s%s%s\n",
when,
- pid_size, proc_ev->event_data.exec.process_pid,
+ pid_size, pid,
+ extra_info(pid),
"",
info1->kernel_thread ? "[" : "",
info1->cmdline,
@@ -1110,12 +1228,13 @@
case PROC_EVENT_EXIT:
proc_stats_account(proc_ev->event_data.exit.process_pid, STAT_EXIT);
if (!(opt_flags & OPT_QUIET) && (opt_flags & OPT_EV_EXIT)) {
- info1 = proc_info_get(proc_ev->event_data.exit.process_pid);
+ pid = proc_ev->event_data.exit.process_pid;
+ info1 = proc_info_get(pid);
if (info1->start.tv_sec) {
double d1, d2;
if (gettimeofday(&tv, NULL) < 0) {
- memset(&tv, 0, sizeof tv);
+ (void)memset(&tv, 0, sizeof tv);
}
d1 = timeval_to_double(&info1->start);
d2 = timeval_to_double(&tv);
@@ -1124,9 +1243,10 @@
snprintf(duration, sizeof(duration), "unknown");
}
row_increment();
- printf("%s exit %*d %5d %8s %s%s%s\n",
+ printf("%s exit %*d %s%6d %8s %s%s%s\n",
when,
- pid_size, proc_ev->event_data.exit.process_pid,
+ pid_size, pid,
+ extra_info(pid),
proc_ev->event_data.exit.exit_code,
duration,
info1->kernel_thread ? "[" : "",
@@ -1135,16 +1255,64 @@
}
proc_info_free(proc_ev->event_data.exit.process_pid);
break;
+ case PROC_EVENT_UID:
+ proc_stats_account(proc_ev->event_data.exec.process_pid, STAT_UID);
+ info1 = proc_info_update(proc_ev->event_data.exec.process_pid);
+ if (!(opt_flags & OPT_QUIET) && (opt_flags & OPT_EV_UID)) {
+ row_increment();
+ pid = proc_ev->event_data.exec.process_pid;
+ if (proc_ev->what == PROC_EVENT_UID) {
+ printf("%s uid %*d %s%6s %8s %s%s%s\n",
+ when,
+ pid_size, pid,
+ extra_info(pid),
+ get_username(proc_ev->event_data.id.e.euid),
+ "",
+ info1->kernel_thread ? "[" : "",
+ info1->cmdline,
+ info1->kernel_thread ? "]" : "");
+ } else {
+ printf("%s gid %*d %6s %s%8s %s%s%s\n",
+ when,
+ pid_size, pid,
+ extra_info(pid),
+ get_username(proc_ev->event_data.id.e.euid),
+ "",
+ info1->kernel_thread ? "[" : "",
+ info1->cmdline,
+ info1->kernel_thread ? "]" : "");
+ }
+ }
+ break;
+ case PROC_EVENT_SID:
+ proc_stats_account(proc_ev->event_data.exec.process_pid, STAT_SID);
+ info1 = proc_info_update(proc_ev->event_data.exec.process_pid);
+ if (!(opt_flags & OPT_QUIET) && (opt_flags & OPT_EV_UID)) {
+ row_increment();
+ pid = proc_ev->event_data.exec.process_pid;
+ printf("%s sid %*d %s%6d %8s %s%s%s\n",
+ when,
+ pid_size, pid,
+ extra_info(pid),
+ proc_ev->event_data.sid.process_pid,
+ "",
+ info1->kernel_thread ? "[" : "",
+ info1->cmdline,
+ info1->kernel_thread ? "]" : "");
+ }
+ break;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0)
case PROC_EVENT_COREDUMP:
proc_stats_account(proc_ev->event_data.coredump.process_pid, STAT_CORE);
if (!(opt_flags & OPT_QUIET) && (opt_flags & OPT_EV_CORE)) {
- info1 = proc_info_get(proc_ev->event_data.coredump.process_pid);
+ pid = proc_ev->event_data.coredump.process_pid;
+ info1 = proc_info_get(pid);
row_increment();
- printf("%s core %*d %8s %s%s%s\n",
+ printf("%s core %*d %s %8s %s%s%s\n",
when,
- pid_size, proc_ev->event_data.exit.process_pid,
+ pid_size, pid,
+ extra_info(pid),
"",
info1->kernel_thread ? "[" : "",
info1->cmdline,
@@ -1152,19 +1320,47 @@
}
break;
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0)
+ case PROC_EVENT_PTRACE:
+ proc_stats_account(proc_ev->event_data.comm.process_pid, STAT_PTRC);
+ if (!(opt_flags & OPT_QUIET) && (opt_flags & OPT_EV_PTRC)) {
+ const bool attach = (proc_ev->event_data.ptrace.tracer_pid != 0);
+
+#if 0
+ pid = attach ? proc_ev->event_data.ptrace.tracer_pid :
+ proc_ev->event_data.ptrace.process_pid;
+#else
+ pid = proc_ev->event_data.ptrace.process_pid;
+#endif
+ info1 = proc_info_get(pid);
+ row_increment();
+ printf("%s ptrce %*d %s%6s %8s %s%s%s\n",
+ when,
+ pid_size, pid,
+ extra_info(pid),
+ attach ? "attach" : "detach",
+ "",
+ info1->kernel_thread ? "[" : "",
+ attach ? info1->cmdline : "",
+ info1->kernel_thread ? "]" : "");
+ }
+ break;
+#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0)
case PROC_EVENT_COMM:
proc_stats_account(proc_ev->event_data.comm.process_pid, STAT_COMM);
if (!(opt_flags & OPT_QUIET) && (opt_flags & OPT_EV_COMM)) {
- info1 = proc_info_get(proc_ev->event_data.comm.process_pid);
- comm = proc_comm(proc_ev->event_data.comm.process_pid);
- if (comm == NULL)
+ pid = proc_ev->event_data.comm.process_pid;
+ info1 = proc_info_get(pid);
+ comm = proc_comm(pid);
+ if (!comm)
break;
row_increment();
- printf("%s comm %*d %8s %s%s%s -> %s\n",
+ printf("%s comm %*d %s %8s %s%s%s -> %s\n",
when,
- pid_size, proc_ev->event_data.exit.process_pid,
+ pid_size, pid,
+ extra_info(pid),
"",
info1->kernel_thread ? "[" : "",
info1->cmdline,
@@ -1190,14 +1386,15 @@
{
printf("%s, version %s\n\n", APP_NAME, VERSION);
printf("usage: %s [-d|-D|-e|-h|-l|-s|-S|-q]\n", argv[0]);
- printf("-d\tstrip off directory path from process name.\n");
- printf("-D\tspecify run duration in seconds.\n");
- printf("-e\tselect which events to monitor.\n");
- printf("-h\tshow this help.\n");
- printf("-l\tforce stdout line buffering.\n");
- printf("-s\tshow short process name.\n");
- printf("-S\tshow event statistics at end of the run.\n");
- printf("-q\trun quietly and enable -S option.\n");
+ printf("-d\tstrip off directory path from process name.\n"
+ "-D\tspecify run duration in seconds.\n"
+ "-e\tselect which events to monitor.\n"
+ "-h\tshow this help.\n"
+ "-l\tforce stdout line buffering.\n"
+ "-r\trun with real time FIFO scheduler.\n"
+ "-s\tshow short process name.\n"
+ "-S\tshow event statistics at end of the run.\n"
+ "-q\trun quietly and enable -S option.\n");
}
/*
@@ -1219,7 +1416,10 @@
}
}
if (!found) {
- fprintf(stderr, "Unknown event '%s'.\n", token);
+ fprintf(stderr, "Unknown event '%s'. Allowed events:", token);
+ for (i = 0; ev_map[i].event; i++)
+ printf(" %s", ev_map[i].event);
+ printf("\n");
return -1;
}
}
@@ -1233,7 +1433,7 @@
struct sigaction new_action;
for (;;) {
- int c = getopt(argc, argv, "dD:e:hlsSq");
+ const int c = getopt(argc, argv, "dD:e:hlrsSqx");
if (c == -1)
break;
switch (c) {
@@ -1254,6 +1454,9 @@
case 'h':
show_help(argv);
exit(EXIT_SUCCESS);
+ case 'r':
+ opt_flags |= OPT_REALTIME;
+ break;
case 's':
opt_flags &= ~OPT_CMD_LONG;
opt_flags |= OPT_CMD_SHORT;
@@ -1270,6 +1473,9 @@
exit(EXIT_FAILURE);
}
break;
+ case 'x':
+ opt_flags |= OPT_EXTRA;
+ break;
default:
show_help(argv);
exit(EXIT_FAILURE);
@@ -1277,14 +1483,14 @@
}
if ((opt_flags & OPT_EV_MASK) == 0)
- opt_flags |= (OPT_EV_FORK | OPT_EV_EXEC | OPT_EV_EXIT | OPT_EV_CLNE);
+ opt_flags |= (OPT_EV_FORK | OPT_EV_EXEC | OPT_EV_EXIT | OPT_EV_CLNE | OPT_EV_PTRC);
if (geteuid() != 0) {
fprintf(stderr, "Need to run with root access.\n");
goto abort_sock;
}
- memset(&new_action, 0, sizeof(new_action));
+ (void)memset(&new_action, 0, sizeof(new_action));
for (i = 0; signals[i] != -1; i++) {
new_action.sa_handler = handle_sig;
sigemptyset(&new_action.sa_mask);
@@ -1304,6 +1510,27 @@
goto abort_sock;
}
+ if (opt_flags & OPT_REALTIME) {
+ struct sched_param param;
+ int max_prio;
+ const int policy = SCHED_FIFO;
+
+ max_prio = sched_get_priority_max(policy);
+ if (max_prio < 0) {
+ fprintf(stderr, "sched_get_priority_max failed: errno=%d (%s)\n",
+ errno, strerror(errno));
+ goto abort_sock;
+ }
+
+ (void)memset(¶m, 0, sizeof(param));
+ param.sched_priority = max_prio;
+ if (sched_setscheduler(getpid(), policy, ¶m) < 0) {
+ fprintf(stderr, "sched_setscheduler failed: errno=%d (%s)\n",
+ errno, strerror(errno));
+ goto abort_sock;
+ }
+ }
+
sock = netlink_connect();
if (sock == -EPROTONOSUPPORT) {
fprintf(stderr, "Cannot show process activity with this kernel, netlink required.\n");