Вопрос

For an assignment, I am working on creating a time aware shell. The shell forks and executes commands and kills them if they run for more than a set amount of time. For example.

 input# /bin/ls
 a.out code.c
 input# /bin/cat
 Error - Expired After 10 Seconds.
 input#

Now, my question is: is there a way to prevent the alarm from starting if an error is incurred in the processing of the program, that is, when exevce returns -1?

Since the child-process runs separately and after hours of experimenting and research I have yet to find anything that discusses or even hints at this type of task, I have a feeling it may be impossible. If it is indeed impossible, how can I prevent something like the following from happening...

 input# /bin/fgdsfgs
 Error executing program
 input# Error - Expired After 10 Seconds.

For context, here is the code I am currently working with, with my attempt at doing this myself removed. Thanks for the help in advance!

while(1){
    write(1, prompt, sizeof(prompt)); //Prompt user
    byteCount = read(0, cmd, 1024); //Retrieve command from user, and count bytes
    cmd[byteCount-1] = '\0';    //Prepare command for execution

    //Create Thread
    child = fork();

    if(child == -1){
        write(2, error_fork, sizeof(error_fork));
    }

    if(child == 0){ //Working in child
        if(-1 == execve(cmd,arg,env)){  //Execute program or error
            write(2, error_exe, sizeof(error_exe));
        }   
    }else if(child != 0){   //Working in the parent
        signal(SIGALRM, handler);   //Handle the alarm when it goes off
        alarm(time);
        wait();
        alarm(0);
    }
}
Это было полезно?

Решение

According to the man page:

Description

The alarm() function shall cause the system to generate a SIGALRM signal for the process after the number of realtime seconds specified by seconds have elapsed. Processor scheduling delays may prevent the process from handling the signal as soon as it is generated.

If seconds is 0, a pending alarm request, if any, is canceled.

Alarm requests are not stacked; only one SIGALRM generation can be scheduled in this manner. If the SIGALRM signal has not yet been generated, the call shall result in rescheduling the time at which the SIGALRM signal is generated.

Interactions between alarm() and any of setitimer(), ualarm(), or usleep() are unspecified.

So, to cancel an alarm: alarm(0). It is even present in your sample code.

The main problem

By the way, you're missing an important piece here:

if(child == 0){ //Working in child
    if(-1 == execve(cmd,arg,env)){  //Execute program or error
        write(2, error_exe, sizeof(error_exe));
        _exit(EXIT_FAILURE);  // EXIT OR A FORKED SHELL WILL KEEP GOING
    }   
}else if(child != 0){   //Working in the parent

Другие советы

The wait() system call takes an argument; why aren't you compiling with the right headers in the source file and with compiler warnings (preferably errors) for undeclared functions? Or, if you are getting such warnings, pay heed to them before submitting code for review on places like StackOverflow.

You don't need to test the return status from execve() (or any of the exec*() functions); if it returns, it failed.

It is good to write an error on failure. It would be better if the child process exited as well, so that it doesn't go back into the while (1) loop, competing with your main shell for input data.

if (child == 0)
{
    execve(cmd, arg, env);
    write(2, error_exe, sizeof(error_exe));
    exit((errno == ENOEXEC) ? 126 : 127);
}

In fact, the non-exiting of your child is the primary cause of your problem; the wait doesn't return until the alarm goes off because the child hasn't exited. The exit statuses shown are intended to match the POSIX shell specification.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top