LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 11-19-2003, 05:25 PM   #1
Hady
Member
 
Registered: Nov 2003
Posts: 55

Rep: Reputation: 15
get full path of a command (in C)


Hi!

I'm trying to write a very simple shell in C that
Prompts the user for a command,
Parses the command line,
Execute the command while passing to it the arguments passed on the command
line.

say the desired command is in variable cmd

how can i get the full path of this specific cmd?
anything like path = getenv("PATH"); ??

Thank you for your time.

Hady
 
Old 11-19-2003, 05:45 PM   #2
trickykid
LQ Guru
 
Registered: Jan 2001
Posts: 24,149

Rep: Reputation: 256Reputation: 256Reputation: 256
Moved: More suitable in our Programming forum.
 
Old 11-20-2003, 11:51 AM   #3
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 110Reputation: 110
If you need a program to find the full path to itself, here's an example.
(If the program is executed through a symbolic link, it will print the full path to the actual file, not the link.)
Code:
/* getexepath2.c */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

#define MAXPATHLEN 200   /* make this larger if you need to. */

int main ()
{
     int length;
     char fullpath[MAXPATHLEN];
     
     /* /proc/self is a symbolic link to the process-ID subdir
      * of /proc, e.g. /proc/4323 when the pid of the process
      * of this program is 4323.
      *
      * Inside /proc/<pid> there is a symbolic link to the
      * executable that is running as this <pid>.  This symbolic
      * link is called "exe".
      *
      * So if we read the path where the symlink /proc/self/exe
      * points to we have the full path of the executable.
      */


     length = readlink("/proc/self/exe", fullpath, sizeof(fullpath));
     
     /* Catch some errors: */
     if (length < 0) {
          fprintf(stderr, "Error resolving symlink /proc/self/exe.\n");
          exit(EXIT_FAILURE);
     }
     if (length >= MAXPATHLEN) {
          fprintf(stderr, "Path too long. Truncated.\n");
          exit(EXIT_FAILURE);
     }

     /* I don't know why, but the string this readlink() function 
      * returns is appended with a '@'.
      */
     fullpath[length] = '\0';       /* Strip '@' off the end. */

     printf("Full path is: %s\n", fullpath);
     return 0;
}

Last edited by Hko; 11-20-2003 at 11:52 AM.
 
Old 11-20-2003, 12:56 PM   #4
Hady
Member
 
Registered: Nov 2003
Posts: 55

Original Poster
Rep: Reputation: 15
Thanks for replying,

but I need something that returns the path not of itself,
but of any command that the user types,

for example, if the user of the program types ls,
it returns (/usr/bin) [supposing ls is in that directory]


thanks for the help.
 
Old 11-20-2003, 02:25 PM   #5
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 110Reputation: 110
Quote:
Originally posted by Hady
but I need something that returns the path not of itself,
but of any command that the user types,

for example, if the user of the program types ls,
it returns (/usr/bin) [supposing ls is in that directory]
I have looked for it in the man an info pages, but there seems not to be a standard library call for this. This amazes really. There will be a day, when I will need it as well, so I made one. Hope this helps you out.
Code:
/* searchpath.c
 *
 * Find named executable in the PATH environment variabele.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <libgen.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>


/* int checkifexecutable(const char *filename)
 * 
 * Return non-zero if the name is an executable file, and
 * zero if it is not executable, or if it does not exist.
 */

int checkifexecutable(const char *filename)
{
     int result;
     struct stat statinfo;
     
     result = stat(filename, &statinfo);
     if (result < 0) return 0;
     if (!S_ISREG(statinfo.st_mode)) return 0;

     if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
     if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
     return statinfo.st_mode & S_IXOTH;
}


/* int findpathof(char *pth, const char *exe)
 *
 * Find executable by searching the PATH environment variable.
 *
 * const char *exe - executable name to search for.
 *       char *pth - the path found is stored here, space
 *                   needs to be available.
 *
 * If a path is found, returns non-zero, and the path is stored
 * in pth.  If exe is not found returns 0, with pth undefined.
 */

