так что я пытаюсь создать 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");
}
}
}