首页 > 解决方案 > 有关命令终止事实的信息,C 中的 Shell

问题描述

runco​​mmand() 用于通过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);
}

标签: cshfork

解决方案


所以如果你打电话ret = waitpid(pid, &exitstat, WNOHANG),那么即使孩子没有退出,命令也会返回。因此,您需要查看返回值ret以查看函数是否成功,然后exitstat查看子项是否退出(通过从main()函数返回或由于信号):

if(ret >= 0)
{
    if(WIFEXITED(exitstat) || WIFSIGNALED(exitstat))
    {
        printf("Child ended\n");
    }
}
else
{
    printf("Error!\n");
}

笔记:

  1. 在某些情况下,您可能还想检查WIFSTOPPED(exitstat). 有关详细信息,请参阅waitpid(2)

  2. 如果出现错误,您可以检查errno以获取有关问题的更多信息。


推荐阅读