int findpathof(char *pth, const char *exe)
{
     char *searchpath;
     char *beg, *end;
     int stop, found;
     int len;

     if (strchr(exe, '/') != NULL) {
	  if (realpath(exe, pth) == NULL) return 0;
	  return  checkifexecutable(pth);
     }

     searchpath = getenv("PATH");
     if (searchpath == NULL) return 0;
     if (strlen(searchpath) <= 0) return 0;

     beg = searchpath;
     stop = 0; found = 0;
     do {
	  end = strchr(beg, ':');
	  if (end == NULL) {
	       stop = 1;
	       strncpy(pth, beg, PATH_MAX);
	       len = strlen(pth);
	  } else {
	       strncpy(pth, beg, end - beg);
	       pth[end - beg] = '\0';
	       len = end - beg;
	  }
	  if (pth[len - 1] != '/') strncat(pth, "/", 1);
	  strncat(pth, exe, PATH_MAX - len);
	  found = checkifexecutable(pth);
	  if (!stop) beg = end + 1;
     } while (!stop && !found);
	  
     return found;
}



int main(int argc, char **argv)
{
     char path[PATH_MAX+1];
     char *progpath = strdup(argv[0]);
     char *prog = basename(progpath);
     char *exe;

     if (argc != 2) {
	  fprintf(stderr, "Usage:  %s <executable file>\n", prog);
	  return 1;
     }
     exe = argv[1];

     if (!findpathof(path, exe)) {
	  fprintf(stderr, "No executable \"%s\" found\n", exe);
	  return 1;
     }
     puts(path);
     free(progpath);
     return 0;
}
If you need only the directory, not the file (or symbolic link) itself, you can use dirname() (see "man 3 dirname") to strip it of.
 
Old 11-20-2003, 02:45 PM   #6
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 110Reputation: 110
One small bug still:

On my system (Debian testing) "/usr/bin/gcc" is a symbolic link to /usr/bin/gcc-3.3.

When I try my program:
Code:
bash$ searchpath gcc
/usr/bin/gcc

# which is correct, though it is a symbolic link actually.
# But when I do the following, the $PATH is not used, and then
# the symbolic link gets resolved by the realpath() function:

bash$ searchpath /usr/bin/gcc
/usr/bin/gcc-3.3
So two different answers for the same thing, though both correct, it's not consistent.
More or less a "cosmetic" bug.
 
Old 11-20-2003, 06:53 PM   #7
Hady
Member
 
Registered: Nov 2003
Posts: 55

Original Poster
Rep: Reputation: 15
Thanks for your time and help.

[I'm new to programming in Linux]
Could you tell me more about the

struct stat statinfo;

stat(path, &statinfo);

and S_ISREG(statinfo.st_mode)

and where can I read documentation about them.

thanks
 
Old 11-21-2003, 08:33 AM   #8
mbabuskov
Member
 
Registered: Nov 2003
Location: Subotica
Distribution: Slackware, Knoppix, Mandriva
Posts: 42

Rep: Reputation: 15
Re: get full path of a command (in C)

Quote:
Originally posted by Hady
say the desired command is in variable cmd

how can i get the full path of this specific cmd?
anything like path = getenv("PATH"); ??
Try using which & popen, something like this:

FILE *fp = popen('which cmd');
fgets(fp, path_to_command);
pclose(fp);

just an idea.
 
Old 11-21-2003, 10:47 AM   #9
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 110Reputation: 110
Yes, that's also possible, but not "real C".
But much easier and without bugs allright.
 
Old 11-21-2003, 10:50 AM   #10
Hko
Senior Member
 
Registered: Aug 2002
Location: Groningen, The Netherlands
Distribution: Debian
Posts: 2,536

Rep: Reputation: 110Reputation: 110
Hady: You can find out about stat(), its struct stat, the S_ISREG macro (and others), and also about the bitmask to test for file rights with:

man 2 stat

or, more comprehensive, (if you have the info system and the info file for libc installed):

info libc "file attributes"
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
full path of a file ttilt Linux - General 1 11-08-2005 06:02 PM
Need to specify the full URL path.. Why? soichih Linux - Networking 3 07-31-2004 08:37 AM
get full path of a command (in C) Hady Linux - Software 1 11-19-2003 05:46 PM
Full Path problems chedmaster Linux - Newbie 1 06-26-2003 10:24 AM
How to get executable's full path using C/C++? oldbee Programming 6 02-19-2002 09:21 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 12:28 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration