检索正在运行的进程的名称
首先,我知道已经有人问过类似的问题,但到目前为止提供的答案并不是很有帮助(他们都推荐以下选项之一)。
我有一个用户应用程序需要确定特定进程是否正在运行。以下是我对该进程的了解:
- 名称
- 用户 (
root
) - 它应该已经在运行,因为它是一个 LaunchDaemon,这意味着
- 它的父进程应该是
launchd
(pid 1)
我已经尝试了几种方法来获得这个,但到目前为止还没有奏效。这是我尝试过的:
运行
ps
并解析输出。这可行,但速度很慢(fork
/exec
很昂贵),我希望它尽可能快。使用
GetBSDProcessList
函数此处列出。这也有效,但是他们所说的检索进程名称的方式(从每个kinfo_proc
结构访问kp_proc.p_comm
)是有缺陷的。生成的char*
仅包含进程名称的前 16 个字符,这可以在kp_proc
结构的定义中看到:#define MAXCOMLEN 16 //在param.h中定义 struct extern_proc { //在proc.h中定义 ...剪断... char p_comm[MAXCOMLEN+1]; ...剪断... };
使用 libProc.h 检索进程信息:
pid_t pids[1024]; int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids)); for (int i = 0; i < 进程数; ++i) { if (pids[i] == 0) { 继续; } 字符名称[1024]; proc_name(pids[i], 名称, sizeof(名称)); printf("找到进程: %s\n", name); }
这可行,但它与
GetBSDProcessList
具有相同的缺陷。仅返回进程名称的第一部分。使用ProcessManager 函数碳含量:
进程序列号 psn; psn.lowLongOfPSN = kNoProcess; psn.highLongOfPSN = 0; while (GetNextProcess(&psn) == noErr) { CFStringRef 过程名称 = NULL; if (CopyProcessName(&psn, &procName) == noErr) { NSLog(@"找到进程:%@", (NSString *)procName); } CFRelease(procName); }
这不起作用。它只返回向 WindowServer 注册的进程(或类似的东西)。换句话说,它仅返回带有 UI 的应用程序,并且仅针对当前用户。
我无法使用
-[NSWorkspace launchApplications]
,因为这必须与 10.5 兼容。此外,这仅返回有关当前用户 Dock 中显示的应用程序的信息。
我知道可能检索正在运行的进程的名称(因为ps
可以做到这一点),但问题是“我可以在不分叉和执行的情况下做到这一点<代码>ps?”。
有什么建议吗?
编辑
经过大量研究后,我一直无法找到一种方法来做到这一点。我发现这个SO问题,它引用了< a href="http://bitbucket.org/chrismiles/psi/src/tip/src/arch/darwin_process.c" rel="noreferrer">Python 模块中的此 C 文件。这对于尝试在 sysctl 调用中使用 KERN_PROCARGS 值非常有用。
但是,Python 模块代码似乎源自 ps
的源代码,我在这里找到的。 ps 可以以某种方式获取每个正在运行的进程的可执行路径,但我尽最大努力提取其执行此操作的方式但没有成功。 print.c
中有一个名为 getproclline
的函数,它看起来很神奇,但是当我从自己的命令行工具中运行相同的代码时,我无法检索除我自己的进程之外的任何进程的进程可执行文件。
我会继续试验,但没有更多确凿的证据,看起来 @drawnonward 的答案是迄今为止最正确的。
编辑(很长一段时间后)
感谢奎因·泰勒指出的答案,我'我找到了有用的东西。它获取每个进程的可执行路径,然后我可以获取最后一个路径组件来获取实际的进程名称。
#import <sys/proc_info.h>
#import <libproc.h>
int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
pid_t pids[numberOfProcesses];
bzero(pids, sizeof(pids));
proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
for (int i = 0; i < numberOfProcesses; ++i) {
if (pids[i] == 0) { continue; }
char pathBuffer[PROC_PIDPATHINFO_MAXSIZE];
bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE);
proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer));
if (strlen(pathBuffer) > 0) {
printf("path: %s\n", pathBuffer);
}
}
First off, I know that similar questions have been asked, but the answers provided haven't been very helpful so far (they all recommend one of the following options).
I have a user application that needs to determine if a particular process is running. Here's what I know about the process:
- The name
- The user (
root
) - It should already be running, since it's a LaunchDaemon, which means
- Its parent process should be
launchd
(pid 1)
I've tried several ways to get this, but none have worked so far. Here's what I've tried:
Running
ps
and parsing the output. This works, but it's slow (fork
/exec
is expensive), and I'd like this to be as fast as possible.Using the
GetBSDProcessList
function listed here. This also works, but the way in which they say to retrieve the process name (accessingkp_proc.p_comm
from eachkinfo_proc
structure) is flawed. The resultingchar*
only contains the first 16 characters of the process name, which can be seen in the definition of thekp_proc
structure:#define MAXCOMLEN 16 //defined in param.h struct extern_proc { //defined in proc.h ...snip... char p_comm[MAXCOMLEN+1]; ...snip... };
Using libProc.h to retrieve process information:
pid_t pids[1024]; int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0); proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids)); for (int i = 0; i < numberOfProcesses; ++i) { if (pids[i] == 0) { continue; } char name[1024]; proc_name(pids[i], name, sizeof(name)); printf("Found process: %s\n", name); }
This works, except it has the same flaw as
GetBSDProcessList
. Only the first portion of the process name is returned.Using the ProcessManager function in Carbon:
ProcessSerialNumber psn; psn.lowLongOfPSN = kNoProcess; psn.highLongOfPSN = 0; while (GetNextProcess(&psn) == noErr) { CFStringRef procName = NULL; if (CopyProcessName(&psn, &procName) == noErr) { NSLog(@"Found process: %@", (NSString *)procName); } CFRelease(procName); }
This does not work. It only returns process that are registered with the WindowServer (or something like that). In other words, it only returns apps with UIs, and only for the current user.
I can't use
-[NSWorkspace launchedApplications]
, since this must be 10.5-compatible. In addition, this only returns information about applications that appear in the Dock for the current user.
I know that it's possible to retrieve the name of running processes (since ps
can do it), but the question is "Can I do it without forking and exec'ing ps
?".
Any suggestions?
EDIT
After doing a lot more research, I've been unable to find a way to do this. I found this SO question, which referred to this C file in a python module. This was really useful in trying to use the KERN_PROCARGS
values in a sysctl
call.
However, Python module code seemed to be derived from the source to ps
, which I found here. ps
can somehow get the executable path of every running process, but my best efforts to extract how its doing this have been unsuccessful. There's a function in print.c
called getproclline
that seems to be doing the magic, but when I run the same code from within my own command line tool, I'm unable to retrieve the process executable for any processes other than my own.
I'll keep experimenting, but without more conclusive evidence, it looks like @drawnonward's answer is the most correct so far.
EDIT (a long time later)
Thanks to the answer pointed to by Quinn Taylor, I've found something that works. It gets the executable path of each process, and then I can just grab the last path component to get the actual process name.
#import <sys/proc_info.h>
#import <libproc.h>
int numberOfProcesses = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
pid_t pids[numberOfProcesses];
bzero(pids, sizeof(pids));
proc_listpids(PROC_ALL_PIDS, 0, pids, sizeof(pids));
for (int i = 0; i < numberOfProcesses; ++i) {
if (pids[i] == 0) { continue; }
char pathBuffer[PROC_PIDPATHINFO_MAXSIZE];
bzero(pathBuffer, PROC_PIDPATHINFO_MAXSIZE);
proc_pidpath(pids[i], pathBuffer, sizeof(pathBuffer));
if (strlen(pathBuffer) > 0) {
printf("path: %s\n", pathBuffer);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这个相关问题的答案怎么样? https://stackoverflow.com/a/12274588/120292 这旨在通过 pid 获取进程的完整路径,您可以只获取最后一个路径组件。
What about this answer to a related question? https://stackoverflow.com/a/12274588/120292 This purports to get the full path for a process by the pid, and you can grab just the last path component.
上面的 2 询问内核提供了唯一完整的正在运行的进程列表。获取进程的实际名称并不简单。简而言之,您可以在任何其他可以找到的来源中查找 pid,直到找到匹配的为止。
对于某些进程,以下方法将起作用:
对于某些进程,您可以通过
NSApplicationProcessIdentifier
在[[NSWorkspace sharedWorkspace]launchApplications]
结果中查找 pid。适用于 10.2 及更高版本。此列表中的大多数(但可能不是全部)项目将与上面的 CopyProcessName 相同。对于某些进程,您可以查找进程参数并从第一个参数获取完整路径。与获取原始列表类似,但使用 KERN_PROCARGS 或 KERN_PROCARGS2 作为第二个 mib 值。这就是
ps
正在做的事情。对于某些进程,您只能使用 16 个字符的 p_comm。
The only complete list of running processes is provided by 2 above, asking the kernel. Getting the actual name of the process is not straight forward. In a nutshell, you look up the pid in any other source you can find until you get a match.
For some processes, the following will work:
For some processes, you can look up the pid in the results of
[[NSWorkspace sharedWorkspace] launchedApplications]
byNSApplicationProcessIdentifier
. Available with 10.2 and later. Most, but maybe not all, items in this list will be the same as CopyProcessName above.For some processes, you can look up the process arguments and get the full path from the first argument. Similar to getting the original list, but using KERN_PROCARGS or KERN_PROCARGS2 as the second mib value. This is what
ps
is doing.For some processes, you are stuck with the 16 character p_comm.
不确定这是否是您要找的,但您可以将
LaunchServices
API 与 __LSCopyApplicationArrayInFrontToBackOrder
一起使用吗?我听说过这个,但自己从未使用过。经过一番谷歌搜索后,这里的代码示例可能会提供您正在寻找的内容?我真的不知道并且猜测了一点;)http://gist.github.com/163918
编辑
实际上,哈。这是一个 Stack Overflow 帖子,给出了这个答案,并链接到我链接到的同一篇帖子...
http://www.stackoverflow.com/questions/945033/getting-the-list-of-running-applications-ordered-by-last-use
Not sure if this is what you're looking for, but could you use the
LaunchServices
API with __LSCopyApplicationArrayInFrontToBackOrder
? I've heard of this, but never used it myself. After some googling, here's a code sample that might provide what you're looking for? I really don't know and am guessing a little ;)http://gist.github.com/163918
Edit
Actually, Ha. Here's a Stack Overflow post that gives this as an answer and links to the same post I linked to...
http://www.stackoverflow.com/questions/945033/getting-the-list-of-running-applications-ordered-by-last-use