own shell in C using execv - c

I am trying to build my own shell in C as part of a class project. We are required to use execv and implement our own path. For better understanding here is the question:
The list of paths is empty by default, but may grow to any arbitrary size. You should implement a built-in command to control this variable:
path [+|- /some/dir]
path (without arguments) displays all the entries in the list separated by colons, e.g. "/bin:/usr/bin".
path + /some/dir appends the given pathname to the path list.
path - /some/dir removes the given pathname from the path list.
I have misread the assignment and used execvp so far. Please can you shed some light on how to create my own path variable, and for each command executed search the directory it is in and add it to the path? Or is there any simple shell written using execv I can take a look at?
I saw http://linuxgazette.net/111/ramankutty.html, but I found the search a little too complex, and he uses execve.
so far i have char *mypath variable which is null initially. but the user can add or remove using path + some/dir or path - /some/dir. syntax for execv is execv("/some/dir", argv) how do i search my path for the executable and pass it to execv....for example mypath=/bin/ls ; when i pass execv(mypath, argv) it does not work...so how do i pass the path to execv?

I'm guessing the reason you are supposed to use excev is precisely that it doesn't take into account the path of the environment, but the call has to provide a full path to the function.
Since this is a class project, you are supposed to write your code - writing code is how you learn how to do things, much more than copy-and-paste from the internet, so I'm not going to write code to solve the problem but instead describe the solution.
You will need to keep a list of path entries - adjusted through the path + some/dir and path - some/dir mechanism - so these commands need to be handled inside your shell, of course, and they should add/remove from your list of path entries.
When you then come to executing something, say "mycommand" is entered, you will have to scan the list of path entries, and check if there is a file by the name "mycommand" in the directory specified by the path entry that can be executed (has execute bit set in the directory entry). If so, call execv on the string of current path entry and "mycommand" concatenated. (You can produce the concatenated string and use the stat function to get the information about the file, for example)
Do check for errors, and report if something goes wrong.
Please do not try to find someone else's shell on the internet. That is not how you learn, and if you don't actually learn from the class exercises, you will most likely not succeed once you finish school - and that's ultimately WHY you are going to school, right?

Related

How to get directory of exec files of any commands on terminal in C? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I am rewriting the problem since it's not clearly understood as far as I see. I implement my own shell in C which needs to support all commands the original one does.
The problem is to execute all existing UNIX bash commands in C without using execvp() or system() functions which already let you do that easily.
To do that, I need to search all required directories which may consist any kind of UNIX commands. I just want to know that:
Do I really be sure that I support all possible UNIX commands in any distribution when I checked all directories in my PATH environment variable? (which becomes /bin/, /usr/bin/, /usr/local/bin in my machine)
I have also found a method which gets the full directory of a file you inserted called realpath() . But unfortunately, it returns (null) when I attempt to get the directory of the command inserted in my own shell.
What else do you suggest me to achieve this problem? As a last solution, does it make sense to search whole computer recursively from the root to find the command inserted?
If there's something unclear, please let me know to clarify. I would be very thankful if you could answer with a piece of example code and clear [on hold] tag in the question if you think it's clearly described from now.
Thanks in advance!
It is true that a UNIX executable can be absolutely anywhere, but in the context of a homework assignment, it doesn't make sense to search the entire filesystem. What your instructor probably wants you to do is implement the functionality of execvp yourself, using execv. What execvp does is, first, it looks to see if there is a slash in the command name. If there is, it passes the command and arguments directly to execv - it doesn't search. Otherwise, it iterates over the directories in PATH and checks whether the command is an executable in each. Crucially, it does NOT scan the contents of each directory; not only would that be very slow, it wouldn't even work under some conditions (such as a directory with --x permissions) Instead, it blindly calls execv with the pathname "$dir/$cmd". If that works, execv doesn't return. If it didn't work, and errno is set to ENOENT, it goes on to try the next directory in the path.
First, note that realpath() doesn't search anything, it just determines the absolute path of a given file.
There is no all possible UNIX command as you may think. At least any executable file can be considered as UNIX command, and executables are not necessarily the ones that have x right attached to it. Shell scripts may be executed by command like sh myscript even if executable access is not granted on it. Only binaries necessitate to have that attached right to be executed natively. So there is no true criterion that can help you. But you may have files that have x right and that are not executables!
A common usage is that executables are located in some directories /bin, /usr/bin, /usr/local/bin, and alike. Your shell has an environnement variable named PATH that contains list of directories where to search for command you specified freely on command line.
Anyway, if you choose a criterion to make an exhaustive search by yourself, say all files with x right then you can use command find like find some_starting_dir -perm +0111 to get all files that have x right somewhere.
If you want to program it then you may use either legacy readdir() function or the newer nftw() to make your own directory traversal. You will find many example of these even on SO.

How do i use vfs_readdir in linux kernel?

