function
- Print prompt information: [current user name @ hostname current working directory name] identifier ($#)
- Get user's command: command name option parameter
- To classify commands:
1) Built in command: exit cd
2) External command: a separate program. The subprocess created by bash runs the executable file under / bin - Create subprocess: the subprocess replaces the executable corresponding to the command entered by the user
Source code
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <assert.h> #include <sys/types.h> #include <sys/utsname.h> #include <pwd.h> #include <signal.h> #define NUM 20 #define LENGTH 128 char OLDPWD[LENGTH] = { 0 }; // Save last working path //Output prompt void PrintfTag() { //[username @ hostname current working directory] symbol char flag = '$'; //Ordinary users if(getuid() == 0) //root users { flag = '#'; } //getuid returns the uid of the current user //getpwuid returns user information according to uid (return type is structure pointer) struct passwd *pw = getpwuid(getuid()); assert(pw != NULL); //Get host information struct utsname hostname; uname(&hostname); //getcwd gets the absolute path of the current working directory char path[LENGTH] = { 0 }; getcwd(path, LENGTH - 1); char *dirName = NULL; if(strcmp(path, pw->pw_dir) == 0) //Determine whether the current path is home directory { dirName = "~"; } else if(strlen(path) == 1) //Determine whether the path is the root directory { dirName = "/"; } else { dirName = path + strlen(path); while(*dirName != '/') { dirName--; } dirName++; } printf("[%s@%s %s]%c", pw->pw_name, hostname.nodename, dirName, flag); } //Cut command string by space void CutCommandString(char *cmd, char *Argv[]) { // cmd: "ls -l /bin" // Each pointer of the Argv array points to a cut string int index = 0; char *p = strtok(cmd, " "); while(p != NULL) { Argv[index++] = p; p = strtok(NULL, " "); } //Verify the cut is successful /* int i = 0; for(; i < index; i++) { printf("%s\n", Argv[i]); } */ } //Implement cd command void AchieveCd(char *path) { /* * cd Path -- > int chdir (const char * path); success returns 1, failure returns 0 * cd / cd ~ * cd - */ // Get the absolute path of the current working directory char nowPath[LENGTH] = { 0 }; getcwd(nowPath, LENGTH - 1); if(path == NULL || strncmp(path, "~", 1) == 0) //Switch to home directory or directory under home directory { struct passwd *pw = getpwuid(getuid()); path = strcat(pw->pw_dir, path + 1); } if(strncmp(path, "-", 1) == 0) //Switch to the last directory { if(strlen(OLDPWD) == 0) { printf("mybush: OLDPWD no set\n"); return; } path = OLDPWD; } //Toggle directory if(-1 == chdir(path)) { perror(path); return; } //Save the path before switching to OLDPWD memset(OLDPWD, 0, LENGTH); strcpy(OLDPWD, nowPath); //Test code /* memset(nowPath, 0, LENGTH); getcwd(nowPath, LENRTH - 1); printf("%s\n", nowPath); */ } //Sort commands and process built-in commands int DealBuiltInCmd(char *Argv[]) { // Argv[0]: user entered command if(strncmp(Argv[0], "exit", 4) == 0) { exit(0); //End mybush } if(strncmp(Argv[0], "cd", 2) == 0) { AchieveCd(Argv[1]); // Switch to the specified working directory return 1; } return 0; } //Signal processing function void SignBack(int sign) { wait(NULL); } //Create child process void CreatChild(char *Argv[]) { // SIGCHLD will be sent to the parent process after the child process ends signal(SIGCHLD, SignBack); pid_t pid = fork(); assert(pid != -1); if(pid == 0) { //Search for executable files in / bin by default char path[LENGTH] = "/bin/"; //Must be an absolute path if(strstr(Argv[0], "/") != NULL) //Determine whether the command given by the user has a path { memset(path, 0, LENGTH); strcpy(path, Argv[0]); } else { strcat(path, Argv[0]); } execv(path, Argv); perror(path); exit(0); //Prevent sub process exec replacement failure } else // Background operation { int i = NUM - 1; for(; i >= 0; i--) { if(Argv[i] != NULL) { break; } } if(strcmp(Argv[i], "&") != 0) { wait(NULL); } } } int main() { while(1) { //1. Output prompt information PrintfTag(); //2. Get user input command string char cmd[LENGTH] = { 0 }; fgets(cmd, LENGTH - 1, stdin); //Writing string to cmd from standard input encountered end of carriage return and also got carriage return cmd[strlen(cmd) - 1] = 0; //Set carriage return to 0 //3. The cutting of string separates command from option and parameter according to space char *Argv[NUM] = { 0 }; //Pointer array to store the separated strings CutCommandString(cmd, Argv); //4. Classification command 1. CD exit 2. External if(DealBuiltInCmd(Argv)) //If the DealBuiltInCmd function processes built-in commands, the program returns the first sentence of while, otherwise it continues { continue; } //5. Create a child process. The child process replaces the external command. The parent process wait s for the child process to execute the command CreatChild(Argv); } }
Published 21 original articles, won praise 0, visited 332