You need to first obtain the path list, e.g. using
getenv("PATH"). Allocate a temporary string long enough to contain both the longest directory (delimited by colons) in the path list, a slash, the file name, and a trailing EOS (zero byte) to mark the end of the string.
Write a loop that tries each directory specified in the path list in the order they're listed. Remember to skip over empty ones, sometimes PATH contains multiple successive colons (like
::). Append a slash and the file name to the directory name, followed by an end of string mark '\0', then check using e.g
access(pathname,X_OK) to see if that one is executable. If it is, this is the result; don't check any further. If none of them match, then most
which implementations return nothing.
Most of this is string manipulation. Personally, I would only need
strlen(),
strcspn() and
strspn() (the latter two to find where the next colon is, and to skip over the colon -- these can be written using a trivial loop too, of course).
Usually most people tend to write interfaces that save the pathname to a buffer provided by the caller. I disagree, strongly. Compare the GNU/POSIX.1-2008
getline() interface to old
fgets(). As the example at the end of the getline man page shows, a trivial program can accept any input without problems, as long as there is enough resources available. A corresponding fgets() program is either wasteful (using a lot of memory for a buffer that is only partially used), or will get confused with long lines.
I shudder to think what kind of security problems could be caused by a part of a shell silently truncating the PATH string! Especially if it truncated to one length at one place, and to another length at another place. No, please! Don't do it! Noo.......
Therefore, I'd also use
malloc() to allocate the pathname buffer (also used to return the string to the caller). Hint:
malloc(strlen(pathlist)+strlen(filename)+2) is guaranteed to be long enough, and is not wasteful as the path list is always quite short. One extra char is for the slash, the other for the end-of-string '\0'. Just remember that when a problem occurs, the function should remember to
free() the temporary/result buffer, and that all callers should remember to
free() the pointer they receive after they've done with it.