I'm trying to use a system call to display the contents of a directory. I've been pointed in the direction of vfs_readdir, but I have no clue of how to use it or what to pass to it to get the contents of a directory. All I want to do is be able to list files in a directory similar to how ls works. (I eventually intend to store this in some sort of buffer, but for now just being able to print the contents of a dir would be enough).
I think you probably have to open the directory using filp_open.
For the "flags" argument, you proably need to put some combination of the LOOKUP_ flags listed in include/linux/namei.h
You can see what build_open_flags does here: http://lxr.linux.no/#linux+v3.1.5/fs/open.c#L876 to provide flags to filp_open.
As far as I know, filp_open IS the correct way of opening a file in kernel-space. However, doing so is discouraged.
Provided you do so from the context of a "normal" thread belonging to a user process, I think you will be ok.

Using execv() with PATH env variable

I'm writing a shell and I want to use execv() and search for the right directory through the $PATH environment variable (Yes, I know I can use execvp() and just pass the name of the file to it).
What I'm thinking about doing is getting a string from getenv("PATH"), breaking it down to separate paths then trying each one. But I was wondering if there is an easier way to do it?
I guess the question is: how does execvp() search for the right path?
Thanks!
What you described is exactly how execvp() searches the PATH. I don't think there's much point in reimplementing this yourself.

How to get the parent directory of the current folder in a C program?

I am trying to get the parent directory of the current folder in which i have the program.
I need to include in the C program I have. I tried doing it through string methods and solve it, but I feel there can be a better and simpler way. Eg: If his path is “C:\Application\Config”, then I want to get - “C:\Application” the just parent path.
Can some one please help me with this?
Thanks,
Priyanka
To in-place truncate a string at its last backslash:
char pathname[MAX_PATH];
GetCurrentDirectory(MAX_PATH, pathname);
char* last_backslash = strrchr(pathname, '\\');
if (last_backslash)
{
*last_backslash = '\0';
}
Sometimes just adding \.. will suffice if you are not afraid by MAX_PATH.
It's difficult to answer your question since you haven't really specified what you want to -do- with the path once you have it. If you want to change to the new directory, that's easy, you just use whatever function you'd normally use to change directory but pass it ".." instead of a full path - that's because on all sane filesystems, ".." is a 'magic' directory which exists inside all other directories and refers to the parent thereof.
If you want to perform some string function on the new directory before jumping to it, your problem instantly becomes a lot more difficult to solve. The way I'd go about doing it mirrors RichieHindle's solution - strip the current directory away from the full path then you're left with the parent directory's path with which you can muck about to your heart's content.
In Windows OS, the API function you need is called GetCurrentDirectory().
http://msdn.microsoft.com/en-us/library/aa364934%28v=vs.85%29.aspx

What can I do if getcwd() and getenv("PWD") don't match?

I have a build system tool that is using getcwd() to get the current working directory. That's great, except that sometimes people have spaces in their paths, which isn't supported by the build system. You'd think that you could just make a symbolic link:
ln -s "Directory With Spaces" DirectoryWithoutSpaces
And then be happy. But unfortunately for me, getcwd() resolves all the symbolic links. I tried to use getenv("PWD"), but it is not pointing at the same path as I get back from getcwd(). I blame make -C for not updating the environment variable, I think. Right now, getcwd() gives me back a path like this:
/Users/carl/Directory With Spaces/Some/Other/Directories
And getenv("PWD") gives me:
/Users/carl/DirectoryWithoutSpaces
So - is there any function like getcwd() that doesn't resolve the symbolic links?
Edit:
I changed
make -C Some/Other/Directories
to
cd Some/Other/Directories ; make
And then getenv("PWD") works.. If there's no other solution, I can use that.
According to the Advanced Programming in the UNIX Environment bible by Stevens, p.112:
Since the kernel must maintain knowledge of the current working directory, we should be able to fetch its current value. Unfortunately, all the kernel maintains for each process is the i-node number and device identification for the current working directory. The kernel does not maintain the full pathname of the directory.
Sorry, looks like you do need to work around this in another way.
There is no way for getcwd() to determine the path you followed via symbolic links. The basic implementation of getcwd() stats the current directory '.', and then opens the parent directory '..' and scans the entries until it finds the directory name with the same inode number as '.' has. It then repeats the process upwards until it finds the root directory, at which point it has the full path. At no point does it ever traverse a symbolic link. So the goal of having getcwd() calculate the path followed via symlinks is impossible, whether it is implemented as a system call or as a library function.
The best resolution is to ensure that the build system handles path names containing spaces. That means quoting pathnames passed through the shell. C programs don't care about the spaces in the name; it is only when a program like the shell interprets the strings that you run into problems. (Compilers implemented as shell scripts that run pre-processors often have problems with pathnames that contain spaces - speaking from experience.)

Resources