1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2010 Konstantin Belousov 5 * Copyright (c) 2015 Allan Jude <allanjude@freebsd.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/sysctl.h> 35 #include <sys/user.h> 36 37 #include <ctype.h> 38 #include <err.h> 39 #include <errno.h> 40 #include <signal.h> 41 #include <stdbool.h> 42 #include <stdint.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <libprocstat.h> 47 48 #include "procstat.h" 49 50 static void 51 procstat_print_signame(int sig) 52 { 53 char name[12]; 54 int i; 55 56 if ((procstat_opts & PS_OPT_SIGNUM) == 0 && sig < sys_nsig) { 57 strlcpy(name, sys_signame[sig], sizeof(name)); 58 for (i = 0; name[i] != 0; i++) 59 name[i] = toupper(name[i]); 60 xo_emit("{d:signal/%-7s/%s} ", name); 61 xo_open_container(name); 62 } else { 63 xo_emit("{d:signal/%-7d/%d} ", sig); 64 snprintf(name, 12, "%d", sig); 65 xo_open_container(name); 66 } 67 } 68 69 static void 70 procstat_close_signame(int sig) 71 { 72 char name[12]; 73 int i; 74 75 if ((procstat_opts & PS_OPT_SIGNUM) == 0 && sig < sys_nsig) { 76 strlcpy(name, sys_signame[sig], sizeof(name)); 77 for (i = 0; name[i] != 0; i++) 78 name[i] = toupper(name[i]); 79 xo_close_container(name); 80 } else { 81 snprintf(name, 12, "%d", sig); 82 xo_close_container(name); 83 } 84 } 85 86 static void 87 procstat_print_sig(const sigset_t *set, int sig, char flag) 88 { 89 xo_emit("{d:sigmember/%c}", sigismember(set, sig) ? flag : '-'); 90 switch (flag) { 91 case 'B': 92 xo_emit("{en:mask/%s}", sigismember(set, sig) ? 93 "true" : "false"); 94 break; 95 case 'C': 96 xo_emit("{en:catch/%s}", sigismember(set, sig) ? 97 "true" : "false"); 98 break; 99 case 'P': 100 xo_emit("{en:list/%s}", sigismember(set, sig) ? 101 "true" : "false"); 102 break; 103 case 'I': 104 xo_emit("{en:ignore/%s}", sigismember(set, sig) ? 105 "true" : "false"); 106 break; 107 default: 108 xo_emit("{en:unknown/%s}", sigismember(set, sig) ? 109 "true" : "false"); 110 break; 111 } 112 } 113 114 void 115 procstat_sigs(struct procstat *prstat __unused, struct kinfo_proc *kipp) 116 { 117 int j; 118 119 if ((procstat_opts & PS_OPT_NOHEADER) == 0) 120 xo_emit("{T:/%5s %-16s %-7s %4s}\n", "PID", "COMM", "SIG", 121 "FLAGS"); 122 123 xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid); 124 xo_emit("{e:command/%-16s/%s}", kipp->ki_comm); 125 xo_open_container("signals"); 126 for (j = 1; j <= _SIG_MAXSIG; j++) { 127 xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); 128 xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); 129 procstat_print_signame(j); 130 xo_emit(" "); 131 procstat_print_sig(&kipp->ki_siglist, j, 'P'); 132 procstat_print_sig(&kipp->ki_sigignore, j, 'I'); 133 procstat_print_sig(&kipp->ki_sigcatch, j, 'C'); 134 procstat_close_signame(j); 135 xo_emit("\n"); 136 } 137 xo_close_container("signals"); 138 } 139 140 void 141 procstat_threads_sigs(struct procstat *procstat, struct kinfo_proc *kipp) 142 { 143 struct kinfo_proc *kip; 144 int j; 145 unsigned int count, i; 146 char *threadid; 147 148 if ((procstat_opts & PS_OPT_NOHEADER) == 0) 149 xo_emit("{T:/%5s %6s %-16s %-7s %4s}\n", "PID", "TID", "COMM", 150 "SIG", "FLAGS"); 151 152 kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, 153 kipp->ki_pid, &count); 154 if (kip == NULL) 155 return; 156 xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid); 157 xo_emit("{e:command/%-16s/%s}", kipp->ki_comm); 158 xo_open_container("threads"); 159 kinfo_proc_sort(kip, count); 160 for (i = 0; i < count; i++) { 161 kipp = &kip[i]; 162 asprintf(&threadid, "%d", kipp->ki_tid); 163 if (threadid == NULL) 164 xo_errc(1, ENOMEM, "Failed to allocate memory in " 165 "procstat_threads_sigs()"); 166 xo_open_container(threadid); 167 xo_emit("{e:thread_id/%6d/%d}", kipp->ki_tid); 168 xo_open_container("signals"); 169 170 for (j = 1; j <= _SIG_MAXSIG; j++) { 171 xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); 172 xo_emit("{d:thread_id/%6d/%d} ", kipp->ki_tid); 173 xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); 174 procstat_print_signame(j); 175 xo_emit(" "); 176 procstat_print_sig(&kipp->ki_siglist, j, 'P'); 177 procstat_print_sig(&kipp->ki_sigmask, j, 'B'); 178 procstat_close_signame(j); 179 xo_emit("\n"); 180 } 181 xo_close_container("signals"); 182 xo_close_container(threadid); 183 free(threadid); 184 } 185 xo_close_container("threads"); 186 procstat_freeprocs(procstat, kip); 187 } 188 189 void 190 procstat_sigfastblock(struct procstat *procstat, struct kinfo_proc *kipp) 191 { 192 struct kinfo_proc *kip; 193 char *threadid; 194 uintptr_t sigfastblk_addr; 195 int error, name[4]; 196 unsigned int count, i; 197 size_t len; 198 bool has_sigfastblk_addr; 199 200 if ((procstat_opts & PS_OPT_NOHEADER) == 0) 201 xo_emit("{T:/%5s %6s %-16s %-16s}\n", "PID", "TID", 202 "COMM", "SIGFBLK"); 203 204 kip = procstat_getprocs(procstat, KERN_PROC_PID | KERN_PROC_INC_THREAD, 205 kipp->ki_pid, &count); 206 if (kip == NULL) 207 return; 208 xo_emit("{ek:process_id/%5d/%d}", kipp->ki_pid); 209 xo_emit("{e:command/%-16s/%s}", kipp->ki_comm); 210 xo_open_container("threads"); 211 kinfo_proc_sort(kip, count); 212 for (i = 0; i < count; i++) { 213 kipp = &kip[i]; 214 len = sizeof(sigfastblk_addr); 215 name[0] = CTL_KERN; 216 name[1] = KERN_PROC; 217 name[2] = KERN_PROC_SIGFASTBLK; 218 name[3] = kipp->ki_tid; 219 error = sysctl(name, 4, &sigfastblk_addr, &len, NULL, 0); 220 if (error < 0) { 221 if (errno != ESRCH && errno != ENOTTY) { 222 warn("sysctl: kern.proc.fastsigblk: %d", 223 kipp->ki_tid); 224 } 225 has_sigfastblk_addr = false; 226 } else 227 has_sigfastblk_addr = true; 228 229 asprintf(&threadid, "%d", kipp->ki_tid); 230 if (threadid == NULL) 231 xo_errc(1, ENOMEM, "Failed to allocate memory in " 232 "procstat_sigfastblock()"); 233 xo_open_container(threadid); 234 xo_emit("{dk:process_id/%5d/%d} ", kipp->ki_pid); 235 xo_emit("{d:thread_id/%6d/%d} ", kipp->ki_tid); 236 xo_emit("{d:command/%-16s/%s} ", kipp->ki_comm); 237 xo_emit("{e:sigfastblock/%#-16jx/%#jx}", has_sigfastblk_addr ? 238 (uintmax_t)sigfastblk_addr : (uintmax_t)-1); 239 xo_emit("{d:sigfastblock/%#-16jx/%#jx}", has_sigfastblk_addr ? 240 (uintmax_t)sigfastblk_addr : (uintmax_t)-1); 241 xo_emit("\n"); 242 xo_close_container(threadid); 243 free(threadid); 244 } 245 xo_close_container("threads"); 246 procstat_freeprocs(procstat, kip); 247 } 248