Skip to content

Commit 35e8e78

Browse files
committed
Assignment 4
1 parent 83f9691 commit 35e8e78

File tree

1 file changed

+162
-0
lines changed

1 file changed

+162
-0
lines changed

myshell.c

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/* In this assignment, you start writing a command interpreter (shell).
2+
3+
The shell will give a prompt for the user to type in a command from the set of
4+
commands. Take the command, execute it and give the prompt back to the user for
5+
the next command. Your program should be able to do the following:
6+
7+
1. Give a prompt "myshell>" for the user to type in a command
8+
2. Implement the following built in commands:
9+
a) cd <dir> : Changes the directory to dir
10+
b) pwd : Prints the current directory
11+
c) mkdir <dir> : Creates the directory dir
12+
d) rmdir <dir> : Removes the directory dir
13+
e) ls : Lists the files and directories in the present directory
14+
f) exit : Exits out of the shell
15+
3. Any other command typed at the prompt should be executed as if it is the
16+
name of the executable file. For example - typing "a.out" should execute the
17+
file a.out. This file can be in the current directory or any of the other
18+
directories specified by PATH environment variable.
19+
4. The executable file should be executed after creating a new process and
20+
executing the file onto it. The parent process should wait for the file to
21+
finish execution and then go on to read the next command from the user. The
22+
executable can take any number of command line parameters.
23+
*/
24+
25+
#include <stdio.h>
26+
#include <string.h>
27+
#include <stdlib.h>
28+
#include <unistd.h>
29+
#include <dirent.h>
30+
#include <sys/types.h>
31+
#include <sys/stat.h>
32+
33+
#define PROMPT "myshell>"
34+
#define BUFFERSIZE 150
35+
36+
char** split_by_space(char* string) {
37+
char** tokens = (char**)malloc(sizeof(char*) * 40);
38+
int i = 0;
39+
char *token = strtok(string, " ");
40+
while (token != NULL) {
41+
tokens[i++] = token;
42+
token = strtok(NULL, " ");
43+
}
44+
tokens[i] = NULL;
45+
return tokens;
46+
}
47+
48+
int main() {
49+
char command[BUFFERSIZE];
50+
int status;
51+
pid_t pid;
52+
53+
while (1) {
54+
55+
// Give the prompt
56+
printf("%s ", PROMPT);
57+
58+
// Read the command
59+
fgets(command, BUFFERSIZE, stdin);
60+
command[strlen(command) - 1] = '\0';
61+
62+
// Exit out of the program if the command is "exit"
63+
if (strcmp(command, "exit") == 0)
64+
break;
65+
66+
// If the command is "cd", use chdir() system call in the parent process
67+
else if (strstr(command, "cd") != NULL) {
68+
char dirname[BUFFERSIZE/3];
69+
strcpy(dirname, command + 3);
70+
int ret = chdir(dirname);
71+
if (ret)
72+
printf("%s: No such directory\n", dirname);
73+
}
74+
75+
// If the command is "cd", use getcwd() system call in the parent process
76+
else if (strcmp(command, "pwd") == 0) {
77+
char cwd[BUFFERSIZE];
78+
getcwd(cwd, BUFFERSIZE);
79+
printf("%s\n", cwd);
80+
}
81+
82+
// If the command is "mkdir", use mkdir() system call and give 755 permission
83+
else if (strstr(command, "mkdir") != NULL) {
84+
char dirname[BUFFERSIZE/3];
85+
strcpy(dirname, command + 6);
86+
int status = mkdir(dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
87+
if (status)
88+
printf("%s: Directory could not be created due to some error!\n", dirname);
89+
}
90+
91+
// If the command is "rmdir", use rmdir() system call
92+
else if (strstr(command, "rmdir") != NULL) {
93+
char dirname[BUFFERSIZE/3];
94+
strcpy(dirname, command + 6);
95+
int status = rmdir(dirname);
96+
if (status)
97+
printf("%s: Directory could not be removed due to some error!\n", dirname);
98+
}
99+
100+
// If the command is ls, use readdir() system call and filter out entries like
101+
// ., .. and any hidden files beginning with . to match the format used by ls
102+
else if (strcmp(command, "ls") == 0) {
103+
struct dirent *dp;
104+
DIR *dirp = opendir(".");
105+
int count = 0;
106+
if (dirp != NULL) {
107+
while ((dp = readdir(dirp)) != NULL) {
108+
if (dp->d_name[0] != '.') {
109+
if (++count % 4)
110+
printf("%-16s", dp->d_name);
111+
else
112+
printf("%-16s\n", dp->d_name);
113+
}
114+
}
115+
closedir(dirp);
116+
if (count % 4 != 0)
117+
printf("\n");
118+
} else {
119+
printf("Could not get the files of the current directory\n");
120+
}
121+
}
122+
123+
// For any other command, spawn a child process and execute the process in it
124+
else {
125+
if ((pid = fork()) == 0) {
126+
char **tokens = split_by_space(command);
127+
int file_in_cur_dir = 0;
128+
129+
// Check if the file is present in the current directory
130+
struct dirent *dp;
131+
DIR *dirp = opendir(".");
132+
if (dirp != NULL) {
133+
while ((dp = readdir(dirp)) != NULL) {
134+
if (strcmp(tokens[0], dp->d_name) == 0) {
135+
file_in_cur_dir = 1;
136+
break;
137+
}
138+
}
139+
closedir(dirp);
140+
}
141+
142+
// If the file is present in the current directory, add the current
143+
// directory to the PATH. This only lasts in the child process.
144+
if (file_in_cur_dir) {
145+
const char* PATH = "PATH";
146+
char* path = getenv(PATH);
147+
148+
char newpath[BUFFERSIZE*10];
149+
getcwd(newpath, BUFFERSIZE); // New path starts with the current directory
150+
strcat(newpath, ":");
151+
strcat(newpath, path); // Concatenate ":" followed by old path
152+
153+
setenv(PATH, newpath, 1); // Set the PATH environment variable
154+
}
155+
execvp(tokens[0], tokens);
156+
}
157+
else {
158+
waitpid(pid, &status, 0);
159+
}
160+
}
161+
}
162+
}

0 commit comments

Comments
 (0)