this is a piece of a shell that I'm creating. I'm having some trouble using libreadline, because when the shell gets loaded and I try to cd in a directory using autocompletion (so pressing TAB), after I press enter I access the directory but I get some strange output before another prompt is printed. I noticed that this happens only when the name of the directory starts with an upper case letter.
Example: "user:: ~ % cd Github" <-- written pressing tab to autocomplete Github
Next prompt is: "8b�/�user :: Github %"
I really cannot understand why, this is something really strange for me.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>
#include <readline/history.h>
#include <readline/readline.h>
#include "flush.h"
#include "env.h"
#include "fget.h"
char * flush_builtins[] =
{
"cd",
"help",
"exit",
"ver",
"fget"
};
int flush_num_builtins() {
return sizeof(flush_builtins) / sizeof(char *);
}
int (*flush_func[]) (char **) =
{
&flush_cd,
&help,
&exit_flush,
&ver,
&fget
};
static int flush_startp(char **args)
{
pid_t pid;
int status;
pid = fork();
if (pid == 0)
{
if (execvp(args[0], args) == -1)
{
fprintf(stderr, "flush: command not found\n");
}
exit(1);
}
else if (pid < 0)
{
fprintf(stderr, "flush: command not found\n");
}
else
{
do
{
waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
return 1;
}
static int flush_exec(char **args)
{
int i;
if (args[0] == NULL)
{
return 1;
}
for (i = 0; i < flush_num_builtins(); i++)
{
if (strcmp(args[0], flush_builtins[i]) == 0) {
return (*flush_func[i])(args);
}
}
return flush_startp(args);
}
static char * flush_read(void)
{
fflush(stdout);
char *line_read = malloc(sizeof(char) * LINE_BUF);
char *prompt = malloc(sizeof(char) * LINE_BUF);
char *current, buffer[TOK_BUF];
current = getcwd(buffer, TOK_BUF);
strcat(prompt, get_user());
strcat(prompt, " :: ");
if (strcmp(current, get_home()) == 0)
{
strcat(prompt, "~");
}
else
{
strcat(prompt, get_cwd());
}
strcat(prompt, " % ");
line_read = readline(prompt);
if (line_read && *line_read)
{
add_history(line_read);
}
return line_read;
free(prompt);
free(line_read);
free(current);
}
static char **flush_getargs(char * line)
{
int bufsize = TOK_BUF;
int i = 0;
char **tokens = malloc(bufsize * sizeof(char *));
char **token;
if (!tokens)
{
fprintf(stderr, "allocation error\n");
exit(1);
}
token = strtok(line, DELIM);
while (token != NULL)
{
tokens[i] = token;
i++;
token = strtok(NULL, DELIM);
}
tokens[i] = NULL;
return tokens;
}
static void flush_loop(void)
{
char *line;
char **args;
int status;
do
{
line = flush_read();
args = flush_getargs(line);
status = flush_exec(args);
free(line);
free(args);
} while (status);
}
static void handler(int num)
{
signal(SIGINT, handler);
flush_loop();
fflush(stdout);
}
int main()
{
init();
signal(SIGINT, handler);
flush_loop();
return 0;
}
You can not use strcat with a non \0 terminated string:
char *prompt = malloc(sizeof(char) * LINE_BUF);
char *current, buffer[TOK_BUF];
current = getcwd(buffer, TOK_BUF);
strcat(prompt, get_user());
Use strcpy instead of strcat, or calloc instead of malloc
Related
Trying make a custom shell in c that executes (among others) this command
ls -l >> text.txt
Now this used to work, but after changes in getArgs() it either loops endlessly printing success messages without creating a file, or terminates abnormally.
Here is the immediately relevant code
else if(option == 3){
directory=" ";
if(A[0]=='.' || A[0]=='/'){
directory="./";
}
getArgs(&A,args,directory,&size);
for(i=0;i<size;i++){
printf("arg[%d] : %s\n",i,args[i]);
}
directory=concat(directory,args[0]);
printf("directory %s\n",directory );
fp = open(args[3],O_RDWR | O_CREAT|O_TRUNC,S_IRWXU);
pid=fork();
if(pid==0){
com = args[0];
dup2(fp,STDOUT_FILENO);
readCommand(args,directory,com,0);
return 1;
}
waitpid(-1,&status,0);
dup2(output,STDOUT_FILENO);
if(WIFEXITED(status)){
printf("Data successfully saved in file");
}else{
printf("Abnormal termination\n");
}
close(fp);
close(output);
clean(args);
}
Here is the mylib.c file including getArgs()
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include "mylib.h"
#define MAX_SIZE 50
void getArgs(char **A,char *args[10], char *directory,int *sizeA){
int i,j,num,slash,size;
char *token,*s,*dummy;
trim(*A,&size);
*A=(char*)realloc(*A,(size) * sizeof(char*));
token = strtok (*A, " ");
num=0;
while (token != NULL)
{
args[num] = token;
token = strtok (NULL, " ");
num++;
}
s=args[0];
for(i=num;i<10;i++){
args[i]="\0";
}
if(*A[0]=='.' || *A[0]=='/'){
for(i=0;*args[i]!='\0';i++){
if(args[0][i]=='/'){
slash=i;
}
}
slash+=1;
j=0;
if(*A[0]=='.'){
memmove(args[0], (args[0])+slash, strlen(args[0]));
}
else if(*A[0]=='/'){
memmove(args[0], (args[0])+slash, strlen(args[0]));
}
}
*sizeA=num;
}
//resets args array
void clean(char *args[10]){
int i;
for(i=0;i<10;i++){
args[i] = '\0';
}
}
//reads and executes command
void readCommand(char *args[10],char *directory,char *com, int i){
if(execl(directory, args[i],args[i+1], NULL)==-1){
execl("/bin/sh", "/bin/sh", "-c", com, NULL);
perror("execlp");
}
else{
execl(directory, args[0],args[1],args[2],args[3],args[4], NULL); //max number of args=4
perror("execlp");
}
}
//concatenates 2 strings
char* concat(const char *s1, const char *s2)
{
const size_t len1 = strlen(s1);
const size_t len2 = strlen(s2);
char *result = malloc(len1 + len2 + 1);
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
return result;
}
//trims the /n from the argument
void trim(char *A,int *size) {
int i=0;
do{
*size=i;
if(A[i]=='\n'){
A[i]='\0';
}
i++;
}while(A[i]!='\n');
}
I have troubles with creating my own shell in C. Here is the code I have so far
#include "interpreter.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <syslog.h>
void readconfig(int *timeout, char *file){
FILE * fp;
char * line = NULL;
size_t len = 0;
char * token;
fp = fopen(CONFIG, "r");
if (fp == NULL)
{
*timeout = DEFAULTTIME;
}
else
{
while ((getline(&line, &len, fp)) != -1){
token = strtok(line, TOKEN);
if ((strcmp(token,TIME_PERIOD) == 0)){
*timeout = atoi(strtok(NULL, TOKEN));
}
if ((strcmp(token,HISTORY)==0)){
strcpy(file,trim_command(strtok(NULL, TOKEN)));
}
}
}
}
int waitPeriod(pid_t pid){
if(pid) {
int stat_val;
pid_t child_pid;
int time = 0;
while(time < TIME_PERIOD){
child_pid = waitpid(pid, &stat_val, WNOHANG);
if (child_pid == pid){
break;
} else if (child_pid == 0) {
time++;
sleep(1);
}
}
if (time == TIME_PERIOD){
printf("Process ended. Execution time was over. \n");
kill(pid, SIGINT);
if (kill(pid, 0) == 0){
kill(pid, SIGKILL);
}
}
if(WIFEXITED(stat_val)) {
return WEXITSTATUS(stat_val);
}
return 0;
} else {
return -1;
}
}
void splitCommand(char ** parameters, char * command, int count){
char * cm = strtok(command, " ");
int i = 0;
while (cm != NULL){
parameters[i] = malloc(strlen(cm) * sizeof(char *));
parameters[i] = cm;
i++;
cm = strtok (NULL, " ");
}
i++;
parameters[i] = NULL;
}
int getParamsCount(char command[]){
int i;
int count = 1;
int com_length = strlen(command);
for(i=0; i<com_length; i++){
if (command[i] == ' '){
count++;
}
}
return count;
}
void getHistory(FILE * history_file, char ** history_commands){
char line[MAX_INPUT];
int i = 0;
int j;
rewind(history_file);
while (fgets(line, MAX_INPUT, history_file)!= NULL){
history_commands[i] = malloc(strlen(line) * sizeof(char *));
history_commands[i] = strdup(line);
for(j=0; j<MAX_INPUT; j++){
if (history_commands[i][j] == '\n'){
history_commands[i][j] = '\0';
break;
}
}
i++;
}
}
int getNumberOfRows(FILE * history_file){
rewind(history_file);
int lines = 0;
char ch;
while(!feof(history_file)){
ch = fgetc(history_file);
if(ch == '\n'){
lines++;
}
}
return lines;
}
void printCommands(char ** history_commands, int lines){
int i = 0;
int j = 0;
for(j = i; j < lines; j++){
printf("[%d] %s\n", j, history_commands[j]);
}
}
int runCommand(pid_t pid, char * command, char ** parameters, int child){
int count = 0;
switch(pid) {
case -1 :
return -1;
case 0 :
count = getParamsCount(command);
parameters = malloc((count+1) * sizeof(char *));
splitCommand(parameters, command, count);
if (strncmp("cd", parameters[0], 2) == 0){
chdir(parameters[1]);
} else {
execvp(parameters[0], parameters[0]);
}
free(parameters);
return 0;
default :
child = waitPeriod(pid);
printf("Child status: %d\n", child);
command[0] = 0;
free(command);
return 0;
}
}
char * trim_command(char * string){
int l = strlen(string);
int i;
for (i = 0; i<l; i++){
if (string[i] == '\n'){
string[i] = '\0';
}
}
return string;
}
int main(){
char * command;
FILE * history;
char cwd[MAX_INPUT];
pid_t pid = 0;
int child = 0;
int number_of_rows = 0;
int count = 0;
char ** history_commands;
char ** parameters[10];
printf(" Safe comand line interpreter \n");
printf(" Type \"quit\" to cancel interpreter or command \n");
printf(" Type \"history\" to show full command history \n");
printf(" Type \"history number\" to execute command from history \n");
printf("________________________________________________________________________________________\n");
sleep(1);
history = fopen(HISTORY, "a+");
if (history == NULL){
printf("Could not open history file\n");
return -1;
}
while(1){
getcwd(cwd, sizeof(cwd));
printf("Command: [%d]%s : ", child, cwd);
command = malloc(MAX_INPUT * sizeof(char *));
fgets(command, MAX_INPUT, stdin);
trim_command(command);
if (strncmp(QUIT, command, 4) == 0) {
fclose(history);
return EXIT_SUCCESS;
} else if (strncmp("history", command, 7) == 0) {
number_of_rows = getNumberOfRows(history);
history_commands = malloc(number_of_rows * sizeof(char *));
getHistory(history, history_commands);
count = getParamsCount(command);
if (strcmp("history", command) == 0){
printf("HISTORY OF COMMANDS\n");
printCommands(history_commands, number_of_rows);
} else {
char * cm = strtok(command, " ");
cm = strtok(NULL, " ");
int x;
x = atoi(cm);
if (x >= number_of_rows){
printf("Command does not exist\n");
continue;
}
command = strdup(history_commands[x]);
count = getParamsCount(command);
trim_command(command);
fprintf(history, "%s\n", command);
pid = fork();
runCommand(pid, command, parameters, child);
}
} else if (command[0] != 0){
fprintf(history, "%s\n", command);
pid = fork();
runCommand(pid, command, parameters, child);
}
}
fclose(history);
return 0;
}
The problem is, it doesn't execute cd command. When I comment malloc and free lines in runCommand method, cd command starts working, but every other command without parameter is not working...
could somebody help me with this?
I am new to C programming and currently learning this into a course. I'm facing an issues while trying to practice the below history function.
I'm able to display the shell commands. However, when I type history, the past shell commands are not getting saved into the history buffer.
Can anyone help me to find where I went wrong?
Here is my code:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#define BUFSIZE 20
#define MAX_WORD_IN_LINE 20
int tokenize(char *str, char **args)
{
int i, argc = 0;
char *token;
token = strtok(str," \t\n");
for(i=0; token!=NULL;i++)
{
args[i] = token;
printf("args[%d] = %s\n", i, args[i]);
token = strtok(NULL, " \t\n");
argc++;
}
return argc;
}
void display_strings(char **p)
{
if (p == NULL) return;
while(*p != NULL){
printf("%s\n",*p);
p++;
}
}
int history(char *hist[], int current){
int i = current;
int hist_num = 1;
do {
if (hist[i]) {
printf("%4d %s\n", hist_num, hist[i]);
hist_num++;
}
i = (i + 1) % BUFSIZE;
} while (i != current);
return 0;
}
int main(void){
char *args[MAX_WORD_IN_LINE];
char buffer[BUFSIZE];
char *hist[BUFSIZE];
int i,current=0;
pid_t pid;
int argc;
for(i=0;i<BUFSIZE;i++)
hist[i]= NULL;
while(1) {
memset(args,0,MAX_WORD_IN_LINE);
printf("osh> ");
fgets(buffer, BUFSIZE, stdin);
argc = tokenize(buffer, args);
//display_strings(args);
// skip on empty command
if (argc == 0) continue;
if (strcmp(args[0],"quit") == 0) break;
else if (strcmp(args[0], "hello") == 0) printf("Hello there. How are you?\n");
else if (strcmp(args[0],"history")==0) history(hist,current);
else {
pid = fork();
if (pid == 0) {
hist[current]=strdup(args[0]);
current++;
execvp(args[0], args);
return 0;
}
You need to make a copy of the string that args[0] points to when you save it in hist. Currently, you're just assigning the pointer to the current args[0], and it will be overwritten by the next command. When you print the history, you'll just get the last command repeatedly. So use:
hist[current] = strdup(args[0]);
we are writing a program that has to mimic the Linux shell.
It is consisted of some parts. Every part does what the previous part did, plus something extra.
Part one runs single commands like ls, pwd etc. No parameters no
redirection.
Part two runs single commands plus redirection.
This is where we are stuck.. We compile myShell 2 without errors. But when we are typing any command we get the segmentation fault.
We're sorry for writing almost all out code here(myShell 1 not included), we just wanted to make sure you have everything you need to tell us where we are wrong.
functions.h
#ifndef FUNCTIONS_H
#define FUNCTIONS_H
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#define max 260
extern int argCounter(char *argLine,char *delim);
extern void myExec(char *argLine,int howMany,char *delim);
extern char **argArray(char* argLine,int howMany,char *args[],char *delim);
void myExecRedir(char **tokens,char* argLine, int howMany);
#endif
functions.c
#include "functions.h"
int argCounter(char *argLine,char *delim)
{
char *temp;
memcpy(temp,argLine,strlen(argLine));
char *pointer = strtok(temp, delim);
int counter = 0;
while (pointer != NULL)
{
counter++;
pointer = strtok(NULL, delim);
}
return counter;
}
void myExec(char *argLine,int howMany,char *delim)
{
char temp[max];
memset(temp,0,max);
char *args[howMany];
argLine[strlen(argLine)-1] = '\0';
//argArray breaks the argLine and returns an array that contains each argument
argArray(argLine,howMany,args,delim);
execvp(args[0],args);
perror("ERROR: wrong command!");
}
char **argArray(char *argLine,int howMany,char *args[],char *delim)
{
args[howMany] = NULL;
char *pointer = strtok(argLine, delim);
int counter = 0;
while (pointer != NULL)
{
args[counter]=pointer;
counter++;
pointer = strtok(NULL, delim);
}
return args;
}
void myExecRedir(char **tokens,char* argLine, int howMany)
{
char *delim3="<";
char *delim4=">";
int howManyIn= argCounter(argLine,delim3);
int howManyOut= argCounter(argLine,delim4);
if(howManyOut= howManyIn)
{
int fdin = open(tokens[1],O_RDWR);
int fdout = open(tokens[2],O_RDWR);
if(dup2(fdin,fdout) >= 0)
{
tokens[1]=NULL;
tokens[2]=NULL;
execvp(tokens[0],tokens);
}
else
{
printf("ERROR in dup2\n");
}
}
else if(howManyIn== 0) //means we only have > redirection
{
int fdout = open(tokens[1],O_RDWR);
if(dup2(2,fdout) >= 0)
{
tokens[2]=NULL;
execvp(tokens[0],tokens);
}
else
{
printf("ERROR in dup2\n");
}
}
else //means we only have redirection
{
int fdin = open(tokens[1],O_RDWR);
if(dup2(fdin,1) >= 0)
{
tokens[2]=NULL;
execvp(tokens[0],tokens);
}
else
{
printf("ERROR in dup2\n");
}
}
}
myShell2.c
#include "functions.h"
int main()
{
printf("myshell2>");
pid_t pid,waitPid;
//WE TRIED WITHOU ALLOCATING MEMORY AS WELL
char *argLine = (char *)malloc(max);
char **args = (char **)malloc(max);
char **args2 =( char **)malloc(max);
char **temp = (char **)malloc(max);
char *delim="><";
char *delim2=" ";
int i,howMany,howMany2,status;
while(fgets(argLine,max,stdin) != NULL)
{
howMany= argCounter(argLine,delim);//howMany redirections
args=argArray(argLine,howMany,args,delim);
if (howMany == 1)//means we are at myShell 1
{
howMany2= argCounter(argLine,delim2);
if(howMany2 ==1)//checking if the command has any parameters (like ls -l)
{
printf("myshell2>");
pid = fork();
if (pid < 0)
{
perror("ERROR: Fork failed.\n");
return -1;
}
else if(pid == 0)
{
myExec(args[0],howMany2,delim2);
perror("ERROR: Child should never arrive here.\n");
}
else
{
waitPid = wait(&status);
if (waitPid == -1)
{
perror("ERROR: Waitpid failed.\n");
return -1;
}
}
}
else
{
printf("ERROR: Wrong number of Arguments!\n");//can't run on myshell 2
return(0);
}
}
//means we have redirection (< or >)
for (i=0; i<howMany; i++)
{
argArray(args[i],2,args2,delim2);//args2 contains the tokens without spaces(delim2)
temp[i] = args2[0];
howMany2 = argCounter(args[i],delim2);
if(howMany2 > 1) // eg. ls -l should not run here
{
printf("ERROR: Wrong number of Arguments!\n");//myShell3 should be running this
return(0);
}
}
printf("myshell2>");
pid = fork();
if (pid < 0)
{
perror("ERROR: Fork failed.\n");
return -1;
}
else if(pid == 0)
{
myExecRedir(temp,argLine,howMany);
perror("ERROR: Child should never arrive here.\n");
}
else
{
waitPid = wait(&status);
if (waitPid == -1)
{
perror("ERROR: Waitpid failed.\n");
return -1;
}
}
}
}
Thank you in advance.
char *temp;
memcpy(temp,argLine,strlen(argLine));
char *pointer = strtok(temp, delim);
...
is wrong, you need to reserve space with malloc:
size_t len = strlen(argline);
char *temp = malloc(len + 1);
if (temp == NULL) return 0;
memcpy(temp, argLine, len);
/* NUL-terminate the string */
temp[len] = '\0';
char *pointer = strtok(temp, delim);
...
free(temp);
or you can use the non-standard function (but available on many implementations) strdup:
char *temp = strdup(argline);
if (temp == NULL) return 0;
char *pointer = strtok(temp, delim);
...
free(temp);
char **args = (char **)malloc(max);
is also wrong, if you need to reserve space for n pointers to char use:
char **args = malloc(sizeof(*args) * n); /* don't cast malloc */
or
char **args = malloc(sizeof(char *) * n);
My results for cd and history:
sgraham#myshell:/home/class/sgraham/proj1>cd .. (works fine)
sgraham#myshell:/home/class/sgraham>cd .. (not working)
sgraham#myshell:/home/class/sgraham>cd .. (not working)
cd: Too many arguments
sgraham#myshell:/home/class/sgraham>history
sgraham#myshell:/home/class/sgraham> (not printing out history)
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MAX_COMMAND_SIZE 80
#define MAX_ARGS 9
#define HIS_SIZE 100
typedef struct
{
int argument; // userCom arguments
char *arg[MAX_ARGS + 1]; // userCom arguments array
char *history[HIS_SIZE]; //history array
char *input; // hold input file
char *output; // hold output file
} Command;
int main()
{
Command userCom = {0}; //holds userCom struct
const char *whitespace = " \n\r\t\v\f"; // userCom delimiting chars
char* username = getenv("USER"); //Get user name
char* curDirect = getenv("HOME"); //get cwd
char* token[MAX_ARGS];
char* cwd;
char* buf;
char* cmd;
char buffer[MAX_COMMAND_SIZE + 1]; //hold userCom line
//char history[HIS_SIZE][MAX_ARGS +1]; //2D array for history
int tok = 0;
int new;
int i;
int limit;
int last = 0;
int hist = 0; //initialize history size to 0
long size;
struct stat buff; //holds file information
//gets current working directory and also changes buffer if necessary
size = pathconf(".", _PC_PATH_MAX);
if ((buf = (char *)malloc((size_t)size)) != NULL)
cwd = getcwd(buf, (size_t)size);
while(1){
//prints users prompt
printf("\n%s#myshell:%s>", username,cwd);
//gets string from userCom line
fgets(buffer, MAX_COMMAND_SIZE + 1, stdin);
buffer[strlen(buffer)-1] = 0 ;//set null
//set-up history function
userCom.history[last% HIS_SIZE] = cmd;
last++;
//parses tokens and looks for delimiters
token[tok] = strtok(buffer,whitespace);
while(token[tok])
{
++tok;
if(tok == MAX_ARGS)
printf("Reached MAX userCom arguments");
break;
token[tok] = strtok(NULL, whitespace);
}
i =0;
//sort tokens based on special characters
for (;i<tok;++i)
{
if(!strcmp(token[i], "<"))
{
userCom.output = token[++i];
}
else if(!strcmp(token[i], ">"))
{
userCom.input = token[++i];
}
else if (token[i][0] == '$')
{
char* toktok = getenv((const char*)&token[i][1]);
if (!toktok)
{
printf("%s: ERROR: variable.\n", token[i]);
return 0;
}
else
{
userCom.arg[userCom.argument] = toktok;
++(userCom.argument);
}
}
else
{
userCom.arg[userCom.argument] = token[i];
++(userCom.argument);
}
}
tok = 0;
userCom.arg[userCom.argument] = 0;
//handles the "cd" command
if((strcmp(userCom.arg[0],"cd") == 0))
{
if (userCom.argument > 2)
printf("cd: Too many arguments\n");
// change directories if valid target and update cwd
else if (userCom.argument == 1)
{
new = chdir(cwd);
if (new != 0)
printf("%s: No such file or directory\n");
// if no argument is given, new directory should be $HOME
else
{
new = chdir(curDirect);
// get the new current working directory
size = pathconf(".", _PC_PATH_MAX);
if ((buf = (char *)malloc((size_t)size)) != NULL)
cwd = getcwd(buf, (size_t)size);
}
}
}//end "cd" function
//handles the echo command
else if(strcmp(userCom.arg[0], "echo") == 0)
{
int p;
for(p=1;p < userCom.argument; ++p)
printf("%s ", userCom.arg[p]);
}//ends echo function
//handles exit
else if(strcmp(userCom.arg[0], "exit") == 0)
{
exit(0);
}
//handles history functions
else if(strcmp(userCom.arg[0], "history") == 0)
{
int j;
for(j = last, limit = 0; userCom.history[j] != NULL && limit != HIS_SIZE ; j = (j -1)% HIS_SIZE, limit++)
printf(" %s ",userCom.history[j]);
}
else {
break;
}
}//end while 1 loop
return 0;
}//End int main
while(token[tok])
{
++tok;
if(tok == MAX_ARGS)
printf("Reached MAX userCom arguments");
break;
token[tok] = strtok(NULL, whitespace);
}
This loop breaks at the first time. Probably the if should be like
if(tok == MAX_ARGS) {
printf("Reached MAX userCom arguments");
break;
}
Also userCom.argument is never set back to zero, which causes the cd .. to work first time.