запуск процесса в фоновом режиме, тогда передний план не ждет в Ubuntu? - PullRequest
0 голосов
/ 01 ноября 2018

так что я пытаюсь создать cmd с использованием языка c. Однако при обнаружении «&» он должен работать в фоновом режиме. В настоящее время проблема заключается в том, что если, скажем, я запускаю «gedit &», то «gedit», «gedit» не будет ждать, когда он выйдет после его вызова. Я пытался отладить, но я обнаружил, что то же самое происходит с оболочкой Ubuntu. Однако я хотел бы реализовать это по-другому. Есть ли веская причина для решения, почему это происходит и как я могу реализовать это, как я объяснил?

gedit & #this is to run gedit in the background
gedit #this should run gedit and block the terminal

Это мой код:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <limits.h>
#include <signal.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#define TRUE 1
#define DELIMITER "\t\n "
FILE *f;

/*
* description: this functions parses an array of characters to
*              seperate strings
* @params:
*   char *command - pointer to an array of characteres
*   char **params - pointer to a pointer of an array of characters
* @returns:
* int isBackroung - a number > 0 showcases this is a background process
*/
int tokenizer(char *command, char** params)
{
    // count to keep track of each token and add it to params
    int count = 0;
    // this has the tokens returend from the strtok
    char *ptr = strtok(command, DELIMITER);
    // acts as a bolean to check if u ser entered '&' and execute it as background
    int isBackground = 0;

    while( ptr != NULL )
    {
        params[count] = ptr;
        //check if background process
        if(strcmp(ptr, "&") == 0)
        {
            // replace it with null character to prevent it from confusing commnads like ls
            params[count] = '\0';
            isBackground = count;
        }
        count++;
        ptr = strtok(NULL, DELIMITER);
    }

    //adding the null for execvp
    params[count] = NULL;

    return isBackground;
}

/*
* description: writes in file when a child is terminated
* @params:
*   int sig- signal when child is terminated
* @returns:
* int isBackroung - a number > 0 showcases this is a background process
*/
void handler(int sig)
{
    pid_t pid;
    int status;

    //hunting zombie processes
    //
    pid_t pid2 = waitpid(-1, &status, WNOHANG);
    //open file in append mode
    f= fopen("shell.log","a+");


    //in case an error pops up
    if(!f)
    {
        fprintf(stderr, "Error openning file");
    }
    fprintf(f,"Child %d was termintaed\n", pid);
    fclose(f);

}


/*
* description: forks the current process and waits if not a background process
* @params:
*   cahr* program- main program name
*   cahr** params- argument list includingthe program name
*   int background- if 1 then it is a background process
* @returns:
*/

void spawn (char* program, char** params, int isBackground)
{
    pid_t child_pid;
    //used for wait, meaning this variable will be set when process child finshes
    int status;
    //passing signals to cal handler
    signal(SIGCHLD,handler);
    //in the case no command entered just do nothing
    if(params[0]==NULL) ;

    // implementation of exit with 0 to showcase no errors
    else if(strcasecmp(params[0], "exit") == 0)
        exit(0);
    else
    {
        //fork child
        child_pid = fork();

        // if negative then error in forking
        if (child_pid < 0)
        {
            fprintf (stderr, "an error occurred cannot fork\n");
        }
        // a zero value means child so go ahead child execute ur code
        else if (child_pid == 0)
        {
            //this is a system call to execute the command and its options/args/flags
            execvp(program, params);

            // if execvp returns, meaning there is a n error, then we need to tell the user
            fprintf (stderr, "an error occurred in execvp or maybe just an non-existent command\n");
        }
            // if its a background then we need to wait for the process
            else if(!isBackground)
            {
                printf("child: %d\n", child_pid);
                pid_t j = waitpid(child_pid, &status, 0);
                printf("child: %d %d\n", child_pid, WSTOPSIG(status));

            }
            else
            {
                //this is just to sleep the parent for a while to make printing prettier
                printf("child: %d\n", child_pid);
                sleep(1);
            }


    }
}



void main()
{
    // Command is an array of strings that is initially used to take the entire input
    // params is a pointer to arrays of strings in order to take further command args(ex: ls -l)
    char command[2048];
    char *params[128];
    char cwd[PATH_MAX];

    // fancy way of showing u where u r currently working when u start
    if (getcwd(cwd, sizeof(cwd)) != NULL)
    {
        printf("Current working dir: %s\n", cwd);
    }

    // Inifinitely running loop to keep the program running
    while(TRUE)
    {
        printf("Shell>");

        //read the entire line into command
        fgets(command,2048,stdin);

        printf("\n");

        // just to make sure that the entered commands are shorter than the array
        if(strlen(command)<2049)
            //tokenizer will parse the command, where the command name will be params[0]
            //spawn it executes the commands and fork processes
            spawn(params[0],params,tokenizer(command, params));
        else
        {
            fprintf(stdout, "Youn need to enter a string of max size 2048");
        }
    }
}
...