所以我正在尝试创建一个自定义shell,因为我将在下学期学习操作系统课程,并希望获得一些先发优势 - 并且制作一个自定义shell看起来很常见去做。所以,我正在试图弄清楚如何执行后台进程,而我真的很难搞清楚如何执行。如果有人能够深入了解我如何能够实施后台流程(显然使用“&”符号),我们将不胜感激。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MAX_SIZE 20
int getArgs(char *buffer){
int count = 1;
for (int i = 0; i < strlen(buffer); i++){
if (buffer[i] == ' ') count++;
}
return count;
}
void printError(){
char errorMessage[30] = "An error has occurred\n";
write(STDERR_FILENO, errorMessage, strlen(errorMessage));
}
int splitArg(char *buffer, char *args[], int numArgs){
char *tmp = strtok(buffer, " \n");
int i = 0, pipeOrRedir = 0; //pipeOrRedir will store -1 if a redirect ; number position in args if a pipe
//Traverse args, tokenize at space, newline.
while (tmp != NULL && i < MAX_SIZE -1){
if (strcmp(tmp, ">") == 0 && i == (numArgs-2)) pipeOrRedir = -1;
else if (strcmp(tmp, "|") == 0) pipeOrRedir = i;
//Create args[] from input, tokenize at space, newline
args[i] = tmp;
tmp = strtok(NULL, " \n");
i++;
}
args[i] = NULL;
return pipeOrRedir;
}
int main(int argc, char *argv[]){
char buffer[1024];
int numArgs, output, status, pipeOrRedir;
int count = 1;
pid_t pid;
while(1){
printf("shell (%d)> ", count);
fgets(buffer, 1024, stdin); //Get input
if (strlen(buffer) > 128){
printError();
printf("mysh (%d)> ", count);
}
numArgs = getArgs(buffer); //Get number of arguments in the command
char *args[numArgs + 1]; //Array of args (1 larger to hold NULL for execvp
pipeOrRedir = splitArg(buffer, args, numArgs);
//Ensure we don't have empty command line
if (strcmp(buffer, "\n") == 0){
printError();
printf("mysh (%d)> ", count);
}
//INTERNAL COMMANDS
//"exit"
if (strcmp("exit", args[0]) == 0){
if (numArgs != 1) printError();
else exit(0); //Successful exit
}
//"cd"
else if (strcmp("cd", args[0]) == 0){
if (args[1] == NULL) chdir(getenv("HOME"));
else{
if (chdir(args[1]) == -1) printError();
}
}
//"pwd"
else if (strcmp("pwd", args[0]) == 0){
//printf("%d\n", numArgs);
if (numArgs != 1) printError();
else printf("%s\n", getcwd(buffer, 1024));
}
//EXTERNAL COMMANDS
else{
pid = fork();
if (pid == 0){
//Inside child
//Arguments for execvp
char *prev[pipeOrRedir+1];
char *post[numArgs - pipeOrRedir];
prev[pipeOrRedir] = NULL;
post[numArgs - pipeOrRedir + 1] = NULL;
//REDIRECTION
if (pipeOrRedir == -1){
output = open(args[numArgs - 1], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
if (output < 0) printError();
//Change output stream stdout -> file
if (dup2(output, 1) == -1) printError();
args[numArgs - 1] = NULL;
args[numArgs - 2] = NULL;
}
//PIPING
else if (pipeOrRedir > 0){
//Set up pipe
if (pipeOrRedir == numArgs - 1) printError();
for (int i = 0; i < pipeOrRedir; i++){
prev[i] = args[i];
}
for (int j = 0; j < numArgs - pipeOrRedir; j++){
post[j] = args[j + pipeOrRedir + 1];
}
}
//EXECVP
if (pipeOrRedir < 1){
if (execvp(args[0], args) == -1) printError();
//If piping
int pipeFileDescriptor[2];
int pipeID;
pipe(pipeFileDescriptor);
pipeID = fork();
//Run 1st command, gives us output
if (pipeID > 0){
close(pipeFileDescriptor[0]); //Input pipe unused
dup2(pipeFileDescriptor[1], 1); //Close STDOUT, replace with pipe
if (execvp(prev[0], prev) == -1) printError();
close(pipeFileDescriptor[1]);
exit(0);
}
//Run 2nd command, takes input
else{
close(pipeFileDescriptor[1]);
dup2(pipeFileDescriptor[0], 0);
if (execvp(post[1], post) == -1) printError();
close(pipeFileDescriptor[0]);
exit(0);
}
}
exit(1);
}
else wait(&status);
}
count++;
}
close(output);
exit(0);
}