简体   繁体   中英

Implementing a Unix shell in C: check if file is executable

I am working on implementing a Unix shell in C and I'm currently dealing with the problem of relative paths. Notably while inputting commands. For now I have to enter the full path of the executable every time, when I would much rather simply put "ls" or "cat".

I have managed to get the $PATH env variable. My idea is to split the variable at the ":" character, then append each new string to the command name and check if the file exists and is executable.

For example if my PATH is: "/bin:/usr/bin" and I input "ls", I would like the program to check first if "/bin/ls" exists and is executable, if not move on to "/usr/bin/".

Two questions:

1) Is it a good way to do it? (Doesn't it have to be necessarily the best. I just want to make sure that it would work.

2) More importantly, How can I check in C, if a file exists and is executable?

I hope I'm clear enough, and ... well thanks :)

Don't. Performing this check is wrong; it's inherently subject to a race condition. Instead, try executing it with the appropriate exec -family call. If it's not executable, you'll get an error.

Also note that you don't need to search the PATH yourself; execvp can do this for you.

stat ? Psh. Way more than you need.

Check out the access() syscall.

if (access(filename, F_OK|X_OK) == 0)
{
    /* You can execute this file. */
}

Note that any check for file access or existence of a file has an in it. You can't guarantee at your call to execve that someone didn't remove the executable bit, change the ownership of the file, delete the file, etc., in the time since your check happened. Keep this in mind when you write your code and decide how to handle error conditions.

Use the stat function: http://linux.die.net/man/2/stat

eg:

struct stat sb;
if(!stat(path, &sb))
{
  if(IS_REG(sb.st_mode) && sb.st_mode & 0111)
    printf("%s is executable\n", path);
}

Call stat on the full pathname, and if it returns 0 (success), the target exists. In that case you can use the st_mode field in the returned structure to test whether the target is a directory, device, named pipe, or ordinary file. If it's a file, st_mode will also contain the permission bits. (If it's a directory, some "executable" bits might be set, but that would imply "searchable" rather than "executable".)

Edit: As others have noted, this is subject to a race condition, and there are better ways of accomplishing what you want to do in this particular situation.

The access() answer is the only sensible one. If you use stat, you'll have to parse /etc/group to find out all the groups you are in BESIDE getgid() and test them together with the group-executable bit.

How are you creating the process??

Use execlp or execvp.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM