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.
Related
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.
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?
I'm trying to implement the ls command with wildcard, *.
I have just learned the fact that most shells convert ls-argument containing * to the corresponding entries when performing ls command.
For example, The directory foo consist of a.file, b.file, and directory bar.
Then, the directory bar has c.file, d.file, and e.file.
and assume that current directory is the directory foo.
the argument */* is converted is to the following entries.
"bar/c.file", "bar/d.file", "bar/e.file"
How can program perform this? I don't know where to start from. And
there are many possible cases.
*/../*, ../../*, */*/*, etc.
Any advice would be awesome. Thank you..
You can of couse use glob() to do a lot of this work.
Such patterns are called globs, for some reason I won't dig up now. :)
POSIX provides glob(3) for programmatic wildcard path expansion.
For educational reasons I have to exploit an C-Code
The Programm set the egid first, and then the vulnerability with the system("/usr/bin/..."); Command.
So I made an 'usr' executeable in my Home-Directory and set the Path to the Home PATH=$HOME:$PATH
And I want to change the IFS Variable in the bash to /: export IFS='/'
Unfortunatelly, when i call the C-Programm: my exploit doesn't work
Is anybody able to tell me what is wrong?
Add the IFS as part of your program's call to system(). System executes the code with /usr/bin/sh -c. So you can do similar to what you'd in the shell prompt.
system("export IFS='/'; /usr/bin/cmd");
Note that once the child process is terminated, the IFS set will no longer be available in the parent.
I suppose we are studying at the same university, because I am currently confronted with the same problem. I don't want to give you the whole solution, because that would be too easy =)
Your IFS variable is not ignored, but it doesn't work as you might think. When you call the C-Programm there is an additional output in the shell, which refers to the lesspipe. With the information in this link and this german link you are able to solve the challenge1 ;)
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