So, I thought I was on the right track with trying to imitate the bash shell, but I'm having issues piping. I am getting an error executing the second command. I was wondering if someone could explain to me how to fix this and why it's going wrong.
I'm very new to C & Linux commands so any supplemental information that could help me along the way would be also be appreciated.
Thank you so much for your time. My code is below, but there is a lot of it. My issue is occurring in the exec_pipe function. I would normally include what I have used for input and what I am getting for output, but my sample input is actually executable files my professor gave us for testing. Unfortunately, mine is not working like it does in the shell. I am just getting my error print out:
Inside Case 5
Inside Exec_Pipe
Error in Pipe EXECVP cmd2
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdbool.h>
#include <time.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/wait.h>
#define BUFSIZE 1024
#define CSTRSIZE 100
#define CMDSIZE 30
#define DEBUG 1
//I referenced our blackboard source code files to create the fork functions and to deal with file descriptors
void exec_cmd(char** cmd1){
pid_t pid;
if((pid = fork()) < 0){
printf("Child Process Failed\n");
}else if(pid == 0){
if(execvp(cmd1[0], cmd1) < 0){
printf("Execution Failed\n");
exit(1);
}
}else{
wait(NULL);
}
}
void exec_cmd_in(char** cmd1, char* infile){
pid_t pid;
int fdi;
if((pid = fork()) < 0){
printf("Child Process Failed\n");
}else if(pid == 0){
fdi = open(infile, O_RDONLY);
if(fdi == -1){
printf("No Infile");
}
}
}
void exec_cmd_opt_in_append(char** cmd1, char* infile, char* outfile){
/* pid_t pid;
int fdi, fdo;
if((pid = fork()) < 0){
printf("Child Process Failed\n");
}else if(pid == 0){
fdo = open(outfile, O_RDWR | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
if(fdo == -1){
printf("No Outfile");
}
if(dup2(fdi, 0) == -1){
printf("Infile not updated");
}
if(dup2(fdo, 1) == -1){
printf("Outfile not updated");
}
close(fdi);
close(fdo);
if(execvp(cmd1[0], cmd1) < 0){
printf("Execution Failed\n");
exit(1);
}
}else{
wait(NULL);
} */
}
void exec_cmd_opt_in_write(char** cmd1, char* infile, char* outfile){
/* pid_t pid;
int fdi, fdo;
if((pid = fork()) < 0 ){
printf("Fork Error");
exit(1);
}else if(pid == 0 ){
fdo = open(outfile, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if(fdo == -1){
printf("No Outfile");
}
if(dup2(fdi, 0) == -1){
printf("Infile not updated");
}
if(dup2(fdo, 1) == -1){
printf("Outfile not updated");
}
close(fdi);
close(fdo);
if(execvp(cmd1[0], cmd1) < 0){
printf("Execution Failed\n");
exit(1);
}
}else{
wait(NULL);
}
*/
}
void exec_pipe(char** cmd1, char** cmd2){
pid_t pid;
int pipefd[2];
// pipe[1] is the write end of the pipe
// pipe[0] is the read end of the pipe
// making a pipe
printf("Inside Exec_Pipe\n");
pid = fork();
switch(pid){
case -1:
//error in fork
printf("Fork Error\n");
//Exit
exit(1);
case 0:
//child
break;
default:
//parent
wait(NULL);
}
//This will be executed by child process
if(pipe(pipefd) < 0 ) {
//error condition
printf("Pipe Error");
exit(1);
}
pid = fork();
switch(pid){
case -1:
//error in fork
printf("Fork Error\n");
//Exit
case 0:
//child
close(STDIN_FILENO);
//direct STDOUT to the pipe
dup2(pipefd[1], STDOUT_FILENO);
//Close descriptors
close(pipefd[0]);
close(pipefd[1]);
//Execute Command1
execvp(cmd1[0], cmd1);
//execvp should not return, so if it does
//there is an error!
printf("Error in EXECVP cmd1");
exit(1);
default:
//parent
close(STDIN_FILENO);
//direct input to the pipe
dup2(pipefd[0],STDIN_FILENO);
//close descriptors
close(pipefd[0]);
close(pipefd[1]);
//execute command 2
execvp(cmd2[0],cmd2);
//if execvp makes it back, error condition
printf("Error in Pipe EXECVP cmd2");
exit(1);
}
}
void exec_pipe_opt_in_append(char** cmd1, char** cmd2, char* infile, char* outfile){
}
void exec_pipe_opt_in_write(char** cmd1, char** cmd2, char* infile, char* outfile){
}
int parse_command(char* line, char** cmd1, char** cmd2, char* infile, char* outfile){
/*
(1)Create a bunch of flags to compare for the right return value
(2)Loop over the entire line and set the flags
(3)Add a bunch of if statements to compare flags
(4)If there is more than one flag for pipe, we can't handle it. Regurn 9.
(5)If there is &, we can't handle.
(6)Return the right value
*/
int pipe_found = 0;
int input_found = 0;
int redirection = 0;
int i = 0;
int spaces = 0;
int append = 0;
int special = 0;
while(line[i] != '\0'){
if(line[i] == '|'){
pipe_found++;
}
if(line[i] == '<'){
input_found = 1;
}
if((line[i] == '&') || (line[i] == '*') || (line[i] == '^') || (line[i] == '%') || (line[i] == '#') || (line[i] == '!') || (line[i] == '#') || (line[i] == '(') || (line[i] == ')')){
special = 1;
}
if(line[i] == '>'){
redirection = 1;
if(line[i+1] == '>'){
append = 1;
}
}
if(line[i] == ' '){
spaces++;
}
i++;
}
if((strlen(line) >=4) && (line[0] == 'q') && (line[1] == 'u') && (line[2] == 'i') && (line[3] == 't')){
return 0;
}
if((pipe_found == 0) && (special == 0)){
if((redirection == 0) && (input_found == 0)){
return 1;
}else if((redirection == 0) && (input_found == 1)){
return 2;
}else if(append == 1){
return 3;
}else if(redirection == 1){
return 4;
}
}else if((pipe_found == 1) && (special == 0)){
if((redirection == 0) && (input_found == 0)){
return 5;
}else if((redirection == 0) && (input_found == 1)){
return 6;
}else if(append == 1){
return 7;
}else if(redirection == 1){
return 8;
}
}
return 9;
}
//I referenced StackOverflow and some online libraries to get this tokenize function
char ** tokenize(char *str, char *delim, unsigned int *number_tokens) {
char *pch = strtok(str, delim);
unsigned int ntok = 0;
if(pch != NULL) {
ntok = 1;
}else{
return NULL;
}
char **tokens = realloc(NULL, sizeof(char *)*ntok);
tokens[ntok-1] = pch;
while(pch != NULL) {
pch = strtok(NULL, delim);
ntok++;
tokens = realloc(tokens, sizeof(char *)*ntok);
tokens[ntok-1] = pch;
}
if(number_tokens) {
*number_tokens = ntok;
}
return tokens;
}
//I referenced StackOverflow.com for this trim function
char *trim(char *str) {
char *end;
if(str == NULL){
return NULL;
}
while(isspace(*str)){
str++;
}
end = str + strlen(str) - 1;
while(end > str && isspace(*end)) {
end--;
}
*(end+1) = 0;
return str;
}
int main(int argc, char *argv[]){
int returnValue = 0;
char *infile = NULL;
char *outfile = NULL;
char **cmd = NULL;
char **cmd1_tokens = NULL;
char **cmd2_tokens = NULL;
char *input;
int current_cmd = 0;
/*
(1)If the user does not enter a command line argument, get one after typing "myshell-%"
(2)Call parse_command on the user input to get the right return value
(3)Begin parsing the user input within main
*/
if(argc == 1){
printf("myshell-%%\n");
fgets (input, 20, stdin);
returnValue = parse_command(input, cmd1_tokens, cmd2_tokens, infile, outfile);
cmd = tokenize(input, "|", NULL);
}else{
returnValue = parse_command(argv[1], cmd1_tokens, cmd2_tokens, infile, outfile);
cmd = tokenize(argv[1], "|", NULL);
}
int infileIt = 0;
while(cmd[current_cmd] != NULL) {
unsigned int number_tokens = 0;
char **infile_token = tokenize(cmd[current_cmd], "<", &number_tokens);
if(number_tokens > 1){
while(infile_token[infileIt] != NULL){
infileIt++;
}
}
if(infile_token[1] != NULL) {
number_tokens = 0;
char **infile_outfile_token = tokenize(infile_token[1], ">", &number_tokens);
if(number_tokens > 1){
infile = infile_outfile_token[0];
infile = infile_token[1];
}
}
number_tokens = 0;
char **outfile_token = tokenize(cmd[current_cmd], ">", &number_tokens);
if(number_tokens > 1){
outfile = outfile_token[1];
}
current_cmd++;
}
//Trim the in/outfiles
infile = trim(infile);
outfile = trim(outfile);
/*
Start breaking up cmd[0] and cmd[1] into smaller chunks and saving into the appropriate cmd
*/
cmd1_tokens = tokenize(cmd[0], " ", NULL);
if(cmd[1] != NULL){
cmd2_tokens = tokenize(cmd[1], " ", NULL);
}
int cmd1Args = 0;
while(cmd1_tokens[cmd1Args] != NULL){
cmd1Args++;
}
int cmd2Args= 0;
if(cmd2_tokens != NULL){
while(cmd2_tokens[cmd2Args] != NULL){
cmd2Args++;
}
}
int iterator = 0;
while((iterator < cmd1Args) && (cmd1Args != 0)){
printf("Cmd1: %s\n", cmd1_tokens[iterator]);
iterator++;
}
iterator = 0;
while((iterator < cmd2Args)&&(cmd2Args != 0)){
printf("Cmd2: %s\n", cmd2_tokens[iterator]);
iterator++;
}
if(infile != NULL){
printf("Infile: %s\n", infile);
}
if(outfile != NULL){
printf("Outfile: %s\n", outfile);
}
/*Use a switch statement to process all the return values (0 ot 9) of parse_command.
Our program should execute the “line” if the return code from parse_command
function is 0 to 8, that is the line is deemed “valid”. For return code 9,
our program simply output ”Not handled at this time!”.*/
switch(returnValue){
case 0 :
printf("Exiting Program.\n");
exit(1);
break;
case 1 :
printf("Inside Case 1\n");
exec_cmd(cmd1_tokens);
break;
case 2 :
printf("Inside Case 2\n");
exec_cmd_in(cmd1_tokens, infile);
break;
case 3 :
printf("Inside Case 3\n");
exec_cmd_opt_in_append(cmd1_tokens, infile, outfile);
break;
case 4 :
printf("Inside Case 4\n");
exec_cmd_opt_in_write(cmd1_tokens, infile, outfile);
break;
case 5 :
printf("Inside Case 5\n");
exec_pipe(cmd1_tokens, cmd2_tokens);
break;
case 6 :
printf("Inside Case 6\n");
//exec_pipe_in(cmd1_tokens, cmd2_tokens, infile);
break;
case 7 :
printf("Inside Case 7\n");
exec_pipe_opt_in_append(cmd1_tokens, cmd2_tokens, infile, outfile);
break;
case 8 :
printf("Inside Case 8\n");
exec_pipe_opt_in_write(cmd1_tokens, cmd2_tokens, infile, outfile);
break;
default :
printf("Inside Case 9\n");
printf("Not handled at this time!\n");
}
return 0;
}
Without having access to the input file that you're giving it, it's a little hard to say what's going on, but here are some tips for debugging it.
First, when something you don't understand is happening, it can be a good idea to strip it down to a minimal, working, self contained example that demonstrates the problem. Sometimes, just the process of cutting it down to that small example can help you to find the problem; but if not, it gives you a much smaller example to ask about.
Next, when putting in these print statements to debug what's going on, give yourself a little more context. Especially in the one that indicates an error; print out what the error is, and what the arguments were to the function that failed. Rather than just:
printf("Error in Pipe EXECVP cmd2");
You can use strerror to get a string representing the error number:
printf("Error %d in Pipe EXECVP cmd2: %s\n", errno, strerror(errno));
And you can also print out what the command and all of your arguments were:
for (char **arg = cmd2; *arg != NULL; ++arg) {
printf("cmd2[%ld] = %s", arg - cmd2, *arg);
}
Between printing out the actual error and printing out the command name and all of the arguments, that should help you to debug the problem.
If you could add that information to your question, and maybe cut your example down to a more minimal example as well as showing a minimal example of the input that causes a problem, we could probably help out a lot more.
Related
I am currently trying to create my own (simple) shell - in C language - but I have a hard time with redirection I/O.
I compile and run in VMware(gcc ,and if i want to execute the command :
$cat < file_in.txt > file_out.txt
I get :
File errorcat: '<': No such file or directory
cat: file_in.txt: No such file or directory
Function in header file:
void fileRedirect(char **args, int k, int ioMode)
{
pid_t pid, wpid;
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
int fd, status = 0;
pid = fork();
if (pid == 0) {
// Child process
if(ioMode == 0) // Input mode
fd = open(args[k+1], O_RDONLY, mode);
else // Output mode
fd = open(args[k+1], O_WRONLY|O_CREAT|O_TRUNC, mode);
if(fd < 0)
fprintf(stderr, "File error");
else {
dup2(fd, ioMode); // Redirect input or output according to ioMode
close(fd); // Close the corresponding pointer so child process can use it
args[k] = NULL;
args[k+1] = NULL;
if (execvp(args[0], args) == -1) {
perror("SHELL");
}
exit(EXIT_FAILURE);
}
}
else if (pid < 0) { // Error forking process
perror("SHELL");
}
else {
// Parent process. Wait till it finishes execution
do {
wpid = waitpid(pid, &status, WUNTRACED);
}
while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
}
And .c code :
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include "functions.h"
#define BUFSIZE 64 // Size of a single token
#define TOKEN_DELIM " \t\r\n\a" // Token Delimiters
void main(){
char *command = NULL, cwd[1024], *pwd;
char **args, *options[4] = {"<", ">"};
int k = 0, option, found;
pwd = NULL;
pwd = getenv("HOME");
do
{
ssize_t bsize = 0;
found = 0;
printf("$");
if(getcwd(cwd, sizeof(cwd)) != NULL)
{
printf("%s$", cwd);
}
getline(&command, &bsize, stdin);
if(endOfFile(command) == 0)
{
printf("\n");
break;
}
if(charLimit(command) == 0)
{
printf("\n");
break;
}
args = splitTokens(command);
if(args[0] == NULL)
{
free(command);
free(args);
continue;
}
if(strcmp(args[0],"exit") == 0)
{
break;
}
else if(strcmp(args[0], "cd") == 0)
{
if(args[1] == NULL)
{
if(pwd[0] != 0)
{
chdir(pwd);
}
}
else
{
chdir(args[1]);
}
}
else
{
k = 1;
while(args[k] != NULL) { // Check for any of the redirect or process operators <,<,|,&
for(option = 0; option < 2; option++) {
if(strcmp(args[k],options[option]) == 0)
break;
}
if(option < 2) {
found = 1;
if(args[k+1] == NULL) { // For IORedirect and Pipe, argument is necessary
fprintf(stderr, "SHELL: parameter missing\n");
break;
}
fileRedirect(args, k, option);
}
k++;
}
if(found == 0)
execute(args, 0); // Start a foreground process or command
}
free(command);
free(args);
} while(1);
}
I have seen many answers in similar question,but they made me more confused.
Thank you in advance .
I'm making simple shell program and trying to exit it if the user enters "exit" and I've tried a few different keywords such as exit(), return 0, break;
This is my code:
void read_command(char path[], char *args[], char input[]) {
char *array[MAX], *ptr;
char *inputptr;
if ((inputptr = strchr(input, '\n')) != NULL) {
*inputptr = '\0';
}
int i = 0;
char *p = strtok(input, " ");
while (p != NULL) {
array[i++] = p;
p = strtok(NULL, " ");
}
for (int j = 0; j < i; j++) {
args[j] = array[j];
}
}
int main() {
char path[MAX];
char *args[MAX] = {NULL};
int status;
char input[MAX];
while (TRUE) {
printf(">> ");
fgets(input, sizeof(input), stdin);
if (fork() != 0) {
if (waitpid(-1, &status, 0) < 0) {
perror("waitpid error ");
}
} else {
read_command(path, args, input);
if (strcmp(input, "exit") == 0) {
exit(0);
}
strcpy(path, "/bin/");
strcat(path, args[0]);
if (execve(path, args, 0) < 0) {
perror("exec error ");
return EXIT_FAILURE;
}
}
}
return EXIT_SUCCESS;
}
When I return the strcomp() value it does give me 0 so I'm not sure why it's not working the program seems to completely ignore that exit statement and just carries on with the code, can someone explain how I could to this? Thank you.
You're calling exit in the child process that you just forked off. Instead, read the command in the parent process and then either exit or fork. By the way, you should really be checking that fork does not return -1:
read_command(path, args, input);
if (strcmp(input, "exit") == 0)
/* Don't pass zero here, that's not portable. */
exit(EXIT_SUCCESS);
pid_t child;
switch ((child = fork())) {
case -1:
perror("fork failed");
exit(EXIT_FAILURE);
case 0:
// call exec
default:
/* Don't pass -1 here if you know which child to wait for.
Also, you can just pass NULL if to status */
if (waitpid(child, NULL, 0) < 0)
perror("waitpid error ");
}
int main(void){
int n, user_length;
char userid[30];
char password[11];
if ((n = read(STDIN_FILENO, userid, 10)) == -1) {
perror("read");
exit(1);
} else if(n == 0) {
fprintf(stderr, "Error: could not read from stdin");
exit(1);
}
if (userid[n-1] == '\n')
userid[n-1] = '\0';
else
userid[n] = '\0';
if ((n = read(STDIN_FILENO, password, 10)) == -1) {
perror("read");
exit(1);
} else if (n == 0) {
fprintf(stderr, "Error: could not read from stdin");
exit(1);
}
if (password[n-1] == '\n')
password[n-1] = '\0';
else
password[n] = '\0';
strcat(userid, ":");
user_length = strlen(userid);
strcat(userid, password);
FILE *fp = fopen(PASSWORD_FILE, "r");
if (!fp) {
perror("fopen");
exit(1);
}
char line[MAXLINE];
while(fgets(line, sizeof(line) - 1, fp)) {
line[strlen(line) - 1] = '\0';
if (strcmp(userid, line) == 0)
exit(0); // found match
else if(strncmp(userid, line, user_length) == 0)
exit (2); // invalid password
}
exit(3); // no such user
}
Above is the implementation of validate.c, but how do I pass value such as userid and password to the function by using pipe(),dup2 or execl()
I used the following`
int main(void) {
char userid[10];
char password[10];
int pid;
int p[2][4];
char other[MAXSIZE];
/* Read a user id and password from stdin */
printf("User id:\n");
scanf("%s", userid);
printf("Password:\n");
scanf("%s", password);
/*Your code here*/
if (pipe(p[1]) == -1) {
perror("pipe");
}
if (pipe(p[0]) == -1) {
perror("pipe");
}
pid = fork();
if (pid != 0) {
close(p[1][0]);
close(p[0][0]);
dup2(p[1][1],STDIN_FILENO);
dup2(p[0][1],STDIN_FILENO);
close(p[1][1]);
close(p[0][1]);
int status;
if (wait(&status)!= -1) {
if (WIFEXITED(status)) {
printf("[%d] Child exited with %d\n", getpid(), WEXITSTATUS(status));
switch(WEXITSTATUS(status)){
case 0:
printf("found match\n");
break;
case 2:
printf("invalid password\n");
break;
case 3:
printf("No such user\n");
break;
default:
printf("error has occur\n");
break;
};
} else {
printf("[%d] Child exited abnormally\n", getpid());
}
}
} else if (pid == 0) {
close(p[1][1]);
close(p[0][1]);
dup2(p[1][0], fileno(stdout));
dup2(p[1][0], fileno(stdout));
execl("validate",other);
printf("what\n");
close(p[1][0]);
close(p[0][0]);
} else {
perror("fork");
exit(1);
}
return 0;
}
But the prompt always asks me for re-entering the input. What is wrong with this approach?( Note: I "execl" "validate" because it is an executable file that has been already created. The execl() I wrote simply calls the validate.c function )
As I said in the comments you probably do not need to spawn another process for this but You have an error in the way you call execl.
This:
execl("validate",other);
Should be:
execl(filename,list of arguments, NULL);
This is the documentation page. They use (char *) 0 which is the same as using NULL.
I am trying to create a simple c shell. The only thing I can't get to work is the piping. I just need one pipe (i.e. "ls | wc -l"). I can't find anything where someone does this by reading the arguments from command line, any help would be greatly appreciated. I need help getting a second set of arguments that is after the "|" right now if I had the argument "ls | wc -l" I would get "ls" stored in args2 but I need "wc -l" to be in args3 so I can execvp() them separately.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#define HISTORY_COUNT 20
char *prompt = "% ";
int
main()
{
int pid;
//int child_pid;
char line[81];
char *token;
char *separator = " \t\n";
char **args;
char **args2;
char **args3;
char cmd[100];
char *hp;
char *cp;
char *ifile;
char *ofile;
int check;
int pfds[2];
int i;
int j;
int current = 0;
int p = 0;
//int check;
char *hist[HISTORY_COUNT];
//char history[90];
//typedef void (*sighandler_t) (int);
args = malloc(80 * sizeof(char *));
args2 = malloc(80 * sizeof(char *));
while (1) {
fprintf(stderr, "%s", prompt);
fflush(stderr);
if (fgets(line, 80, stdin) == NULL)
break;
// split up the line
i = 0;
while (1) {
token = strtok((i == 0) ? line : NULL, separator);
if (token == NULL)
break;
args[i++] = token;
/* build command array */
}
args[i] = NULL;
// assume no redirections
ofile = NULL;
ifile = NULL;
// split off the redirections
j = 0;
i = 0;
while (1) { //stackoverflow.com/questions/35569673
cp = args[i++];
if (cp == NULL)
break;
switch (*cp) {
case '<':
if (cp[1] == 0)
cp = args[i++];
else
++cp;
ifile = cp;
break;
case '>':
if (cp[1] == 0)
cp = args[i++];
else
++cp;
ofile = cp;
break;
case '|': //I need this case to put the commands following
the pipe into a variable
if(cp[1] ==0){
cp = args[i++];
printf("%s\n", cp);
if(pipe(pfds) == -1){
perror("Broken Pipe");
exit(1);
}
//args3[j++] = cp;
p = 1;
}
else{
++cp;
printf("DOES THIS HAPPEN\n");
//
}
break;
default:
args2[j++] = cp;
args3[cp++] = cp
break;
}
}
args2[j] = NULL;
if (j == 0)
continue;
switch (pid = fork()) {
case 0:
// open stdin
if (ifile != NULL) {
int fd = open(ifile, O_RDONLY);
if (dup2(fd, STDIN_FILENO) == -1) {
fprintf(stderr, "dup2 failed");
}
close(fd);
}
// open stdout
if (ofile != NULL) {
// args[1] = NULL;
int fd2;
if ((fd2 = open(ofile, O_WRONLY | O_CREAT, 0644)) < 0) {
perror("couldn't open output file.");
exit(0);
}
// args+=2;
printf("okay");
dup2(fd2, STDOUT_FILENO);
close(fd2);
}
if(p == 1){ //from stackoverflow.com/questions/2784500
printf("Welcome to the party\n");
close(1);
dup(pfds[1]);
close(pfds[0]);
execvp(args2[0], args2);
break;
}
if(strcmp(args2[0], "cd") == 0){ //cd command
if(args2[1] == NULL){
fprintf(stderr, "Expected argument");
}
else{
//printf("Is this happening");
check = chdir(args2[1]);
//printf("What abuot this");
if(check != 0){
fprintf(stderr,"%s",prompt);
}
}
break;
}
if (strcmp(args2[0], "history") == 0){
int i = 0;
int hist_num = 1;
//printf("%d\n", current);
do {
if (hist[i]) {
printf("%4d %s\n", hist_num, hist[i]);
hist_num++;
}
i = (i + 1) % HISTORY_COUNT;
} while (i != current);
break;
}
execvp(args2[0], args2); /* child */
signal(SIGINT, SIG_DFL);
fprintf(stderr, "ERROR %s no such program\n", line);
exit(1);
break;
case -1:
/* unlikely but possible if hit a limit */
fprintf(stderr, "ERROR can't create child process!\n");
break;
default:
//printf("am I here");
if(p==1){
close(0);
dup(pfds[0]);
close(pfds[1]);
//execvp();
}
wait(NULL);
//waitpid(pid, 0, 0);
}
}
exit(0);
}
I'm actually trying to implement a basic minishell in C. For doing that, I made a fonction which parse what the user enter in the console. I parsed it and then I would like to send the command to the console using pipes. I don't understand why my pipes are not working.
I checked the parsing and it seems to be fine, i have the right commands in parameters of the fonction.
The thing is that my pipe code is literally doing nothing and I don't understand why.
Here is my code.
Thank you in advance.
#define READ 0
#define WRITE 1
char *cmds[5] = {0};
int main() {
char *saisie = (char*)malloc(100*sizeof(char*));
char *saisie2 = (char*)malloc(100*sizeof(char*));
gets(saisie);
int ncmds = 0;
int k = 0;
char* token = (char*)malloc(100*sizeof(char*));
char* tofree;
if(*(saisie + 0) == '$'){
if(*(saisie + 2) == 'e' && *(saisie + 3) == 'x' && *(saisie + 4) == 'i' || *(saisie + 5) == 't'){
exit(0);
}
else{
int i;
for(i = 0;i<99;i++){
*(saisie2+i) = *(saisie+i+1);
}
free(saisie);
if (saisie2 != NULL) {
tofree = saisie2;
while ((token = strsep(&saisie2, "|")) != NULL){
cmds[ncmds] = token;
ncmds++;
}
free(tofree);
}
}
}
exe(cmds, ncmds);
while(wait(NULL) > 0);
return 0;
}
int exe(char *cmds[], int ncmds){
int fdin, fdout;
int fds[2];
int i;
int status;
fdin = 0;
for(i=0; i < ncmds-1; i++){
pipe(fds);
fdout = fds[WRITE];
if(fork() == 0){
if( fdin != 0 ) {
close(0);
dup(fdin);
close(fdin);
}
if( fdout != 1 ) {
close(1);
dup(fdout);
close(fdout);
}
close(fds[READ]);
const char* prog2[] = {cmds[i], "-l", 0};
execvp(cmds[i], prog2);
fprintf(stderr, "si esto se ve es un error\n");
exit(1);
}
if(fdin != 0)
close(fdin);
if(fdout != 1)
close(fdout);
fdin = fds[READ];
}
/* Ultimo comando */
fdout = 1;
if(fork() == 0) {
if( fdin != 0 ) {
close(0);
dup(fdin);
close(fdin);
}
const char* prog2[] = {cmds[i], "-l", 0};
execvp(cmds[i], prog2);
close(fds[READ]);
exit(1);
}
if(fdout!= 1)
close(fdout);
if(fdin != 0)
close(fdin);
}
}
int exe(char *cmds[], int ncmds){
int p2c[2];//pipe parent to child
int c2p[2];//pipe child to parent
int i;
int status;
int pid;
char buf[4096];
memset(buf, 0, 4096);
for(i=0; i < ncmds; i++){
pipe(p2c);
pipe(c2p);
pid = fork();
if(pid < 0) {
exit 1;
}
if(pid == 0){ //in child
close(1);
dup2(c2p[1],1); // make child write to c2p pipe instead of stdout
close(0);
dup2(p2c[0],0); // make child read from p2c pipe instead of stdin
close(p2c[1]);
close(c2p[0]);
const char* prog2[] = {cmds[i], "-l", 0};
execvp(cmds[i], prog2);
fprintf(stderr, "si esto se ve es un error\n");
exit(1);
}
//in parent
write(p2c[1], buf, strlen(buf)); //write the last output to child
close(p2c[1]);
close(c2p[1]);
memset(buf,0,4096);
if(read(c2p[0], buf, 4096) > 0){ //read output from child
if(i == ncmds -1 ){
printf("result:\n");
printf("%s\n", buf);
}
}
}
}