@@ -372,6 +372,8 @@ const char *str_map_lookup_u8(const struct str_num_map *map, uint8_t val);
unsigned int get_str_char_count(const char *str, int match);
int str_split_by_char(char *str, char **before, char **after, int match);
+int escape_str (char *dst, const char *src, int bufsize);
+
#define INDENT_STR_MAXLEN 32
struct indent_mem {
@@ -5,7 +5,7 @@ CFLAGS += -fPIC
UTILOBJ = utils.o utils_math.o rt_names.o ll_map.o ll_types.o ll_proto.o ll_addr.o \
inet_proto.o namespace.o json_writer.o json_print.o json_print_math.o \
- names.o color.o bpf_legacy.o bpf_glue.o exec.o fs.o cg_map.o ppp_proto.o
+ names.o color.o bpf_legacy.o bpf_glue.o exec.o fs.o cg_map.o ppp_proto.o escape.o
ifeq ($(HAVE_ELF),y)
ifeq ($(HAVE_LIBBPF),y)
new file mode 100644
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Escape character print handling derived from procps
+ * Copyright 1998-2002 by Albert Cahalan
+ * Copyright 2020-2022 Jim Warner <james.warner@comcast.net>
+ *
+ */
+
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <langinfo.h>
+
+#include "utils.h"
+
+static const char UTF_tab[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0x00 - 0x0F
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0x10 - 0x1F
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0x20 - 0x2F
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0x30 - 0x3F
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0x40 - 0x4F
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0x50 - 0x5F
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0x60 - 0x6F
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 - 0x7F
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, // 0x80 - 0x8F
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, // 0x90 - 0x9F
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, // 0xA0 - 0xAF
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, // 0xB0 - 0xBF
+ -1, -1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, // 0xC0 - 0xCF
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, // 0xD0 - 0xDF
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, // 0xE0 - 0xEF
+ 4, 4, 4, 4, 4, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, // 0xF0 - 0xFF
+};
+
+static const unsigned char ESC_tab[] = {
+ "@..............................." // 0x00 - 0x1F
+ "||||||||||||||||||||||||||||||||" // 0x20 - 0x3F
+ "||||||||||||||||||||||||||||||||" // 0x40 - 0x5f
+ "|||||||||||||||||||||||||||||||." // 0x60 - 0x7F
+ "????????????????????????????????" // 0x80 - 0x9F
+ "????????????????????????????????" // 0xA0 - 0xBF
+ "????????????????????????????????" // 0xC0 - 0xDF
+ "????????????????????????????????" // 0xE0 - 0xFF
+};
+
+static void esc_all(unsigned char *str)
+{
+ // if bad locale/corrupt str, replace non-printing stuff
+ while (*str) {
+ unsigned char c = ESC_tab[*str];
+
+ if (c != '|')
+ *str = c;
+ ++str;
+ }
+}
+
+static void esc_ctl(unsigned char *str, int len)
+{
+ int i;
+
+ for (i = 0; i < len;) {
+ // even with a proper locale, strings might be corrupt
+ int n = UTF_tab[*str];
+
+ if (n < 0 || i + n > len) {
+ esc_all(str);
+ return;
+ }
+ // and eliminate those non-printing control characters
+ if (*str < 0x20 || *str == 0x7f)
+ *str = '?';
+ str += n;
+ i += n;
+ }
+}
+
+int escape_str(char *dst, const char *src, int bufsize)
+{
+ static int utf_sw;
+
+ if (utf_sw == 0) {
+ char *enc = nl_langinfo(CODESET);
+
+ utf_sw = enc && strcasecmp(enc, "UTF-8") == 0 ? 1 : -1;
+ }
+
+ int n = strlcpy(dst, src, bufsize);
+
+ if (utf_sw < 0)
+ esc_all((unsigned char *)dst);
+ else
+ esc_ctl((unsigned char *)dst, n);
+ return n;
+}
@@ -550,8 +550,7 @@ static void user_ent_add(unsigned int ino, char *task,
static void user_ent_hash_build_task(char *path, int pid, int tid)
{
const char *no_ctx = "unavailable";
- char task[16] = {'\0', };
- char stat[MAX_PATH_LEN];
+ char task[20] = { };
int pos_id, pos_fd;
char *task_context;
struct dirent *d;
@@ -599,6 +598,8 @@ static void user_ent_hash_build_task(char *path, int pid, int tid)
sock_context = strdup(no_ctx);
if (task[0] == '\0') {
+ char stat[MAX_PATH_LEN];
+ char name[16];
FILE *fp;
strlcpy(stat, path, pos_id + 1);
@@ -606,9 +607,8 @@ static void user_ent_hash_build_task(char *path, int pid, int tid)
fp = fopen(stat, "r");
if (fp) {
- if (fscanf(fp, "%*d (%[^)])", task) < 1) {
- ; /* ignore */
- }
+ if (fscanf(fp, "%*d (%[^)])", name) == 1)
+ escape_str(task, name, sizeof(task));
fclose(fp);
}
}
Since the process name is under user control with prctl(PR_SET_NAME) it may contain escape characters to try and mess with screen output. Reuse the existing string logic from procps (used by ps command). Reported-by: Josiah Stearns <B00TK1D@proton.me> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> --- include/utils.h | 2 + lib/Makefile | 2 +- lib/escape.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++ misc/ss.c | 10 ++--- 4 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 lib/escape.c