LinuxQuestions.org
Help answer threads with 0 replies.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 07-31-2015, 02:09 AM   #1
Kslkgh
LQ Newbie
 
Registered: Jul 2015
Location: The computer
Distribution: Debian, Kali Linux, Linux Mint, BackTrack, elementary OS
Posts: 26

Rep: Reputation: Disabled
How do I implement a CD builtin to a C Shell?


I have written (with the help of the community at LQ) a C Shell, named vsh. I now need to implement the CD command. I have tried various implementations, but nothing I have tried works. My code is as follows:
Code:
/**
	@file vsh.c
	
	@author George Gibson
	
	@date Wednesday 29th July 2015
	
	@brief vsh Shell Version 1.0 BETA
*/

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

#define LINESIZE 1024
#define RL_BUFSIZE 1024
#define TOK_BUFSIZE 64
#define TOK_DELIM " \t\r\n\a"

char **split_line(char *line)
{
    int bufsize = TOK_BUFSIZE, position = 0;
    char **tokens = malloc(bufsize * sizeof(char*));
    char *token, **tokens_backup;

    if (!tokens) {
        fprintf(stderr, "vsh: allocation error\n");
        exit(EXIT_FAILURE);
    }
		
    token = strtok(line, TOK_DELIM);
    while (token != NULL) {
        tokens[position] = token;
        position++;
	
        if (position >= bufsize) {
            bufsize += TOK_BUFSIZE;
            tokens_backup = tokens;
            tokens = realloc(tokens, bufsize * sizeof(char*));
            if (!tokens) {
		        free(tokens_backup);
                fprintf(stderr, "vsh: allocation error\n");
                exit(EXIT_FAILURE);
            }
        }
	
        token = strtok(NULL, TOK_DELIM);
    }
    tokens[position] = NULL;
    
	return tokens;
}

int main(int argc, char **argv)
{
	int finish = 0;
	char *user = getenv("USER");
	char hostname[1024];
	char *pwd = getenv("PWD");
    char line[LINESIZE] = {0};
    char lineCopy[LINESIZE] = {0};
    char *command = NULL;
    char **args;
    
    // Print out a welcome message
    printf("Welcome to vsh\n");
	
	// Print out the message of the day
    system("/bin/cat /etc/motd");
    
    printf("\n");
	
	gethostname(hostname, 1024);
	
    while (!finish)
    {
		// Update 'pwd' variable
		pwd = getenv("PWD");
		// Print out prompt
		printf("[");
        printf(user);
        printf("@");
        printf(hostname);
        printf("] ");
        printf(pwd);
        printf(" $ ");
        fflush(stdout);
        
        if(NULL == fgets(line, sizeof line, stdin))
        {
			// If NULL, leave vsh
            finish = 1;
            printf("\nLeaving vsh\n");
        }
        else
        {
			// If there is something there...
            printf("The command read was s", line);
            printf("\n");
            char *newLine = strchr(line, '\n');
            
            if(newLine != NULL)
            {
                *newLine = '\0';
                strcpy(lineCopy, line);
            }
            
            command = strchr(line, ' ');
            
            if(command != NULL)
            {
                *command++ = '\0';
                printf("Command= _%s_\n\n", line);                
            }
            
            args = split_line(line);
            
            if(strcmp(line, "") == 0) {
				fprintf(stderr, "vsh: Expected command\n");
			}
            else if(strcmp(line, "cd") == 0)
            {
				printf("cd not available in BETA versions of vsh");
			}
            else if(strcmp(line,"programmer") == 0)
            {
                printf("The programmer of vsh is George Gibson\n");
            }
            else if(strcmp(line,"ver") == 0)
            {
                printf("The current version is 1.0\n");
            }
            else if(strcmp(line, "help") == 0)
            {
				printf("Help for vsh\n\nType a command to run it. The builtin commands are : cd, programmer, ver, help and exit.Their functions are as follows:\n\ncd: Change Directory. Changes the current working directory.\n\nprogrammer: Display the programmers of vsh.\n\nver: Display the version of vsh you are running.\n\nhelp: Launches this program.\n\nexit: Leave vsh Shell.\n\nThese are the only builtins in vsh, but note that if you define a command in /bin with one of these names, your program will not run in vsh unless you use it's explicit name (/bin/yourprogram) rather than \"yourprogram\". vsh 1.0 written and programmed by George Gibson.\n");
			}
            else if(strcmp(line,"exit") == 0)
			{
				finish = 1;
				printf("\nLeaving vsh...\n");
				getchar();
			}
            else
            {
				// Run the command
                pid_t pid;
				int err;

				pid=fork();
				
				if(pid == -1) {
					perror("vsh");
				}
				else if(pid == 0) {
					execvp(args[0], args);
				    perror("vsh");
				}
				else {
					waitpid(pid, &err, 0);
				}
            }
        }
    }
    
    return 0;
}

Last edited by Kslkgh; 08-02-2015 at 02:59 AM.
 
Old 07-31-2015, 02:56 AM   #2
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Have you tried calling chdir()?
 
1 members found this post helpful.
Old 07-31-2015, 03:29 AM   #3
Kslkgh
LQ Newbie
 
Registered: Jul 2015
Location: The computer
Distribution: Debian, Kali Linux, Linux Mint, BackTrack, elementary OS
Posts: 26

Original Poster
Rep: Reputation: Disabled
Yes, but it never works properly.
 
Old 07-31-2015, 03:42 AM   #4
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by Kslkgh View Post
Yes, but it never works properly.
"never works properly" or other variations of "it doesn't work" are not descriptive enough for anyone to be able to help you.
 
2 members found this post helpful.
Old 07-31-2015, 06:10 AM   #5
Kslkgh
LQ Newbie
 
Registered: Jul 2015
Location: The computer
Distribution: Debian, Kali Linux, Linux Mint, BackTrack, elementary OS
Posts: 26

Original Poster
Rep: Reputation: Disabled
I call it in the following manner:
Code:
directory = args[1];
chdir(directory);
It compiles fine, but nothing happens when I run the cd command with or without an input. It reads the command, but does not change the working directory.
 
Old 07-31-2015, 06:19 AM   #6
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
That's still not really enough context, but I guess that you either you misparsed args[1] and ignored the error returned by chdir, or you called chdir in a subprocess (i.e. after forking); chdir only affects the current process.
 
1 members found this post helpful.
Old 07-31-2015, 06:33 AM   #7
Kslkgh
LQ Newbie
 
Registered: Jul 2015
Location: The computer
Distribution: Debian, Kali Linux, Linux Mint, BackTrack, elementary OS
Posts: 26

Original Poster
Rep: Reputation: Disabled
If there is not enough to go on, here is my complete code:
Code:
/**
	@file vsh.c
	
	@author George Gibson
	
	@date Wednesday 29th July 2015
	
	@brief vsh Shell Version 1.0 BETA
*/

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

#define LINESIZE 1024
#define RL_BUFSIZE 1024
#define TOK_BUFSIZE 64
#define TOK_DELIM " \t\r\n\a"

char **split_line(char *line)
{
    int bufsize = TOK_BUFSIZE, position = 0;
    char **tokens = malloc(bufsize * sizeof(char*));
    char *token, **tokens_backup;

    if (!tokens) {
        fprintf(stderr, "vsh: allocation error\n");
        exit(EXIT_FAILURE);
    }
		
    token = strtok(line, TOK_DELIM);
    while (token != NULL) {
        tokens[position] = token;
        position++;
	
        if (position >= bufsize) {
            bufsize += TOK_BUFSIZE;
            tokens_backup = tokens;
            tokens = realloc(tokens, bufsize * sizeof(char*));
            if (!tokens) {
		        free(tokens_backup);
                fprintf(stderr, "vsh: allocation error\n");
                exit(EXIT_FAILURE);
            }
        }
	
        token = strtok(NULL, TOK_DELIM);
    }
    tokens[position] = NULL;
    
	return tokens;
}

int main(int argc, char **argv)
{
	int finish = 0;
	int errno;
	char *user = getenv("USER");
	char hostname[1024];
	char *pwd = getenv("PWD");
    char line[LINESIZE] = {0};
    char lineCopy[LINESIZE] = {0};
    char *command = NULL;
    char **args;
    char *directory;
    
    // Print out a welcome message
    printf("Welcome to vsh\n");
	
	// Print out the message of the day
    system("/bin/cat /etc/motd");
    
    printf("\n");
	
	gethostname(hostname, 1024);
	
    while (!finish)
    {
		// Update 'pwd' variable
		pwd = getenv("PWD");
		// Print out prompt
		printf("[");
        printf(user);
        printf("@");
        printf(hostname);
        printf("] ");
        printf(pwd);
        printf(" $ ");
        fflush(stdout);
        
        if(NULL == fgets(line, sizeof line, stdin))
        {
			// If NULL, leave vsh
            finish = 1;
            printf("\nLeaving vsh\n");
        }
        else
        {
			// If there is something there...
            printf("The command read was s", line);
            printf("\n");
            char *newLine = strchr(line, '\n');
            
            if(newLine != NULL)
            {
                *newLine = '\0';
                strcpy(lineCopy, line);
            }
            
            command = strchr(line, ' ');
            
            if(command != NULL)
            {
                *command++ = '\0';
                printf("Command= _%s_\n\n", line);                
            }
            
            args = split_line(line);
            
            if(strcmp(line, "") == 0) {
				fprintf(stderr, "vsh: Expected command\n");
			}
            else if(strcmp(line, "cd") == 0)
            {
				directory = args[1];
				chdir(directory);
				if(chdir(directory) == -1)
				{
					fprintf(stderr, "vsh: Error changing directory\n");
				}
			}
            else if(strcmp(line,"programmer") == 0)
            {
                printf("The programmer of vsh is George Gibson\n");
            }
            else if(strcmp(line,"ver") == 0)
            {
                printf("The current version is 1.0\n");
            }
            else if(strcmp(line, "help") == 0)
            {
				printf("Help for vsh\n\nType a command to run it. The builtin commands are : cd, programmer, ver, help and exit.Their functions are as follows:\n\ncd: Change Directory. Changes the current working directory.\n\nprogrammer: Display the programmers of vsh.\n\nver: Display the version of vsh you are running.\n\nhelp: Launches this program.\n\nexit: Leave vsh Shell.\n\nThese are the only builtins in vsh, but note that if you define a command in /bin with one of these names, your program will not run in vsh unless you use it's explicit name (/bin/yourprogram) rather than \"yourprogram\". vsh 1.0 written and programmed by George Gibson.\n");
			}
            else if(strcmp(line,"exit") == 0)
			{
				finish = 1;
				printf("\nLeaving vsh...\n");
				getchar();
			}
            else
            {
				// Run the command
                pid_t pid;
				int err;

				pid=fork();
				
				if(pid == -1) {
					perror("vsh");
				}
				else if(pid == 0) {
					execvp(args[0], args);
				    perror("vsh");
				}
				else {
					waitpid(pid, &err, 0);
				}
            }
        }
    }
    
    return 0;
}
There appears to be an error, as I get "vsh: Error changing directory" when I try to run cd, even with no arguments.
 
