|
2 | 2 | #include "common/processing.h" |
3 | 3 | #include "common/io/io.h" |
4 | 4 | #include "common/time.h" |
| 5 | +#include "util/stringUtils.h" |
5 | 6 |
|
6 | 7 | #include <stdlib.h> |
7 | 8 | #include <unistd.h> |
|
11 | 12 | #include <errno.h> |
12 | 13 | #include <sys/wait.h> |
13 | 14 |
|
| 15 | +#if defined(__FreeBSD__) || defined(__APPLE__) |
| 16 | + #include <sys/types.h> |
| 17 | + #include <sys/user.h> |
| 18 | + #include <sys/sysctl.h> |
| 19 | +#endif |
| 20 | + |
14 | 21 | enum { FF_PIPE_BUFSIZ = 8192 }; |
15 | 22 |
|
16 | 23 | static inline int ffPipe2(int *fds, int flags) |
@@ -101,3 +108,192 @@ const char* ffProcessAppendOutput(FFstrbuf* buffer, char* const argv[], bool use |
101 | 108 |
|
102 | 109 | return "read(childPipeFd, str, FF_PIPE_BUFSIZ) failed"; |
103 | 110 | } |
| 111 | + |
| 112 | +void ffProcessGetInfoLinux(pid_t pid, FFstrbuf* processName, FFstrbuf* exe, const char** exeName, FFstrbuf* exePath) |
| 113 | +{ |
| 114 | + assert(processName->length > 0); |
| 115 | + ffStrbufClear(exe); |
| 116 | + |
| 117 | + #ifdef __linux__ |
| 118 | + |
| 119 | + char filePath[64]; |
| 120 | + snprintf(filePath, sizeof(filePath), "/proc/%d/cmdline", (int)pid); |
| 121 | + |
| 122 | + if(ffAppendFileBuffer(filePath, exe)) |
| 123 | + { |
| 124 | + ffStrbufTrimRightSpace(exe); |
| 125 | + ffStrbufRecalculateLength(exe); //Trim the arguments |
| 126 | + ffStrbufTrimLeft(exe, '-'); //Login shells start with a dash |
| 127 | + } |
| 128 | + |
| 129 | + snprintf(filePath, sizeof(filePath), "/proc/%d/exe", (int)pid); |
| 130 | + ffStrbufEnsureFixedLengthFree(exePath, PATH_MAX); |
| 131 | + ssize_t length = readlink(filePath, exePath->chars, exePath->allocated - 1); |
| 132 | + if (length > 0) // doesn't contain trailing NUL |
| 133 | + { |
| 134 | + exePath->chars[length] = '\0'; |
| 135 | + exePath->length = (uint32_t) length; |
| 136 | + } |
| 137 | + |
| 138 | + #elif defined(__APPLE__) |
| 139 | + |
| 140 | + size_t len = 0; |
| 141 | + int mibs[] = { CTL_KERN, KERN_PROCARGS2, pid }; |
| 142 | + if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), NULL, &len, NULL, 0) == 0) |
| 143 | + { |
| 144 | + #ifndef MAC_OS_X_VERSION_10_15 |
| 145 | + //don't know why if don't let len longer, proArgs2 and len will change during the following sysctl() in old MacOS version. |
| 146 | + len++; |
| 147 | + #endif |
| 148 | + FF_AUTO_FREE char* const procArgs2 = malloc(len); |
| 149 | + if (sysctl(mibs, sizeof(mibs) / sizeof(*mibs), procArgs2, &len, NULL, 0) == 0) |
| 150 | + { |
| 151 | + // https://gist.github.com/nonowarn/770696#file-getargv-c-L46 |
| 152 | + uint32_t argc = *(uint32_t*) procArgs2; |
| 153 | + const char* realExePath = procArgs2 + sizeof(argc); |
| 154 | + |
| 155 | + const char* arg0 = memchr(realExePath, '\0', len - (size_t) (realExePath - procArgs2)); |
| 156 | + ffStrbufSetNS(exePath, (uint32_t) (arg0 - realExePath), realExePath); |
| 157 | + |
| 158 | + do arg0++; while (*arg0 == '\0'); |
| 159 | + assert(arg0 < procArgs2 + len); |
| 160 | + if (*arg0 == '-') arg0++; // Login shells |
| 161 | + |
| 162 | + ffStrbufSetS(exe, arg0); |
| 163 | + } |
| 164 | + } |
| 165 | + |
| 166 | + #elif defined(__FreeBSD__) |
| 167 | + |
| 168 | + size_t size = ARG_MAX; |
| 169 | + FF_AUTO_FREE char* args = malloc(size); |
| 170 | + |
| 171 | + static_assert(ARG_MAX > PATH_MAX, ""); |
| 172 | + |
| 173 | + if(sysctl( |
| 174 | + (int[]){CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, pid}, 4, |
| 175 | + args, &size, |
| 176 | + NULL, 0 |
| 177 | + ) == 0) |
| 178 | + ffStrbufSetNS(exePath, (uint32_t) (size - 1), args); |
| 179 | + |
| 180 | + size = ARG_MAX; |
| 181 | + if(sysctl( |
| 182 | + (int[]){CTL_KERN, KERN_PROC, KERN_PROC_ARGS, pid}, 4, |
| 183 | + args, &size, |
| 184 | + NULL, 0 |
| 185 | + ) == 0) |
| 186 | + { |
| 187 | + char* arg0 = args; |
| 188 | + size_t arg0Len = strlen(args); |
| 189 | + if (size > arg0Len + 1) |
| 190 | + { |
| 191 | + char* p = (char*) memrchr(args, '/', arg0Len); |
| 192 | + if (p) |
| 193 | + { |
| 194 | + p++; |
| 195 | + if (ffStrStartsWith(p, "python")) // /usr/local/bin/python3.9 /home/carter/.local/bin/xonsh |
| 196 | + { |
| 197 | + arg0 += arg0Len + 1; |
| 198 | + } |
| 199 | + } |
| 200 | + } |
| 201 | + if (arg0[0] == '-') arg0++; |
| 202 | + ffStrbufSetS(exe, arg0); |
| 203 | + } |
| 204 | + |
| 205 | + #endif |
| 206 | + |
| 207 | + if(exe->length == 0) |
| 208 | + ffStrbufSet(exe, processName); |
| 209 | + |
| 210 | + assert(exe->length > 0); |
| 211 | + uint32_t lastSlashIndex = ffStrbufLastIndexC(exe, '/'); |
| 212 | + if(lastSlashIndex < exe->length) |
| 213 | + *exeName = exe->chars + lastSlashIndex + 1; |
| 214 | +} |
| 215 | + |
| 216 | +const char* ffProcessGetBasicInfoLinux(pid_t pid, char* name, pid_t* ppid, int32_t* tty) |
| 217 | +{ |
| 218 | + if (pid <= 0) |
| 219 | + return "Invalid pid"; |
| 220 | + |
| 221 | + #ifdef __linux__ |
| 222 | + |
| 223 | + char statFilePath[64]; |
| 224 | + snprintf(statFilePath, sizeof(statFilePath), "/proc/%d/stat", (int)pid); |
| 225 | + char buf[PROC_FILE_BUFFSIZ]; |
| 226 | + ssize_t nRead = ffReadFileData(statFilePath, sizeof(buf) - 1, buf); |
| 227 | + if(nRead < 0) |
| 228 | + return "ffReadFileData(statFilePath, sizeof(buf)-1, buf) failed"; |
| 229 | + buf[nRead] = '\0'; |
| 230 | + |
| 231 | + *ppid = 0; |
| 232 | + static_assert(sizeof(*ppid) == sizeof(int), ""); |
| 233 | + |
| 234 | + int tty_; |
| 235 | + if( |
| 236 | + sscanf(buf, "%*s (%255[^)]) %*c %d %*d %*d %d", name, ppid, &tty_) < 2 || //stat (comm) state ppid pgrp session tty |
| 237 | + !ffStrSet(name) || |
| 238 | + *ppid == 0 |
| 239 | + ) |
| 240 | + return "sscanf(stat) failed"; |
| 241 | + |
| 242 | + if (tty) |
| 243 | + *tty = tty_ & 0xFF; |
| 244 | + |
| 245 | + #elif defined(__APPLE__) |
| 246 | + |
| 247 | + struct kinfo_proc proc; |
| 248 | + size_t size = sizeof(proc); |
| 249 | + if(sysctl( |
| 250 | + (int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4, |
| 251 | + &proc, &size, |
| 252 | + NULL, 0 |
| 253 | + )) |
| 254 | + return "sysctl(KERN_PROC_PID) failed"; |
| 255 | + |
| 256 | + *ppid = (pid_t)proc.kp_eproc.e_ppid; |
| 257 | + strcpy(name, proc.kp_proc.p_comm); //trancated to 16 chars |
| 258 | + if (tty) |
| 259 | + { |
| 260 | + *tty = ((proc.kp_eproc.e_tdev >> 24) & 0xFF) == 0x10 |
| 261 | + ? proc.kp_eproc.e_tdev & 0xFFFFFF |
| 262 | + : -1; |
| 263 | + } |
| 264 | + |
| 265 | + #elif defined(__FreeBSD__) |
| 266 | + |
| 267 | + struct kinfo_proc proc; |
| 268 | + size_t size = sizeof(proc); |
| 269 | + if(sysctl( |
| 270 | + (int[]){CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}, 4, |
| 271 | + &proc, &size, |
| 272 | + NULL, 0 |
| 273 | + )) |
| 274 | + return "sysctl(KERN_PROC_PID) failed"; |
| 275 | + |
| 276 | + *ppid = (pid_t)proc.ki_ppid; |
| 277 | + strcpy(name, proc.ki_comm); |
| 278 | + if (tty) |
| 279 | + { |
| 280 | + if (proc.ki_tdev != NODEV && proc.ki_flag & P_CONTROLT) |
| 281 | + { |
| 282 | + const char* ttyName = devname(proc.ki_tdev, S_IFCHR); |
| 283 | + if (ffStrStartsWith(ttyName, "pts/")) |
| 284 | + *tty = (int32_t) strtol(ttyName + strlen("pts/"), NULL, 10); |
| 285 | + else |
| 286 | + *tty = -1; |
| 287 | + } |
| 288 | + else |
| 289 | + *tty = -1; |
| 290 | + } |
| 291 | + |
| 292 | + #else |
| 293 | + |
| 294 | + return "Unsupported platform"; |
| 295 | + |
| 296 | + #endif |
| 297 | + |
| 298 | + return NULL; |
| 299 | +} |
0 commit comments