trying to create a shell without using system or execvp
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
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().
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.
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);
}
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.
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
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.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.