Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
cse550
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
0
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Winston Jodjana
cse550
Commits
f833938a
Commit
f833938a
authored
2 years ago
by
Dixon Tirtayadi
Browse files
Options
Downloads
Patches
Plain Diff
Part A
parent
396690e9
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
assignment1/parta/Makefile
+13
-1
13 additions, 1 deletion
assignment1/parta/Makefile
assignment1/parta/shell.c
+249
-2
249 additions, 2 deletions
assignment1/parta/shell.c
with
262 additions
and
3 deletions
assignment1/parta/Makefile
+
13
−
1
View file @
f833938a
# Running make in parta must produce an executable called 550shell.
CC
=
gcc
CFLAGS
=
-g
-Wall
all
:
shell
shell
:
shell.o
$(
CC
)
$(
CFLAGS
)
-o
sh shell.c
shell.o
:
shell.c
$(
CC
)
$(
CFLAGS
)
-c
$<
clean
:
/bin/rm
-f
sh
*
.o
*
~
\ No newline at end of file
This diff is collapsed.
Click to expand it.
assignment1/parta/shell.c
+
249
−
2
View file @
f833938a
...
...
@@ -13,7 +13,254 @@ Can:
- Use reasonable, hard-coded maximum sizes to simplify your code.
*/
int
main
(
void
)
{
char
buf
[
128
];
// Assume max char
#include
<stdio.h>
#include
<stdlib.h>
#include
<sys/types.h>
#include
<sys/wait.h>
#include
<unistd.h>
#include
<string.h>
#include
<ctype.h>
// Remove leading and trailing space from str
char
*
trimwhitespace
(
char
*
str
);
// Split line into commands terminated by "|", and store it into *cmds.
// Returns the number of commands there are.
int
getCommands
(
char
***
cmds
,
char
*
line
);
// Set up pipe and execute command cmds[i]. To be called in the child thread.
void
childRun
(
int
i
,
int
n_cmds
,
char
*
cmds
[],
int
old_pipe
[],
int
new_pipe
[]);
int
main
()
{
char
*
line
=
NULL
;
size_t
len
=
0
;
ssize_t
nread
;
int
status
;
char
**
cmds
=
malloc
(
sizeof
(
char
*
));
// Array for commands
printf
(
"Shell is starting...
\n
"
);
printf
(
"$ "
);
// Loop until EOF reading stdin
while
((
nread
=
getline
(
&
line
,
&
len
,
stdin
))
!=
-
1
)
{
line
[
nread
-
1
]
=
'\0'
;
// Remove \n character
// Get the commands from the user input line
int
n_cmds
=
getCommands
(
&
cmds
,
line
);
// Loop through commands and execute it while piping stuff to next command
int
old_pipe
[
2
];
for
(
int
i
=
0
;
i
<
n_cmds
;
i
++
)
{
int
new_pipe
[
2
];
// If its not the last command, open a pipe
if
(
i
!=
n_cmds
-
1
)
{
if
(
pipe
(
new_pipe
)
==
-
1
)
{
perror
(
"pipe creation fails"
);
exit
(
EXIT_FAILURE
);
}
}
// Call the program
if
(
fork
()
==
0
)
{
// Child: set up pipe and execute the command by calling helper
childRun
(
i
,
n_cmds
,
cmds
,
old_pipe
,
new_pipe
);
}
else
{
// Parent: wait for the child
if
(
i
>
0
)
{
// Not the first command, close previous old_pipe so no leak
close
(
old_pipe
[
0
]);
close
(
old_pipe
[
1
]);
}
if
(
i
<
n_cmds
-
1
)
{
// Not the last command, change pipe for the next iteration use
old_pipe
[
0
]
=
new_pipe
[
0
];
old_pipe
[
1
]
=
new_pipe
[
1
];
}
wait
(
&
status
);
}
}
// Print prompt for next user command
printf
(
"$ "
);
}
// Free stuff up
free
(
cmds
);
free
(
line
);
exit
(
EXIT_SUCCESS
);
}
int
getCommands
(
char
***
cmds
,
char
*
line
)
{
char
*
token
;
// For splitting string input into tokens separated by ' '
token
=
strtok
(
line
,
"|"
);
int
n_cmds
=
0
;
// Loop through tokens and get all commands, store it in an array first
while
(
token
!=
NULL
)
{
*
cmds
=
realloc
(
*
cmds
,
sizeof
(
char
*
)
*
++
n_cmds
);
if
(
*
cmds
==
NULL
)
{
perror
(
"realloc fails"
);
exit
(
EXIT_FAILURE
);
}
char
**
cmd_arr
=
*
cmds
;
cmd_arr
[
n_cmds
-
1
]
=
trimwhitespace
(
token
);
token
=
strtok
(
NULL
,
"|"
);
}
return
n_cmds
;
}
// Code from https://stackoverflow.com/questions/122616/how-do-i-trim-leading-trailing-whitespace-in-a-standard-way
// Pretty straightforward code, was looking to find a library function to do this but found this in stackoverflow,
// used it instead.
char
*
trimwhitespace
(
char
*
str
)
{
char
*
end
;
// Trim leading space
while
(
isspace
((
unsigned
char
)
*
str
))
str
++
;
if
(
*
str
==
0
)
// All spaces?
return
str
;
// Trim trailing space
end
=
str
+
strlen
(
str
)
-
1
;
while
(
end
>
str
&&
isspace
((
unsigned
char
)
*
end
))
end
--
;
// Write new null terminator character
end
[
1
]
=
'\0'
;
return
str
;
}
void
childRun
(
int
i
,
int
n_cmds
,
char
*
cmds
[],
int
old_pipe
[],
int
new_pipe
[])
{
// child: execute the program
if
(
i
>
0
)
{
// Not the first command, read from pipe instead of stdin
dup2
(
old_pipe
[
0
],
0
);
close
(
old_pipe
[
0
]);
close
(
old_pipe
[
1
]);
}
if
(
i
<
n_cmds
-
1
)
{
// Not the last command, output to pipe instead of stdout
dup2
(
new_pipe
[
1
],
1
);
close
(
new_pipe
[
0
]);
close
(
new_pipe
[
1
]);
}
// Execute the command
char
*
args
[
2
];
args
[
0
]
=
cmds
[
i
];
args
[
1
]
=
NULL
;
// Args need to be terminated by NULL
execvp
(
cmds
[
i
],
args
);
printf
(
"Cannot run the command
\"
%s
\"\n
"
,
cmds
[
i
]);
// Note that if it reaches here, valgrind will report "still reachable" memory leak
// because the main process is still holding memory, but it's kinda a false report
// because the allocation will be cleaned up at the end.
exit
(
EXIT_SUCCESS
);
// This is a case where the cmd is not runnable, just exit.
}
// Testing code can be cleaned up later
// ----------------------------------------------------------------------------------
// int main() {
// char *line = NULL;
// size_t len = 0;
// ssize_t nread;
// int status;
// char* token; // For splitting string input into tokens separated by ' '
// char** args = malloc(sizeof(char*)); // Array for arguments
// if (args == NULL) {
// exit(-1);
// }
// printf("Shell is starting \n");
// printf("> ");
// // Loop until EOF reading stdin
// while ((nread = getline(&line, &len, stdin)) != -1) {
// int n_spaces = 0;
// line[nread - 1] = '\0'; // Remove \n character
// printf("Retrieved line of length %zd with value %s\n", nread, line);
// // fwrite(line, nread, 1, stdout);
// token = strtok(line, " ");
// /* walk through other tokens */
// while(token != NULL) {
// printf("%s\n", token);
// args = realloc(args, sizeof (char*) * ++n_spaces);
// if (args == NULL) {
// exit (-1); /* memory allocation failed */
// }
// args[n_spaces-1] = token;
// token = strtok(NULL, " ");
// // if (token == '|') {
// // // pipe stuff
// // }
// }
// // Args needs to end with null as last argument
// args = realloc(args, sizeof (char*) * (n_spaces+1));
// args[n_spaces] = NULL;
// // Call the program
// if (fork() == 0) {
// execvp(args[0], args); // child: execute the program
// } else {
// wait(&status); // parent: wait for the child before next prompt
// }
// printf("> ");
// }
// // Free stuff up
// free(args);
// free(line);
// exit(1);
// }
// ----------------------------------------------------------------------------------
// int main(int argc, char *argv[]) {
// int pipefd[2];
// pid_t cpid;
// char buf;
// if (argc != 2) {
// fprintf(stderr, "Usage: %s <string>\n", argv[0]);
// exit(EXIT_FAILURE);
// }
// if (pipe(pipefd) == -1) {
// perror("pipe");
// exit(EXIT_FAILURE);
// }
// cpid = fork();
// if (cpid == -1) {
// perror("fork");
// exit(EXIT_FAILURE);
// }
// if (cpid == 0) { /* Child reads from pipe */
// close(pipefd[1]); /* Close unused write end */
// while (read(pipefd[0], &buf, 1) > 0)
// write(STDOUT_FILENO, &buf, 1);
// write(STDOUT_FILENO, "\n", 1);
// close(pipefd[0]);
// _exit(EXIT_SUCCESS);
// } else { /* Parent writes argv[1] to pipe */
// close(pipefd[0]); /* Close unused read end */
// write(pipefd[1], argv[1], strlen(argv[1]));
// close(pipefd[1]); /* Reader will see EOF */
// wait(NULL); /* Wait for child */
// exit(EXIT_SUCCESS);
// }
// }
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment