summaryrefslogtreecommitdiffstats
path: root/src/ps/signames.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ps/signames.c')
-rw-r--r--src/ps/signames.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/ps/signames.c b/src/ps/signames.c
new file mode 100644
index 0000000..129a4c2
--- /dev/null
+++ b/src/ps/signames.c
@@ -0,0 +1,170 @@
+/*
+ * signames.c - ps signal names
+ *
+ * Copyright © 2023 Craig Small <csmall@dropbear.xyz>
+ * Copyright © 2020 Luis Chamberlain <mcgrof@kernel.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <inttypes.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+
+#include "common.h"
+#include "signals.h"
+
+/* For libraries like musl */
+#ifndef __SIGRTMIN
+#define __SIGRTMIN SIGRTMIN
+#endif
+#ifndef __SIGRTMAX
+#define __SIGRTMAX SIGRTMAX
+#endif
+
+/*
+ * The actual list of unsupported signals varies by operating system. This
+ * program is Linux specific as it processes /proc/ for signal information and
+ * there is no generic way to extract each process signal information for each
+ * OS. This program also relies on Linux glibc defines to figure out which
+ * signals are reserved for use by libc and then which ones are real time
+ * specific.
+ */
+
+/*
+ * As per glibc:
+ *
+ * A system that defines real time signals overrides __SIGRTMAX to be something
+ * other than __SIGRTMIN. This also means we can count on __SIGRTMIN being the
+ * first real time signal, meaning what Linux programs it for your architecture
+ * in the kernel. SIGRTMIN then will be the application specific first real
+ * time signal, that is, on top of libc. The values in between
+ *
+ * __SIGRTMIN .. SIGRTMIN
+ *
+ * are used by * libc, typically for helping threading implementation.
+ */
+static const char *sigstat_strsignal_abbrev(int sig, char *abbrev, size_t len)
+{
+ memset(abbrev, '\0', len);
+
+ if (sig == 0 || sig >= NSIG) {
+ snprintf(abbrev, len, "BOGUS_%02d", sig - _NSIG);
+ return abbrev;
+ }
+
+ /*
+ * The standard lower signals we can count on this being the kernel
+ * specific SIGRTMIN.
+ */
+ if (sig < __SIGRTMIN) {
+ const char *signame = NULL;
+#ifdef HAVE_SIGABBREV_NP
+ signame = sigabbrev_np(sig);
+#else
+ signame = signal_number_to_name(sig);
+#endif /* HAVE_SIGABBREV_NP */
+ if (signame != NULL && signame[0] != '\0') {
+ strncpy(abbrev, signame, len);
+ return abbrev;
+ }
+ }
+
+ /* This means your system should *not* have realtime signals */
+ if (__SIGRTMAX == __SIGRTMIN) {
+ snprintf(abbrev, len, "INVALID_%02d", sig);
+ return abbrev;
+ }
+
+ /*
+ * If we're dealing with a libc real time signal start counting
+ * after libc's version of SIGRTMIN
+ */
+ if (sig >= SIGRTMIN) {
+ if (sig == SIGRTMIN)
+ snprintf(abbrev, len, "RTMIN");
+ else if (sig == SIGRTMAX)
+ snprintf(abbrev, len, "RTMAX");
+ else
+ snprintf(abbrev, len, "RTMIN+%02d", sig - SIGRTMIN);
+ } else
+ snprintf(abbrev, len, "LIBC+%02d", sig - __SIGRTMIN);
+
+ return abbrev;
+}
+
+/*
+ * For instance SIGTERM is 15, but its actual mask value is
+ * 1 << (15-1) = 0x4000
+ */
+static uint64_t mask_sig_val_num(int signum)
+{
+ return ((uint64_t) 1 << (signum -1));
+}
+
+int print_signame(char *restrict const outbuf, const char *restrict const sig, const size_t len_in)
+{
+ unsigned int i;
+ char abbrev[PATH_MAX];
+ unsigned int n = 0;
+ char *c = outbuf;
+ size_t len = len_in;
+ uint64_t mask, mask_in;
+ uint64_t test_val = 0;
+
+ if (1 != sscanf(sig, "%" PRIu64, &mask_in))
+ return 0;
+ mask = mask_in;
+
+ for (i=1; i < NSIG; i++) {
+ test_val = mask_sig_val_num(i);
+ if (test_val & mask) {
+ n = strlen(sigstat_strsignal_abbrev(i, abbrev, PATH_MAX));
+ if (n+1 >= len) { // +1 for the '+'
+ strcpy(c, "+");
+ len -= 1;
+ c += 1;
+ break;
+ } else {
+ n = snprintf(c, len, (c==outbuf)?"%s":",%s",
+ sigstat_strsignal_abbrev(i, abbrev,
+ PATH_MAX));
+ len -= n;
+ c+=n;
+ }
+ }
+ }
+ if (c == outbuf) {
+ n = snprintf(c, len, "%c", '-');
+ len -= n;
+ c += n;
+ }
+ return (int) (c-outbuf);
+}