LinuxQuestions.org
Review your favorite Linux distribution.
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 04-14-2014, 10:13 PM   #1
23nigam
LQ Newbie
 
Registered: Apr 2014
Posts: 4

Rep: Reputation: Disabled
trying to create a shell without using system or execvp


I want to create a basic shell which will support a few general commands like cd,ls,date,pwd.

I do not want to use system or execvp but rather understand how these commands run.

I dont know where to start
 
Old 04-14-2014, 11:22 PM   #2
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
As a start, read this: http://man7.org/linux/man-pages/man2/chdir.2.html
 
Old 04-15-2014, 12:37 AM   #3
prushik
Member
 
Registered: Mar 2009
Location: Pennsylvania
Distribution: gentoo
Posts: 372

Rep: Reputation: 29
Quote:
Originally Posted by 23nigam View Post
I want to create a basic shell which will support a few general commands like cd,ls,date,pwd.

I do not want to use system or execvp but rather understand how these commands run.

I dont know where to start
Usually, most "commands" are not part of the shell at all. Usually they are programs that the shell runs, part of something like GNU coreutils or busybox. However, some commands may be shell built-in commands. cd and ls are likely to be built-in. ch is easy, as NevemTeve already mentioned, chdir() does this. ls is a little more complex, but you will probably want to look at dirent.h.
For simple implementations of these programs, you can look at the busybox source or suckless sbase source (http://tools.suckless.org/sbase), which both contain very simple and easy to read implementations. You could also look at GNU coreutils source, but I'm sure that is a huge mess and isn't worth your time.

As for date, that just interprets the unix timestamp, should be easy enough. My understanding is that pwd just reads the environment variable PWD. echo $PWD does the same as pwd. You can read environment variables with getenv().
 
Old 04-15-2014, 06:06 PM   #4
23nigam
LQ Newbie
 
Registered: Apr 2014
Posts: 4

Original Poster
Rep: Reputation: Disabled
i made implementations for ls.cd is giving me seg fault i dont know why

DIR *d;
string dir_name;

void cd(string new_dir_name)
{
struct stat st = {0};

string temp_dir_name = dir_name + new_dir_name + "/";
printf("\nchecking this dir%s\n",temp_dir_name.c_str());
if((stat(temp_dir_name.c_str(), &st) < 0)) {
printf("%s Directory does not exist in %s\n",temp_dir_name.c_str(),dir_name.c_str());
}
else
{
closedir(d);
d = opendir(temp_dir_name.c_str());
printf("Directory changed from %s to %s\n",dir_name.c_str(),temp_dir_name.c_str());
dir_name = temp_dir_name;
}
}

int main(void)
{
dir_name = "/";
cd("etc"); //works
cd("fonts"); //segmentation fault
return(0);
}
 
Old 04-15-2014, 06:47 PM   #5
prushik
Member
 
Registered: Mar 2009
Location: Pennsylvania
Distribution: gentoo
Posts: 372

Rep: Reputation: 29
Quote:
Originally Posted by 23nigam View Post
i made implementations for ls.cd is giving me seg fault i dont know why

DIR *d;
string dir_name;

Code:
void cd(string new_dir_name)
{
	struct stat st = {0};
	
	string temp_dir_name = dir_name + new_dir_name + "/";
	printf("\nchecking this dir%s\n",temp_dir_name.c_str());
	if((stat(temp_dir_name.c_str(), &st) < 0)) {
		printf("%s Directory does not exist in %s\n",temp_dir_name.c_str(),dir_name.c_str());
	}
	else
	{
		closedir(d);
		d = opendir(temp_dir_name.c_str());
		printf("Directory changed from %s to %s\n",dir_name.c_str(),temp_dir_name.c_str());
		dir_name = temp_dir_name;
	}
}
int main(void)
{
dir_name = "/";
cd("etc"); //works
cd("fonts"); //segmentation fault
return(0);
}
I'm not sure, but 1 thing I can say is that C++ strings suck. How can you tell where memory gets allocated? and what exactly does + do? In C that would be the cause of the segfault there.
However, one thing I can see is that you are never actually changing directories, just checking it with stat. Then if stat fails you call closedir? why? you never opened it, that might be your segfault there since you never changed direcories to /etc so /fonts will fail, then you close it before you open it.

You need chdir() to change directories.

Also, use code tags for code, it makes it a lot easier to read.
 
Old 04-15-2014, 09:03 PM   #6
23nigam
LQ Newbie
 
Registered: Apr 2014
Posts: 4

Original Poster
Rep: Reputation: Disabled
Quote:
I'm not sure, but 1 thing I can say is that C++ strings suck. How can you tell where memory gets allocated? and what exactly does + do? In C that would be the cause of the segfault there.
However, one thing I can see is that you are never actually changing directories, just checking it with stat. Then if stat fails you call closedir? why? you never opened it, that might be your segfault there since you never changed direcories to /etc so /fonts will fail, then you close it before you open it.

You need chdir() to change directories.

Also, use code tags for code, it makes it a lot easier to read.
DIR *d;
string dir_name;

void cd(string new_dir_name)
{
struct stat st = {0};

string temp_dir_name = dir_name + new_dir_name + "/";
printf("\nchecking this dir%s\n",temp_dir_name.c_str());
if((stat(temp_dir_name.c_str(), &st) < 0)) {
printf("%s Directory does not exist in %s\n",temp_dir_name.c_str(),dir_name.c_str());
}
else
{
closedir(d);
d = opendir(temp_dir_name.c_str());
printf("Directory changed from %s to %s\n",dir_name.c_str(),temp_dir_name.c_str());
dir_name = temp_dir_name;
}
}

int main(void)
{
dir_name = "/";
d = opendir(dir_name);
cd("etc"); //works
cd("fonts"); //segmentation fault
return(0);
}
 
Old 04-15-2014, 10:08 PM   #7
prushik
Member
 
Registered: Mar 2009
Location: Pennsylvania
Distribution: gentoo
Posts: 372

Rep: Reputation: 29
in posts, use code tags.

Your added call to opendir() isn't right. You need a character array (a "c string"), not a silly C++ string. Second, your function still closes d before it knows for sure that its opened, you tried to fix it in this case, but its poor coding style and very hard to read.

Third, and most importantly, opendir() still isn't going to do what you think it does. You need chdir() if you want to change directories. opendir will open the directory and you will be able to read it's contents, but your next call will not be relative to the new directory.

add .c_str() to your string in the function call from main and you will fix the segfault. However, your code will still not do what you want. and your function will still segfault every time there is an error or when called without opening a directory first. fix that and then change your opendir() calls to chdir() calls and it will work.
 
Old 04-16-2014, 12:09 PM   #8
23nigam
LQ Newbie
 
Registered: Apr 2014
Posts: 4

Original Poster
Rep: Reputation: Disabled
Quote:
in posts, use code tags.

Your added call to opendir() isn't right. You need a character array (a "c string"), not a silly C++ string. Second, your function still closes d before it knows for sure that its opened, you tried to fix it in this case, but its poor coding style and very hard to read.

Third, and most importantly, opendir() still isn't going to do what you think it does. You need chdir() if you want to change directories. opendir will open the directory and you will be able to read it's contents, but your next call will not be relative to the new directory.

add .c_str() to your string in the function call from main and you will fix the segfault. However, your code will still not do what you want. and your function will still segfault every time there is an error or when called without opening a directory first. fix that and then change your opendir() calls to chdir() calls and it will work.
Code:
DIR *d;
string dir_name;

void cd(string new_dir_name)
{
struct stat st = {0};

string temp_dir_name = dir_name + new_dir_name + "/";
printf("\nchecking this dir%s\n",temp_dir_name.c_str());
if((stat(temp_dir_name.c_str(), &st) < 0)) {
printf("%s Directory does not exist in %s\n",temp_dir_name.c_str(),dir_name.c_str());
}
else
{
closedir(d);
d = opendir(temp_dir_name.c_str());
printf("Directory changed from %s to %s\n",dir_name.c_str(),temp_dir_name.c_str());
dir_name = temp_dir_name;
}
}

int main(void)
{
dir_name = "/";
d = opendir(dir_name.c_str());
cd("etc"); //works
cd("fonts"); //segmentation fault
return(0);
}
This still gives the same error.Also if i use chdir(),it will change the env. variable "HOME".I dont want to use environmental variables
 
Old 04-18-2014, 07:06 PM   #9
theNbomr
LQ 5k Club
 
Registered: Aug 2005
Distribution: OpenSuse, Fedora, Redhat, Debian
Posts: 5,399
Blog Entries: 2

Rep: Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908Reputation: 908
A real shell, at least anything like the common Borne shell variants and C-shell variants cannot be written without using some form of the exec() system call. When you get around to the understanding that a shell is really just a way to expose the core OS services to the user, you will understand that one to those core services is to create new processes. In Linux, that is a two step procedure; fork() a clone of the present (parent) process, and then replace that child process with a different process (exec()). If you wish to avoid one particular variant of exec(), then that's your prerogative, but at some level, you just have to use an exec() system call. Avoiding system() does make sense, since it wraps the whole thing with a call to launch (using fork() + exec()) another child shell, which I find is almost never useful.
You can never write the 'cd' command as an external process, since it needs to alter a property of a process, and the only process it can alter is the one that is running. It is impossible to alter the current working directory of any other process, be it a child, parent or sibling. The example code fails to change the current working directory of the shell process. To do that use the chdir() command. Opening a directory for reading does not change the current working directory property of a process. Changing the current working directory will not alter anything in the process's environment. Some shells will make that a side effect of the 'cd' command, but your shell doesn't have to, and it certainly won't happen without a deliberate call to setenv(), which is how the environment of any process gets altered.

Last edited by theNbomr; 04-18-2014 at 07:12 PM.
 
  


Reply



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
[SOLVED] BinUtils: The system has no more ptys. Ask your system administrator to create more. ArchaicBlues Linux From Scratch 6 10-27-2012 03:21 AM
i want to write a shell script create backup of my system into a external hard disk. rajhans Linux - Newbie 6 03-30-2012 04:18 PM
execvp system call?? khoh Programming 2 04-03-2011 02:55 PM
'sh' shell - Actually calls legacy Bourne shell, or uses system default? Dtsazza Linux - Software 1 10-28-2005 09:20 AM
execvp vs. shell wiredj Programming 4 04-14-2004 08:24 AM

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

All times are GMT -5. The time now is 10:28 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