Old 07-31-2015, 06:39 AM   #8
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
There appears to be an error, as I get "vsh: Error changing directory" when I try to run cd, even with no arguments.
I suggest adding a perror("cd") to see exactly what the error is. Examining the value of args[1] using a debugger could also provide some insight.

Last edited by ntubski; 07-31-2015 at 06:49 AM. Reason: missed words
 
Old 07-31-2015, 06:47 AM   #9
Kslkgh
LQ Newbie
 
Registered: Jul 2015
Location: The computer
Distribution: Debian, Kali Linux, Linux Mint, BackTrack, elementary OS
Posts: 26

Original Poster
Rep: Reputation: Disabled
OK, taken your advice and added a perror("cd"), now I get the error 'cd: Bad address'. I've had this error before, but that was being executing in a different manner, and thus won't work here. If I try to do args[0], I get 'cd: No such file or directory'.
 
Old 07-31-2015, 06:47 AM   #10
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
Never ever ignore return values and error codes, ok?

Code:
rc= chdir (directory);
if (rc) {
    int ern= errno;

    fprintf (stderr, "*** Error in chdir('%s') errno=%d: %s\n",
        directory, ern, strerror (ern));
    }
}
 
Old 07-31-2015, 07:18 AM   #11
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,780

Rep: Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081Reputation: 2081
Quote:
Originally Posted by Kslkgh View Post
OK, taken your advice and added a perror("cd"), now I get the error 'cd: Bad address'.
Ok, so that tells you args[1] is bad in some way. Try looking at it in the debugger.
 
1 members found this post helpful.
Old 07-31-2015, 07:45 AM   #12
Kslkgh
LQ Newbie
 
Registered: Jul 2015
Location: The computer
Distribution: Debian, Kali Linux, Linux Mint, BackTrack, elementary OS
Posts: 26

Original Poster
Rep: Reputation: Disabled
The variable errno is set to 0 and ern is set to "Success", but the directory doesn't change.
 
1 members found this post helpful.
Old 07-31-2015, 07:58 AM   #13
genss
Member
 
Registered: Nov 2013
Posts: 741

Rep: Reputation: Disabled
use strace
it will help you a lot

also (unrelated to this) see termios, notably setting the terminal in to non-canonical mode
https://en.wikibooks.org/wiki/Serial...amming/termios
 
Old 07-31-2015, 08:29 AM   #14
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
Quote:
Originally Posted by Kslkgh View Post
The variable errno is set to 0 and ern is set to "Success", but the directory doesn't change.
Exactly how do you know that?
 
Old 07-31-2015, 09:40 AM   #15
Kslkgh
LQ Newbie
 
Registered: Jul 2015
Location: The computer
Distribution: Debian, Kali Linux, Linux Mint, BackTrack, elementary OS
Posts: 26

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by NevemTeve View Post
Exactly how do you know that?
The debugger (and the fprintf() in your earlier post).
 
  


Reply

Tags
shell



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
builtin: not found. when running shell file. Ewais Linux - Software 1 08-04-2013 11:33 AM
Creating a shell using C which could Implement LS command imrrann Linux - Newbie 7 09-07-2010 01:26 AM
Implement a Unix Shell with History Feature vipin_jss Linux - Newbie 2 05-07-2009 07:38 PM
how to implement suspended job handling of a shell using c chrislam Programming 1 09-19-2007 11:43 AM
Shell implement in c SatYr_84 Programming 8 10-06-2005 12:44 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 07:39 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration