Question: Looking for some help on these next two steps for my code. My code: #include #include #include #include #include #include #include #define MAX_ARGS 512 #define
Looking for some help on these next two steps for my code.

My code:
#include
#define MAX_ARGS 512 #define MAX_ARG_LEN 2048
// Declaring function prototypes: void str_replace(char *str, const char *old_str, const char *new_str); void expand_env(char *str);
// Signal handler for SIGINT and SIGTSTP void handle_signal(int signo) { printf(" "); fflush(stdout); }
// Function to replace a substring in a string with another string void str_replace(char *str, const char *old_str, const char *new_str) { size_t old_len = strlen(old_str); size_t new_len = strlen(new_str); char *pos = strstr(str, old_str); while (pos != NULL) { // Shift the characters after the old string to make room for the new string memmove(pos + new_len, pos + old_len, strlen(pos + old_len) + 1); // Copy the new string into the position of the old string memcpy(pos, new_str, new_len); // Look for the next occurrence of the old string pos = strstr(pos + new_len, old_str); } }
// Function to expand the environment variables in a string void expand_env(char *str) { int status; pid_t bg_pid; // Declare the variable for background PID // Replace any occurrence of "$$" with the process ID char pid_str[16]; sprintf(pid_str, "%d", getpid()); str_replace(str, "$$", pid_str);
// Replace any occurrence of "$?" with the exit status char exit_str[16]; sprintf(exit_str, "%d", WEXITSTATUS(status)); str_replace(str, "$?", exit_str);
// Replace any occurrence of "$!" with the process ID of the most recent background process char bg_pid_str[16]; sprintf(bg_pid_str, "%d", bg_pid); str_replace(str, "$!", bg_pid_str);
// Replace any occurrence of "~/" at the beginning of a word with the value of HOME environment variable if (str[0] == '~' && (str[1] == '/' || str[1] == '\0')) { str_replace(str, "~/", getenv("HOME")); } }
int main() { // Set signal handlers for SIGINT and SIGTSTP struct sigaction sa; sa.sa_handler = handle_signal; sa.sa_flags = SA_RESTART; sigfillset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTSTP, &sa, NULL);
while (1) { // Check for any un-waited-for background processes pid_t pid; int status; while ((pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { if (WIFEXITED(status)) { printf("background pid %jd is done: exit value %d ", (intmax_t) pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("background pid %jd is done: terminated by signal %d ", (intmax_t) pid, WTERMSIG(status)); } else if (WIFSTOPPED(status)) { printf("background pid %jd is stopped: signal %d ", (intmax_t) pid, WSTOPSIG(status)); kill(pid, SIGCONT); printf("background pid %jd is continued ", (intmax_t) pid); } }
// Print the prompt printf(": "); fflush(stdout);
// Read the command line input char input[MAX_ARGS * MAX_ARG_LEN]; if (fgets(input, sizeof(input), stdin) == NULL) { break; }
// Expand environment variables expand_env(input); // Split the command line input into tokens char *args[MAX_ARGS]; char *token = strtok(input, " "); int arg_count = 0; while (token != NULL) { args[arg_count++] = token; token = strtok(NULL, " "); } args[arg_count] = NULL;
// Check if the command is a built-in command if (strcmp(args[0], "exit") == 0) { exit(0); } else if (strcmp(args[0], "cd") == 0) { if (arg_count > 1) { chdir(args[1]); } else { chdir(getenv("HOME")); } } else { // Execute the command pid_t pid = fork(); if (pid == -1) { perror("fork"); } else if (pid == 0) { // Child process execvp(args[0], args); perror(args[0]); exit(1); } else { // Parent process if (args[arg_count - 1][0] == '&') { // Background process printf("background pid %jd ", (intmax_t) pid); } else { // Foreground process waitpid(pid, &status, 0); if (WIFSIGNALED(status)) { printf("terminated by signal %d ", WTERMSIG(status)); } } } } } return 0; }
Built-in commands If the command to be executed is exit or cd the following built-in procedures shall be executed. Note: The redirection and background operators mentioned in Step 4 are ignored by built-in commands. exit The built-in takes one argument. If not provided, the argument is implied to be the expansion of " $? ?, the exit status of the last foreground command. It shall be an error if more than one argument is provided or if an argument is provided that is not an integer. . Smallsh does not need to wait on these child processes and may exit immediately. See, cd The cd built-in takes one argument. If not provided, the argument is implied to be the expansion of " , the value of the HOME environment variable. If shall be an error if more than one argument is provided. Smallsh shall change its own current working directory to the specified or implied path. It shall be an error if the operation fails. (See Non-Built-in commands PATH environment variable (see EXECVP(3)). If a call to fails, it shall be an error. In the child: - All signals shall be reset to their original dispositions when smallsh was invoked. Note: This is not the same as SIG_DFL! See oldact in for reading or does not already exist. with permissions 0777. It shall be an error if the file cannot be opened (or created) for writing. - If the child process fails to exec (such as if the specified command cannot be found), it shall be an error. - When an error occurs in the child, the child shall immediately print an informative error message to 6. Waiting Built-in commands skip this step. 128+[n] where [n] is the number of the signal that caused the child process to terminate. run in the background. Any other child state changes (e.g. WIFCONTINUED) shall be ignored. value should be set to the pid of such a process
Step by Step Solution
There are 3 Steps involved in it
Get step-by-step solutions from verified subject matter experts
