c - 有关命令终止事实的信息,C 中的 Shell
问题描述
runcommand() 用于通过fork()
.
对于在后台启动的命令,如何打印有关命令终止的信息(使用 waitpid 的 WNOHANG 选项)?
打印信息:进程终止 [PID]
重要的是所有子进程完全结束
#include <sys/types.h>
#include <signal.h>
#include <fcntl.h> // tipi di apertura file
#include <assert.h> // assert
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define EOL 1 /* end of line */
#define ARG 2 /* normal topic */
#define AMPERSAND 3 /* & */
#define SEMICOLON 4 /* ; */
#define REDIRECT 5 /* > */
#define APPEND 6 /* >> */
#define MAXARG 512 /* maximum number of arguments */
#define MAXBUF 512
#define FOREGROUND 0
#define BACKGROUND 1
int gettok(char **outptr); /* reads a symbol */
void runcommand(char **cline,int where); /* execute a command */
int inarg(char c); /* check if c is not a special character */
pid_t pid;
char prompt[MAXBUF];
static char inpbuf[MAXBUF], tokbuf[2*MAXBUF], *ptr, *tok;
static char special[]=
{' ', '\t', '&', ';', '\n', '\0', '>'};
int proc(void) /* treats a line of input */
{
char *arg[MAXARG+1]; /* array of pointers for runcommand */
int toktype;
int n_arg; /* number of topics considered so far */
int type; /* FOREGROUND o BACKGROUND */
n_arg=0;
while (1)
{
switch (toktype = gettok(&arg[n_arg]))
{
/* if argument: go to the next symbol */
case ARG:
if (n_arg < MAXARG)
{n_arg++;}
break;
/* if end of line or ';' or '&' executes the command now contained in arg, putting NULL to signal the end of the arguments: it serves as execvp */
case EOL:
case SEMICOLON:
case AMPERSAND:
type = (toktype == AMPERSAND) ? BACKGROUND : FOREGROUND;
if (n_arg != 0)
{
arg[n_arg] = NULL;
runcommand(arg,type);
}
if (toktype == EOL) return 1;
n_arg = 0;
break;
}
}
}
void runcommand(char **command,int wr)
{
int exitstat,ret;
pid = fork();
if (pid == (pid_t) -1)
{
perror("smallsh: fork fallita");
return;
}
if (pid == (pid_t) 0) /* child */
{
execvp(*command,command);/* executes a command */
perror(*command);
exit(1);
}
else if(wr != BACKGROUND) /* father */
{
ret = waitpid(pid, &exitstat, 0);
if (ret == -1) perror("wait");
}
}
int scan(char *p); /* print the prompt and read a line */
int main()
{
while(scan(prompt) != EOF)
proc();
}
int scan(char *p)
{
int c, count;
ptr = inpbuf;
tok = tokbuf;
printf("%s ",p);
count=0;
while(1)
{
if ((c = getchar()) == EOF)
return(EOF);
if (count < MAXBUF)
inpbuf[count++] = c;
if (c == '\n' && count < MAXBUF)
{
inpbuf[count] = '\0';
return(count);
}
if (c == '\n')
{
printf("riga in input troppo lunga\n");
count = 0;
printf("%s ",p);
}
}
}
int gettok(char **outptr)
{
int type;
*outptr = tok;
while (*ptr == ' ' || *ptr == '\t') ptr++;
*tok++ = *ptr;
switch(*ptr++)
{
case '\n':
type = EOL; break;
case '&':
type = AMPERSAND; break;
case ';':
type = SEMICOLON; break;
default:
type = ARG;
while(inarg(*ptr))
*tok++ = *ptr++;
}
*tok++ = '\0';
return(type);
}
int inarg(char c)
{
char *wrk;
for (wrk = special; *wrk != '\0'; wrk++)
if (c == *wrk) return(0);
return(1);
}
解决方案
所以如果你打电话ret = waitpid(pid, &exitstat, WNOHANG)
,那么即使孩子没有退出,命令也会返回。因此,您需要查看返回值ret
以查看函数是否成功,然后exitstat
查看子项是否退出(通过从main()
函数返回或由于信号):
if(ret >= 0)
{
if(WIFEXITED(exitstat) || WIFSIGNALED(exitstat))
{
printf("Child ended\n");
}
}
else
{
printf("Error!\n");
}
笔记:
在某些情况下,您可能还想检查
WIFSTOPPED(exitstat)
. 有关详细信息,请参阅waitpid(2)。如果出现错误,您可以检查errno以获取有关问题的更多信息。
推荐阅读
- java - 此 rtmp://username:password@xxxx:port/application/streamname for JAVA 的正则表达式模式
- java - Gradle badass-runtime-plugin 和 ProGuard Gradle 插件
- ios - 从 0.59 升级到 0.61 后找不到“React/RCTDefines.h”文件
- javascript - Angular“错误类型错误:无法读取未定义的属性‘匹配’”
- python - Django / Bootstrap 错误:参数“form”应包含有效的 Django 表单
- fortran - 了解 fortran 中的回溯错误
- arrays - 自动填充查找表中的列
- unity3d - 团结 3d。在网格中强制四边形而不是三角形
- spring-boot - 尝试创建通用 rest api 控制器时不明确的处理程序方法
- bash - 在 (ba)sh 中用 ~ 替换空格,无需外部命令