1

I'm writing a small shell in C as an exercis to learn about linux and C. Now I can execute custom commands and the exit command, but I can't execute a builtin CD command since I don't know how to split it in two part (the cd command and the name of the directory to CD to).

The desired functionality is that my program should accept the cd command with a parameter that is the directory. I can do it with command-line arguments but I don't know how to do it in its current form. How can it be done?

#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

#define BUFFER_LEN 1024
#define BUFFERSIZE 1024


int mystrcmp(char const *, char const *);


void err_syserr(char *fmt, ...)
{
    int errnum = errno;
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    if (errnum != 0)
        fprintf(stderr, "(%d: %s)\n", errnum, strerror(errnum));
    exit(EXIT_FAILURE);
}
int main() {
    char line[BUFFER_LEN];  
    char* argv[100];        
    char* path= "/bin/";    
    char progpath[20];      
    int argc;               
    size_t length;
    char *token;
    int i=0;
    int pid;
    while(1) {
    i = 0;
        printf("miniShell>> ");                    

        if(!fgets(line, BUFFER_LEN, stdin)) { 
            break;                                
        }
        length = strlen(line);
        if (line[length - 1] == '\n') {
            line[length - 1] = '\0';
        }
        if(strcmp(line, "exit")==0) {           
            break;
        }
    if(strcmp(line, "cd")==0) {           
            /*printf("change directory to %s\n", argv[2]);
            chdir(argv[2]);*/
        }

        token = strtok(line," ");

        while(token!=NULL) {
            argv[i]=token;
            token = strtok(NULL," ");
            i++;
        }
        argv[i]=NULL;                     

        argc=i;                           
        for(i=0; i<argc; i++) {
            printf("%s\n", argv[i]);      
        }
        strcpy(progpath, path);           
        strcat(progpath, argv[0]);            

        for(i=0; i<strlen(progpath); i++) {   
            if(progpath[i]=='\n') {
                progpath[i]='\0';
            }
        }
        pid= fork();              

        if(pid==0) {              
            execvp(progpath,argv);
            fprintf(stderr, "Child process could not do execvp\n");

        } else {                  
            wait(NULL);
            printf("Child exited\n");
        }

    }
return (0);
}

int mystrcmp(char const *p, char const *q)
{
    int i = 0;
    for(i = 0; q[i]; i++)
    {
        if(p[i] != q[i])
            return -1;
    }
    return 0;
}

int cd(char *pth) {
    char path[BUFFERSIZE];
    char cwd[BUFFERSIZE];
    char * return_value;
    int other_return;
    strcpy(path,pth);

    if(pth[0] != '/')
    {  
        return_value = getcwd(cwd,sizeof(cwd));
        strcat(cwd,"/");
        strcat(cwd,path);
        other_return = chdir(cwd);
    } else { 
        other_return = chdir(pth);
    }
    printf("Spawned foreground process: %d\n", getpid());
    return 0;
}
Niklas Rosencrantz
  • 25,640
  • 75
  • 229
  • 424

2 Answers2

2

Use strpbrk or strsep to split your input into white-space separated tokens, then use strcmp on the first one and use the remaining ones as arguments.

This answer to a related question has an example, and here are some notes on portability.

Community
  • 1
  • 1
Phillip
  • 13,448
  • 29
  • 41
0

I'd suggest to parse your argument with the getopt function from unistd library. It's covered in this question too.

Here is the documentation for getopt command.

Community
  • 1
  • 1
Eenoku
  • 2,741
  • 4
  • 32
  • 64