WIFSIGNALED returns false 即使我在 Linux 上使用 kill 命令发送信号(Mint 18.3)
WIFSIGNALED returns false even if I send a signal with the kill command on Linux(Mint 18.3)
问题:我需要打印一个进程收到的kill信号,
对于示例:
如果我发送 *kill -15 1245*
其中 1245 是我进程的 pid,我的程序应该打印类似 "Process killed by signal 15"
,但即使我向进程发送 *kill -15*
,WIFSIGNALED macro returns false and obviously WTERMSIG returns 0.
系统: 我在 Linux Mint 18.3,一个基于 Ubuntu 的发行版,我在其他 Ubuntu 上测试了我的程序] 发行版仍然无法正常工作,但在 Fedora 和 OpenSUSE 中运行良好。有什么想法吗?
代码:
//Libraries
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
//Macros
#define MAX_LIMIT 50
//Function where i create a child process and execute a shell over it.
void run(char comando[])
{
int status;
pid_t pid;
if((pid = fork()) == 0)
execlp("sh", "sh", "-c", comando, NULL);
pid = waitpid(pid, &status, 0);
//The problem begins here, the WIFEXITED returns *true* even is the process was killed by a signal.
if(WIFEXITED(status))
printf("Process ended with status %d\n",
WEXITSTATUS(status));
//Is here when i need to print the signal, but WIFSIGNALED returns *false* even if a signal was sended by the *kill* command.
else if(WIFSIGNALED(status))
printf("Process killed by signal %d\n",
WTERMSIG(status));
else if(WIFSTOPPED(status))
printf("Process stopped by signal %d\n",
WSTOPSIG(status));
else if(WIFCONTINUED(status))
printf("Process continued...\n");
}
//Function that simulates a shell by repeating prompt.
void shell()
{
run("clear");
printf("\t\t\t\t\tMINI_SHELL\n");
char comando[MAX_LIMIT];
do
{
printf("$> ");
fgets(comando, MAX_LIMIT, stdin);
char *cp = strchr(comando,'\n'); if (cp != NULL) *cp = 0;
if(strcmp(comando, "ext") != 0)
run(comando);
} while(strcmp(comando, "ext") != 0);
}
int main(int argc, char *argv[])
{
shell();
return 0;
}
这一切都归结为基于 debian 的发行版 (/bin/dash
) 和基于 redhat 的发行版 (/bin/bash
) 的默认 shell 之间的差异。
当你打电话时
execlp("sh", "sh", "-c", comando, NULL);
与 commando
类似 "cat"
或 "echo 1; cat"
,如果 sh
是 /bin/dash
(如在 debian 上),则 shell 将在退出前调用 waitpid()
自身获取 cat
的状态;如果 sh
是 /bin/bash
,它只会 exec
直到脚本中的最后一个命令。
尝试在你的 mini-shell 中输入像 echo pid=$$; cat
这样的命令,然后 kill
回显打印的 pid,而不是 cat
的 pid,然后你将获得预期的 'Process killed by signal ...'
注:此为置顶评论前言
因为fgets
在末尾留下了一个\n
,所以在传递给execlp
之前应该将其删除。否则,由于找不到以换行符结尾的命令,该命令可能会 [快速](具有 WIFEXITED
状态)失败。要删除它,请在 fgets
之后添加:
char *cp = strchr(comando, '\n');
if (cp != NULL)
*cp = 0;
在 Fedora 下,/bin/sh
是 /bin/bash
的符号链接。在 Ubuntu 下,sh
可能会链接到其他内容。在调用目标命令之前,shell 如何进行解释以及它们如何设置默认信号掩码可能存在差异。
由于 Fedora 工作正常,为了保持一致性,将 execlp
中的 sh
替换为 bash
。这应该使两个分布的行为相似。
问题:我需要打印一个进程收到的kill信号,
对于示例:
如果我发送 *kill -15 1245*
其中 1245 是我进程的 pid,我的程序应该打印类似 "Process killed by signal 15"
,但即使我向进程发送 *kill -15*
,WIFSIGNALED macro returns false and obviously WTERMSIG returns 0.
系统: 我在 Linux Mint 18.3,一个基于 Ubuntu 的发行版,我在其他 Ubuntu 上测试了我的程序] 发行版仍然无法正常工作,但在 Fedora 和 OpenSUSE 中运行良好。有什么想法吗?
代码:
//Libraries
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>
//Macros
#define MAX_LIMIT 50
//Function where i create a child process and execute a shell over it.
void run(char comando[])
{
int status;
pid_t pid;
if((pid = fork()) == 0)
execlp("sh", "sh", "-c", comando, NULL);
pid = waitpid(pid, &status, 0);
//The problem begins here, the WIFEXITED returns *true* even is the process was killed by a signal.
if(WIFEXITED(status))
printf("Process ended with status %d\n",
WEXITSTATUS(status));
//Is here when i need to print the signal, but WIFSIGNALED returns *false* even if a signal was sended by the *kill* command.
else if(WIFSIGNALED(status))
printf("Process killed by signal %d\n",
WTERMSIG(status));
else if(WIFSTOPPED(status))
printf("Process stopped by signal %d\n",
WSTOPSIG(status));
else if(WIFCONTINUED(status))
printf("Process continued...\n");
}
//Function that simulates a shell by repeating prompt.
void shell()
{
run("clear");
printf("\t\t\t\t\tMINI_SHELL\n");
char comando[MAX_LIMIT];
do
{
printf("$> ");
fgets(comando, MAX_LIMIT, stdin);
char *cp = strchr(comando,'\n'); if (cp != NULL) *cp = 0;
if(strcmp(comando, "ext") != 0)
run(comando);
} while(strcmp(comando, "ext") != 0);
}
int main(int argc, char *argv[])
{
shell();
return 0;
}
这一切都归结为基于 debian 的发行版 (/bin/dash
) 和基于 redhat 的发行版 (/bin/bash
) 的默认 shell 之间的差异。
当你打电话时
execlp("sh", "sh", "-c", comando, NULL);
与 commando
类似 "cat"
或 "echo 1; cat"
,如果 sh
是 /bin/dash
(如在 debian 上),则 shell 将在退出前调用 waitpid()
自身获取 cat
的状态;如果 sh
是 /bin/bash
,它只会 exec
直到脚本中的最后一个命令。
尝试在你的 mini-shell 中输入像 echo pid=$$; cat
这样的命令,然后 kill
回显打印的 pid,而不是 cat
的 pid,然后你将获得预期的 'Process killed by signal ...'
注:此为置顶评论前言
因为fgets
在末尾留下了一个\n
,所以在传递给execlp
之前应该将其删除。否则,由于找不到以换行符结尾的命令,该命令可能会 [快速](具有 WIFEXITED
状态)失败。要删除它,请在 fgets
之后添加:
char *cp = strchr(comando, '\n');
if (cp != NULL)
*cp = 0;
在 Fedora 下,/bin/sh
是 /bin/bash
的符号链接。在 Ubuntu 下,sh
可能会链接到其他内容。在调用目标命令之前,shell 如何进行解释以及它们如何设置默认信号掩码可能存在差异。
由于 Fedora 工作正常,为了保持一致性,将 execlp
中的 sh
替换为 bash
。这应该使两个分布的行为相似。