aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2024-01-24 17:06:41 -0500
committerMike Frysinger <vapier@gentoo.org>2024-01-24 17:06:41 -0500
commit1cf21243deebbfe3a5655f0ac18cd25e9ba53c48 (patch)
treedaad46aad7d8e40ffba68606db3f6e4383e7ea08
parentbuild: use standard HAVE_xxx define style (diff)
downloadpax-utils-1cf21243deebbfe3a5655f0ac18cd25e9ba53c48.tar.gz
pax-utils-1cf21243deebbfe3a5655f0ac18cd25e9ba53c48.tar.bz2
pax-utils-1cf21243deebbfe3a5655f0ac18cd25e9ba53c48.zip
pspax: rework & document get_proc_name
The current scanf format tries to use "%s.16" to limit reading to 16 bytes, but that doesn't actually work -- the maximum field width is between the "%" and the "s", so it should have been "%16s". This ends up working anyways because the %s consumes the entire string before it stops, and then scanf stops processing after it can't match ".16". If the size of the field were BUFSIZE or larger, then it'd overflow. In practice, BUFSIZ tends to be "large" (i.e. O(KiB)), and the kernel will truncate this field to 16 bytes for userspace programs. Kernel threads can have longer names, but not that big. At least, on Linux. Fix the scanf string to properly limit to 15 bytes, and change the local buffer to be exactly 16 bytes rather than the unrelated BUFSIZ (which is a stdio.h buffer size, and nothing related to kernel processes). Then add some more comments to explain what the code is actually doing, and simplify the final NUL logic to avoid redundant work. Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r--pspax.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/pspax.c b/pspax.c
index 1e3562d..97d51c6 100644
--- a/pspax.c
+++ b/pspax.c
@@ -96,7 +96,13 @@ static const char *get_proc_name_cmdline(int pfd)
static const char *get_proc_name(int pfd)
{
FILE *fp;
- static char str[BUFSIZ];
+ /*
+ * The stat file says process names are truncated to TASK_COMM_LEN (16) bytes.
+ * That includes the trailing NUL (\0) byte. This is true for userspace, but
+ * kernel processes seem to be unlimited. We don't care about those in this
+ * program though, so truncating them all the time is fine.
+ */
+ static char str[16];
if (wide_output)
return get_proc_name_cmdline(pfd);
@@ -105,18 +111,30 @@ static const char *get_proc_name(int pfd)
if (fp == NULL)
return NULL;
- if (fscanf(fp, "%*d %s.16", str) != 1) {
+ /*
+ * The format is:
+ * <pid> (<name>) ...more fields...
+ * For example:
+ * 1234 (bash) R ...
+ *
+ * Match the leading (, then read 15 bytes (since scanf writes, but doesn't count,
+ * NUL bytes, so it will write up to 16 bytes to str). Ignore the rest rather than
+ * look for closing ) since kernel processes can be longer.
+ */
+ if (fscanf(fp, "%*d (%15s", str) != 1) {
fclose(fp);
return NULL;
}
if (*str) {
- str[strlen(str) - 1] = '\0';
- str[16] = 0;
+ /* Discard trailing ) if it exists. */
+ size_t len = strlen(str);
+ if (str[len - 1] == ')')
+ str[len - 1] = '\0';
}
fclose(fp);
- return (str+1);
+ return str;
}
static int get_proc_maps(int pfd)