-
Notifications
You must be signed in to change notification settings - Fork 0
/
simple_shell.c
184 lines (170 loc) · 5.03 KB
/
simple_shell.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include "shell.h"
/**
* get_input - Displays a prompt and retrieves user input
* @queue: destination to store a pointer to a linked list of commands
* input will be converted to a linked list and the address stored here
* !NOTE! This pointer WILL be overwritten with a new address. It must
* be free_list()'d before calling get_input() again to prevent memory leaks.
* Return: 0 if getline fails, 1 on success
* !NOTE! Yes, these return values are inconsistent
*/
int get_input(str_list_t **queue)
{
int getl_r = 0, i, is_tty = isatty(STDIN_FILENO);
size_t buff_len = 0;
char *buffer = NULL, *prompt = "$ ";
*queue = NULL;
if (is_tty) /* Display the command prompt if in interactive mode */
write(STDOUT_FILENO, prompt, _strlen(prompt));
/* Wait for and store user input */
getl_r = getline(&buffer, &buff_len, stdin);
if (getl_r == -1) /* ^D or other failure */
{
free(buffer);
is_tty ? write(STDOUT_FILENO, "\n", 1) : 0;/* Print newline before closing */
return (0);
}
/* Save input line to history; Format input for execution */
/* Strip out any comments "#" */
for (i = 0; buffer[i]; i++)
{
if (buffer[i] == '#')
{
if (i > 0 && (buffer[i - 1] != ' ' && buffer[i - 1] != '\t'))
continue;
buffer[i] = '\0';
break;
}
}
if (buffer[0] == ';')
{
print_error("Syntax error: \";\" unexpected\n");
free(buffer);
return (1);
}
/* Split into statements based on the command separator ";" */
/* And add statements to a queue */
*queue = split_str(buffer, ";\n");
free(buffer);
return (1);
}
/**
* get_built_in - checks if input is calling a shell built-in and
* returns a pointer to a built-in function if it finds one
* @built_in_name: the name of the built-in to return
* Return: pointer to the appropriate built-in; NULL if not found
*/
int (*get_built_in(char *built_in_name))(list_t *)
{
int built_in;
built_in_t built_ins[] = {
/* {"alias", alias}, */
{"cd", cd},
{"env", env},
/* {"exit", exit_built_in}, */
/* {"help", help}, */
/* {"setenv", setenv}, */
/* {"unsetenv", unsetenv}, */
{NULL, NULL}
};
if (!built_in_name)
return (NULL);
/* Find the index of the built-in */
for (built_in = 0; built_ins[built_in].name; built_in++)
{
if (_strncmp(built_in_name, built_ins[built_in].name, 0) == 0)
return (built_ins[built_in].function);
}
return (NULL);
}
/**
* execute - creates and executes child process with arguments
* @input_ll: linked list of commands for the child process
*/
int execute(str_list_t *input_ll)
{
pid_t pid;
char **child_argv = NULL;
int wstatus;
/* Create argv from the linked list */
child_argv = str_list_t_to_array(input_ll);
pid = fork(); /* Create a child process */
if (pid == -1)
exit(EXIT_FAILURE);
else if (pid == 0) /* Inside the child process: */
{ /* Try to execute string arguments as a command */
if (execve(child_argv[0], child_argv, get_env(NULL)) == -1)
exit(EXIT_FAILURE);
}
free(child_argv);
if (wait(&wstatus) == -1) /* Let the child process exit before continuing */
return(EXIT_FAILURE);
if (WIFEXITED(wstatus))
return (WEXITSTATUS(wstatus));
else
return (EXIT_FAILURE);
}
/**
* init_globals - initializes "global" variables.
* Saves their addresses into getters.
* The getters return the values of the variables without allowing
* direct modification (read only).
* @argv_adrs: address of argv
* @env_adrs: address of env
* @count_adrs: address of count
*/
void init_globals(char ***argv_adrs, char ***env_adrs, int *count_adrs)
{
get_env(env_adrs);
get_argv(argv_adrs);
get_count(count_adrs);
}
/**
* main - dash imitation
* @argc: number of command line arguments
* @argv: command line arguments
* @env: environment variables
* Return: always 0 (needs to be updated)
*/
int main(int argc, char **argv, char **env)
{
int (*built_in)(list_t *);
str_list_t *input_ll = NULL, *queue = NULL, *command;
int count = 0, exit_code = 0;
init_globals(&argv, &env, &count);
signal(SIGINT, sigint_handler);
while (1) /* Loop until forced to quit */
{
/* Get user input and generate a linked list */
if (!get_input(&queue))
break;/* Close shell if user enters ^D */
count++; /* count for errors or execution */
/* While there are statements in the queue... */
for (command = queue; command; command = command->next)
{ /* Create linked list from each queued statement */
input_ll = split_str(command->str, " \t");
if (!input_ll)
break;
built_in = get_built_in(input_ll->str);
if (_strncmp("exit", input_ll->str, 0) == 0)
exit_built_in(input_ll, queue, exit_code);
/* Check for and execute built-ins */
else if (built_in)
exit_code = built_in(input_ll->next);
/* If no built-in was found, run search_path fuction */
/* PATH_search modifies input_ll with a new head node*/
else
{
exit_code = PATH_search(&input_ll);
/* if search finds the func, execute child process */
if (exit_code == 0)
exit_code = execute(input_ll);
}
free_list(input_ll);
}
free_list(queue);
}
return (exit_code);
/* TEMPORARY SECTION TO GET AROUND COMPILATION WARNINGS */
argc += 0;
}