Hello community, here is the log from the commit of package forkstat for openSUSE:Factory checked in at 2019-12-17 16:54:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/forkstat (Old) and /work/SRC/openSUSE:Factory/.forkstat.new.4691 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "forkstat" Tue Dec 17 16:54:52 2019 rev:12 rq:757555 version:0.02.12 Changes: -------- --- /work/SRC/openSUSE:Factory/forkstat/forkstat.changes 2019-09-05 12:45:10.911448908 +0200 +++ /work/SRC/openSUSE:Factory/.forkstat.new.4691/forkstat.changes 2019-12-17 16:54:55.929347958 +0100 @@ -1,0 +2,8 @@ +Sun Dec 15 09:47:15 UTC 2019 - Martin Hauke <mar...@gmx.de> + +- Update to version 0.02.12 + * Remove no-op free_proc_comm call on an unknown comm field + * Return no info rather than NULL if proc_info_get returns NULL + * Re-work unknown cmdline information + +------------------------------------------------------------------- Old: ---- forkstat-0.02.11.tar.xz New: ---- forkstat-0.02.12.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ forkstat.spec ++++++ --- /var/tmp/diff_new_pack.NEr9CK/_old 2019-12-17 16:54:56.837348283 +0100 +++ /var/tmp/diff_new_pack.NEr9CK/_new 2019-12-17 16:54:56.841348285 +0100 @@ -18,7 +18,7 @@ Name: forkstat -Version: 0.02.11 +Version: 0.02.12 Release: 0 Summary: Process fork/exec/exit monitoring tool License: GPL-2.0-or-later ++++++ forkstat-0.02.11.tar.xz -> forkstat-0.02.12.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/forkstat-0.02.11/Makefile new/forkstat-0.02.12/Makefile --- old/forkstat-0.02.11/Makefile 2019-08-12 17:07:36.000000000 +0200 +++ new/forkstat-0.02.12/Makefile 2019-12-13 21:00:52.000000000 +0100 @@ -16,7 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # -VERSION=0.02.11 +VERSION=0.02.12 # # Version "Perspicacious Process Peeker" # diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/forkstat-0.02.11/forkstat.c new/forkstat-0.02.12/forkstat.c --- old/forkstat-0.02.11/forkstat.c 2019-08-12 17:07:36.000000000 +0200 +++ new/forkstat-0.02.12/forkstat.c 2019-12-13 21:00:52.000000000 +0100 @@ -188,13 +188,17 @@ static int row = 0; /* tty row number */ static long int opt_duration = -1; /* duration, < 0 means run forever */ +static char unknown[] = "<unknown>"; + +static proc_info_t *proc_info_add(const pid_t pid, const struct timeval * const tv); + /* Default void no process info struct */ static proc_info_t no_info = { .pid = NULL_PID, .uid = NULL_UID, .gid = NULL_GID, .tty = NULL_TTY, - .cmdline = "<unknown>", + .cmdline = unknown, .kernel_thread = false, .start = { 0, 0 }, .next = NULL, @@ -270,6 +274,20 @@ }; /* + * proc_comm_dup() + * duplicate a comm filed string, if it fails, return unknown + */ +static char *proc_comm_dup(const char *str) +{ + char *comm = strdup(str); + + if (!comm) + return unknown; + + return comm; +} + +/* * secs_to_str() * report seconds in different units. */ @@ -450,6 +468,59 @@ } /* + * proc_name_clean() + * clean up unwanted chars from process name + */ +static void proc_name_clean(char *buffer, const int len) +{ + char *ptr; + + /* + * Convert '\r' and '\n' into spaces + */ + for (ptr = buffer; *ptr && (ptr < buffer + len); ptr++) { + if ((*ptr == '\r') || (*ptr =='\n')) + *ptr = ' '; + } + /* + * OPT_CMD_SHORT option we discard anything after a space + */ + if (opt_flags & OPT_CMD_SHORT) { + for (ptr = buffer; *ptr && (ptr < buffer + len); ptr++) { + if (*ptr == ' ') { + *ptr = '\0'; + break; + } + } + } +} + +/* + * proc_comm() + * get process name from comm field + */ +static char *proc_comm(const pid_t pid) +{ + int fd; + ssize_t ret; + char buffer[4096]; + + (void)snprintf(buffer, sizeof(buffer), "/proc/%d/comm", pid); + if ((fd = open(buffer, O_RDONLY)) < 0) + return unknown; + if ((ret = read(fd, buffer, sizeof(buffer) - 1)) <= 0) { + (void)close(fd); + return unknown; + } + (void)close(fd); + buffer[ret - 1] = '\0'; /* remove trailing '\n' */ + proc_name_clean(buffer, ret); + + return proc_comm_dup(buffer); +} + + +/* * get_extra() * quick and dirty way to get UID and GID from a PID, * note that this does not cater of changes @@ -744,6 +815,69 @@ } /* + * proc_info_get_timeval() + * get time when process started + */ +static void proc_info_get_timeval(const pid_t pid, struct timeval * const tv) +{ + int fd; + unsigned long long starttime; + unsigned long jiffies; + char path[PATH_MAX]; + char buffer[4096]; + double uptime_secs, secs; + struct timeval now; + ssize_t n; + + (void)snprintf(path, sizeof(path), "/proc/%d/stat", pid); + + fd = open("/proc/uptime", O_RDONLY); + if (fd < 0) + return; + n = read(fd, buffer, sizeof(buffer)); + if (n <= 0) { + (void)close(fd); + return; + } + (void)close(fd); + n = sscanf(buffer, "%lg", &uptime_secs); + if (n != 1) + return; + if (uptime_secs < 0.0) + return; + + fd = open(path, O_RDONLY); + if (fd < 0) + return; + n = read(fd, buffer, sizeof(buffer)); + if (n <= 0) { + (void)close(fd); + return; + } + (void)close(fd); + n = sscanf(buffer, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u " + "%*u %*u %*u %*u %*u %*d %*d %*d %*d %llu", &starttime); + if (n != 1) + return; + + errno = 0; + jiffies = sysconf(_SC_CLK_TCK); + if (errno) + return; + secs = uptime_secs - ((double)starttime / (double)jiffies); + if (secs < 0.0) + return; + + if (gettimeofday(&now, NULL) < 0) + return; + + secs = timeval_to_double(&now) - secs; + tv->tv_sec = secs; + tv->tv_usec = (suseconds_t)secs % 1000000; +} + + +/* * proc_info_hash() * hash on PID */ @@ -752,6 +886,7 @@ return pid % MAX_PIDS; } + /* * proc_name_hash() * Hash a string, from Dan Bernstein comp.lang.c (xor version) @@ -900,55 +1035,13 @@ } /* - * proc_name_clean() - * clean up unwanted chars from process name + * free_proc_comm() + * free comm field only if it's not the static unknown string */ -static void proc_name_clean(char *buffer, const int len) +static void free_proc_comm(char *comm) { - char *ptr; - - /* - * Convert '\r' and '\n' into spaces - */ - for (ptr = buffer; *ptr && (ptr < buffer + len); ptr++) { - if ((*ptr == '\r') || (*ptr =='\n')) - *ptr = ' '; - } - /* - * OPT_CMD_SHORT option we discard anything after a space - */ - if (opt_flags & OPT_CMD_SHORT) { - for (ptr = buffer; *ptr && (ptr < buffer + len); ptr++) { - if (*ptr == ' ') { - *ptr = '\0'; - break; - } - } - } -} - -/* - * proc_comm() - * get process name from comm field - */ -static char *proc_comm(const pid_t pid) -{ - int fd; - ssize_t ret; - char buffer[4096]; - - (void)snprintf(buffer, sizeof(buffer), "/proc/%d/comm", pid); - if ((fd = open(buffer, O_RDONLY)) < 0) - return NULL; - if ((ret = read(fd, buffer, sizeof(buffer) - 1)) <= 0) { - (void)close(fd); - return NULL; - } - (void)close(fd); - buffer[ret - 1] = '\0'; /* remove trailing '\n' */ - proc_name_clean(buffer, ret); - - return strdup(buffer); + if (comm != unknown) + free(comm); } /* @@ -961,6 +1054,9 @@ ssize_t ret; char buffer[4096]; + if (pid == 0) + return proc_comm_dup("[swapper]"); + if (opt_flags & OPT_COMM) return proc_comm(pid); @@ -994,9 +1090,9 @@ proc_name_clean(buffer, ret); if (opt_flags & OPT_CMD_DIRNAME_STRIP) - return strdup(basename(buffer)); + return proc_comm_dup(basename(buffer)); - return strdup(buffer); + return proc_comm_dup(buffer); } /* @@ -1007,13 +1103,25 @@ { const size_t i = proc_info_hash(pid); proc_info_t *info = proc_info[i]; + struct timeval tv; while (info) { - if (info->pid == pid) + if (info->pid == pid) { + if (info->cmdline == unknown) + info->cmdline = proc_cmdline(pid); return info; + } info = info->next; } - return &no_info; + + /* Hrm, not already cached, so get new info */ + (void)memset(&tv, 0, sizeof(tv)); + proc_info_get_timeval(pid, &tv); + info = proc_info_add(pid, &tv); + if (!info) + info = &no_info; + + return info; } /* @@ -1030,7 +1138,7 @@ info->pid = NULL_PID; info->uid = NULL_UID; info->gid = NULL_GID; - free(info->cmdline); + free_proc_comm(info->cmdline); info->cmdline = NULL; return; } @@ -1051,7 +1159,7 @@ while (info) { proc_info_t *next = info->next; - free(info->cmdline); + free_proc_comm(info->cmdline); free(info); info = next; } @@ -1070,75 +1178,18 @@ if (info == &no_info) return &no_info; newcmd = proc_cmdline(pid); - if (!newcmd) - return &no_info; - free(info->cmdline); - info->cmdline = newcmd; - - return info; -} - -/* - * proc_info_get_timeval() - * get time when process started - */ -static void proc_info_get_timeval(const pid_t pid, struct timeval * const tv) -{ - int fd; - unsigned long long starttime; - unsigned long jiffies; - char path[PATH_MAX]; - char buffer[4096]; - double uptime_secs, secs; - struct timeval now; - ssize_t n; - - (void)snprintf(path, sizeof(path), "/proc/%d/stat", pid); - - fd = open("/proc/uptime", O_RDONLY); - if (fd < 0) - return; - n = read(fd, buffer, sizeof(buffer)); - if (n <= 0) { - (void)close(fd); - return; - } - (void)close(fd); - n = sscanf(buffer, "%lg", &uptime_secs); - if (n != 1) - return; - if (uptime_secs < 0.0) - return; - - fd = open(path, O_RDONLY); - if (fd < 0) - return; - n = read(fd, buffer, sizeof(buffer)); - if (n <= 0) { - (void)close(fd); - return; + /* + * Don't update if newcmd is unknown, at least + * we temporarily keep the parent's name or + * the processes old name + */ + if (newcmd != unknown) { + free_proc_comm(info->cmdline); + info->cmdline = newcmd; } - (void)close(fd); - n = sscanf(buffer, "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u " - "%*u %*u %*u %*u %*u %*d %*d %*d %*d %llu", &starttime); - if (n != 1) - return; - errno = 0; - jiffies = sysconf(_SC_CLK_TCK); - if (errno) - return; - secs = uptime_secs - ((double)starttime / (double)jiffies); - if (secs < 0.0) - return; - - if (gettimeofday(&now, NULL) < 0) - return; - - secs = timeval_to_double(&now) - secs; - tv->tv_sec = secs; - tv->tv_usec = (suseconds_t)secs % 1000000; + return info; } /* @@ -1152,8 +1203,6 @@ char *cmdline; cmdline = proc_cmdline(pid); - if (!cmdline) - return NULL; /* Re-use any info on the list if it's free */ info = proc_info[i]; @@ -1167,7 +1216,7 @@ info = calloc(1, sizeof(proc_info_t)); if (!info) { (void)fprintf(stderr, "Cannot allocate all proc info\n"); - free(cmdline); + free_proc_comm(cmdline); return NULL; } info->next = proc_info[i]; @@ -1631,9 +1680,7 @@ if (!(opt_flags & OPT_QUIET) && (opt_flags & OPT_EV_COMM)) { pid = proc_ev->event_data.comm.process_pid; info1 = proc_info_get(pid); - comm = proc_comm(pid); - if (!comm) - break; + comm = proc_cmdline(pid); row_increment(); (void)printf("%s comm %*d %s%s%s %8s %s%s%s -> %s\n", @@ -1647,7 +1694,7 @@ info1->cmdline, info1->kernel_thread ? "]" : "", comm); - free(comm); + free_proc_comm(comm); proc_info_update(pid); } break;