#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <stddef.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#define MAX_PATH 2048// Maximal full path length we support
#define MAX_COMMANDS 8
#define MAX_COMMAND_LENGTH 48
int main (int argc, char **argv) {
int i = 0;
int j = 0;
int k = 0; //test only
int fork_num = 0;
int status;
char file_name[MAX_PATH];
char file_path[MAX_PATH + 1];
FILE* cmd_file;
struct stat file_stat;
char *cmd_hldr;//[MAX_COMMAND_LENGTH];
char *cmd_ary[MAX_COMMANDS]; //add another dimension here for each arg
char *delimiter = " ";
int pidarray[MAX_COMMANDS];
int statusarray[MAX_COMMANDS];
pid_t childpid;
char * forkcommand[MAX_COMMAND_LENGTH];
int totalpipeid[16];//Stores the ids of the pipes
//check if there is enough arguements (a filename and nothing more)
if (argc != 2) {
fprintf(stderr, "invalid number of arguments, please supply a filename\n");
perror("Error");
exit(1);
}
strcpy(file_name, argv[1]);
strcpy(file_path, "./");
strcat(file_path, file_name);
// obtain file status
if (stat(file_path, &file_stat) == -1) {
// error getting stat
fprintf(stderr, "%s cannot be read properly (cannot get stat)\n", file_name);
perror ("Error");
exit(1);
}
//check if the filename names a regular file
if(S_ISREG(file_stat.st_mode)) {
//printf("'%s' is regular file at '%s'\n", file_name, file_path);
cmd_file = fopen(file_path, "r");
//make sure file opens ok
if (!cmd_file) {
fprintf(stderr, "Failed opening file %s for reading \n", file_path);
perror ("Error");
exit(1);
}
cmd_hldr = malloc(MAX_COMMAND_LENGTH);
//loop to read each command from the file, into cmd_ary
while((fgets(cmd_hldr, MAX_COMMAND_LENGTH, cmd_file)) != NULL) {
if(fork_num > 7) {
fprintf(stderr, "File contains too many commands, will only perform the first %d\n", MAX_COMMANDS);
perror ("Error:");
break;
}
cmd_ary[fork_num] = malloc(strlen(cmd_hldr) + 1);
strcpy(cmd_ary[fork_num], cmd_hldr);
//printf("command number %d is %s\n", fork_num, cmd_ary[fork_num]);
fork_num++;
}
if (fclose(cmd_file) == -1) {
fprintf(stderr, "unable to close [%s]\n", file_path);
perror("Error");
exit(1);
}
}
//file named by filename is not a regular file, quit
else {
fprintf(stderr, "%s is not a regular file\n", file_name);
perror("Error");
exit(1);
}
/*************************************
* file is open now, next read
* commands one by one, forking them
* to seperate processes
************************************/
//Gets rid of any \n in the argument array
for (i = 0; i < fork_num-1; i++){
char * command = cmd_ary[i];
int length = strlen(command);
cmd_ary[i] = strndup(command,length-1);
printf("Without the ENDL on end = %s\n", cmd_ary[i]);
}
//In case there is only a single command
if (fork_num == 1) {
int j = 1;
//Store the program name for execution
cmd_hldr = strtok(cmd_ary[0], delimiter);
forkcommand[0] = cmd_hldr;
//Store the arguments for the program
while (( cmd_hldr = strtok(NULL, delimiter)) != NULL) {
forkcommand[j]=cmd_hldr;
j++;
}
//Execute the single command
childpid = fork();
if (childpid == 0) {
if (execvp(forkcommand[0],forkcommand)==-1) {
perror("Exec failed");
}
perror("I could not call exec for some reason");
return 0;
}
//Check the wait status
waitpid(childpid,&status,0);
if (WIFEXITED(status) != 1) {
perror("Failure to Exit safely");
}
printf("The command [%s] of pid[%d] had a status of [%d]\n", forkcommand[0], childpid, status);
return 1;
}
//Build up an array of pipeids
typedef int* my_type;
my_type p[fork_num];
//DO NOT HAVE A HEART ATTACK AT THIS!
int pipe1[2],pipe2[2],pipe3[2],pipe4[2], pipe5[2], pipe6[2], pipe7[2], pipe8[2];
p[0]=pipe1;
p[1]=pipe2;
p[2]=pipe3;
p[3]=pipe4;
p[4]=pipe5;
p[5]=pipe6;
p[6]=pipe7;
p[7]=pipe8;
int t;
//Connect the pipes
for (t = 0; t < fork_num; t++) {
if (pipe(p[t])==-1){
perror("Failure to pipe");
}
}
//Iterate over all the commands
for(i = 0; i < fork_num; i++) {
//fprintf(stderr,"executing command number %d which is %s\n", i, cmd_ary[i]);
int j = 1;
char * cmd_to_fork[MAX_COMMAND_LENGTH];
//Store the program name for execution
char * cmd = strtok(cmd_ary[i], delimiter);
cmd_to_fork[0] = malloc(strlen(cmd));
strcpy(cmd_to_fork[0],cmd);
//Store the arguments for the program
while (( cmd = strtok(NULL, delimiter)) != NULL) {
cmd_to_fork[j] = malloc(strlen(cmd));
strcpy(cmd_to_fork[j],cmd);
//fprintf(stderr,"Arg %d of command [%s] is [%s] MAIN\n", j, cmd_to_fork[j], cmd_to_fork[j]);
j++;
}
//If the array has leftover arguments, NULLify them
if (cmd_to_fork[j] != NULL) {
cmd_to_fork[j] = NULL;
}
/*
j = 0;
fprintf(stderr,"-----------Command [%s]------------ \n", cmd_to_fork[0]);
while (cmd_to_fork[j] != NULL) {
fprintf(stderr,"At location [%d] the value is [%s]\n", j, cmd_to_fork[j]);
j++;
}
*/
//Initial Case
if (i == 0) {
//fprintf(stderr,"Initial case i = %d and command = [%s]\n", i,program_name );
childpid = fork();
if (childpid ==0 ){
if (dup2(p[i][1],1) == -1) {
perror("Failed at initial redirect");
}
else if (close(p[i][1]) == -1) {
perror("Failed to close pipe");
}
else {
if (execvp(cmd_to_fork[0],cmd_to_fork) == -1) {
perror("Failure calling initial executable");
}
}
return 0;
}
pidarray[i] = childpid;
waitpid(childpid,&status,0);
if (WIFEXITED(status) != 1) {
perror("child exit error");
}
statusarray[i]=status;
close(p[i][1]);
}
//Middle Case
else if (i < (fork_num-1)) {//i is NOT the last command
//fprintf(stderr,"Middle case i = %d and command = [%s]\n", i,program_name );
childpid = fork();
if (childpid == 0 ) {
if ((dup2(p[i-1][0], 0) == -1 ) || (dup2(p[i][1],1)==-1))
perror("Failed to redirect STDIN");
else if ((close(p[i-1][0]) == -1) || (close(p[i][1]) == -1) ) {
perror("Failed at closing");
}
else {
if (execvp(cmd_to_fork[0],cmd_to_fork) == -1) {
perror("Failure calling Middle executable");
}
}
return 1;
}
pidarray[i] = childpid;
waitpid(childpid,&status,0);
if (WIFEXITED(status) != 1) {
perror("child exit error");
}
statusarray[i]=status;
close(p[i-1][0]);
close(p[i][1]);
}
else {
if (i == fork_num-1) {
//End Case
//fprintf(stderr,"End case i = %d and command = [%s]\n", i,program_name );
childpid = fork();
if (childpid==0) {
if (dup2(p[i-1][0] , 0) == -1) {
perror("Failed to redirect from STDIN");
}
else if (close(p[i-1][0]) == -1) {
perror("Failed at closing");
}
else {
// perror("beforeZOMG");
if (execvp(cmd_to_fork[0],cmd_to_fork) == -1) {
perror("Failure calling Final executable");
}
}
return 1;
}
pidarray[i] = childpid;
waitpid(childpid,&status,0);
if (WIFEXITED(status) != 1) {
perror("child exit error");
}
statusarray[i]=status;
close(p[i-1][0]);
// perror("ENDZOMG");
}
}
}
for (i = 0; i < fork_num; i++) {
printf("The command [%s] of pid[%d] had a status of [%d]\n", strtok(cmd_ary[i], delimiter),pidarray[i],statusarray[i]);
}
return 1;
}
//It would print the following three things: process id, command that it executed, and the exit status.