Question

Making a simple -type shell, using fork and execvp functions to run the commands from the stdin line.

However, things like ls work, but not ls -all -S. It will execute ls, but nothing will be printed for ls -all

The only idea I can come up with is that there is a "\n" somewhere in the command, but I don't know how to get it out or even where it is....

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/wait.h>
//Libs ^^^^ Defs vvvvvvvv
#define comlen 4096                     //Max command length
#define comarg 32             //Max argument length

int main(int argc, char *argv[]) 
{
  char buff; //command buffer
    char* comand[comlen];
    int i;
  do
  {
        i = 0;
    printf("simsh: ");

        char* whtspc = strtok (fgets(&buff, comlen, stdin)," ");  //get input and tokenize
        printf("[%lu]   ::   %s------------\nEND OF BUFF TEST\n", strlen(&buff), &buff);

    while (whtspc != NULL)
    {
          comand[i]=(char*)malloc((sizeof(char)*strlen(whtspc))); //alloctie mem for commands
          strncpy(comand[i], whtspc, strlen(whtspc)-1);                     //coppy comand token to array index i
          whtspc = strtok (NULL, " ");                                                      //grab next token
            i++;                                                                                                        //incriment
            /*trying to change new line character to NULL so that commands can be passed properly*/
//          if (comand[strlen(comand[i]) - 1] == "\n") 
//          {
//              comand[strlen(comand[i]) - 1] = '\0';
//          }
            //breka out incase index oversteps
            if (i == 4096)
                break;
    }
        //last entry in command should be null
        comand[i] = NULL;
        //fork to run in background
        pid_t pid = fork();

        if (pid == 0)
        {
            //testing and pass comands to execvp
            printf("START OF COMAND TEST\n!!!!!!!!!%s!!!!!!!!!!!!!!!!\n %lu\nEND OF COMAND TEST\n\n",comand[1], strlen(comand[0]));
            execvp(comand[0], &comand);
        }

        else
        {
            //parent wait on child.
            waitpid(pid, &i, WUNTRACED | WCONTINUED);
        }
    }
    while(1);

  return 0;
}

Any help would be welcomed.

If it helps at all , here is the terminal output of the code::

simsh: ls
[3]   ::   ls
------------
END OF BUFF TEST
START OF COMAND TEST
!!!!!!!!!(null)!!!!!!!!!!!!!!!!
 2
END OF COMAND TEST

chop_line.c  chop_line.h  list.c  list.h  Makefile  Makefile~  One  simsh1  simsh1.c  simsh1.c~
simsh: ls -all
[2]   ::   ls------------
END OF BUFF TEST
START OF COMAND TEST
!!!!!!!!!-all!!!!!!!!!!!!!!!!
 1
END OF COMAND TEST

simsh: echo
[5]   ::   echo
------------
END OF BUFF TEST
START OF COMAND TEST
!!!!!!!!!(null)!!!!!!!!!!!!!!!!
 4
END OF COMAND TEST


simsh: echo all
[4]   ::   echo------------
END OF BUFF TEST
START OF COMAND TEST
!!!!!!!!!all!!!!!!!!!!!!!!!!
 3
END OF COMAND TEST

simsh: echo echo
[4]   ::   echo------------
END OF BUFF TEST
START OF COMAND TEST
!!!!!!!!!echo!!!!!!!!!!!!!!!!
 3
END OF COMAND TEST
Was it helpful?

Solution 2

First of all, your fgets is reading to a single character buff. You should read into a buffer of characters. Second, fgets keeps the newline at the end of the read string, so you may want to remove it first, e.g.:

char buff[4096];
if (!fgets(buff, sizeof(buff), stdin)) {
    // error or EOF
    return 1;
}
int len = strlen(buff);
if (len > 0 && buff[len-1] == '\n') {
    buff[--len] = '\0';
}
char *whtspc = strtok(buff, " ");

You must also replace all references to &buff with buff.

In addition to this, your malloc is also wrong, and allocates one character less than is required (strlen is without the terminating NUL):

if (!(comand[i] = malloc(strlen(whtspc)+1))) {
    return 1; // out of memory
}
(void) strcpy(comand[i], whtspc);

Correspondingly your strncpy was copying one character less than required. This is what made your original code accidentally work for a single-word input because it had the effect of removing the trailing '\n' for you in that case, but in every other case it removed the last character of the word itself.

And the second argument to execvp should be just the comand (sic) array:

execvp(comand[0], comand);

OTHER TIPS

The first argument to fgets should be a pointer to a buffer where the string is copied into. You are passing a pointer to a single char.

Second, execvp expects two arguments: a filename and a null-terminated list of command-line arguments which, by convention, starts with the filename itself.

I took the liberty to make some modifications to your code, both fixing the issues I pointed above and making it a little more readable.

Note that there's a memory leak in the code below (fix it :). There might be other issues that I didn't notice.

I implemented a shell a while ago; if you want to take a look, my GitHub URL is in my profile (BEWARE: ugly college homework code).

Hope it helps!

#include <stdio.h>                                                                                      
#include <stdlib.h>                                                                                     
#include <string.h>                                                                                     
#include <unistd.h>                                                                                     
#include <time.h>
#include <sys/types.h>                                                                                  
#include <sys/wait.h>                                                                                   

#define COMLEN 4096                                                                                     
#define COMARG_N 32                                                                                     
#define TRUE 1

int main(int argc, char *argv[]) 
{                                                                                                       
    char *token;                                                                                        
    char *args[COMARG_N];                                                                               
    char *buff;                                                                                         
    int i;                                                                                              
    pid_t pid;                                                                                          

    while(TRUE) {                                                                                       
        printf("simsh: ");                                                                            

        buff = (char*) malloc(sizeof(char) * COMLEN);                                                 
        fgets(buff, COMLEN, stdin);                                                                   

        if (buff[strlen(buff) - 1] == '\n')                                                           
            buff[strlen(buff) - 1] = '\0';                                                            

        i = 0;                                                                                        
        token = strtok (buff, " ");                                                                   

        while (token != NULL && i < COMARG_N - 1) {                                                   
            args[i] = token;                                                                          
            token = strtok (NULL, " ");                                                               
            i++;                                                                                      
        }                                                                                             

        args[i] = NULL;                                                                               

        pid = fork();                                                                                 
        if (pid == 0)                                                                                 
            execvp(args[0], &args[0]);                                                                
        else                                                                                          
            waitpid(pid, &i, WUNTRACED | WCONTINUED);                                                 

        free(buff);                                                                                   
    }                                                                                                 

    return 0;                                                                                             
}   
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top