#include #include #include #include #include #include #include #include #include #include #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.