C, which prints the name of the executable

Suppose the name of the source file is test.cpp . When it is compiled, it creates a test.exe file. When I execute it, it should identify its test.exe file test.exe and print it.

I can get a list of all the files and directories present in the current directory using the following code:

 DIR * directory; struct dirent * direct; direct = readdir(directory); 

But how can I determine the associated file name, in this case "test.exe" ?

+5
source share
5 answers

You know the name of the executable when creating it; The easiest solution is to embed it in the program using the -D or /D option to define a macro on the command line.

In addition, the general answer is that this is not possible:

According to standard

  • argv[0] must contain the name that was used to invoke the program (whatever that means). Which is nice, but 1) it is not even implemented under Unix, and 2) on most systems, there are all kinds of aliases, which means that the name used to invoke the program has nothing to do with the name of the executable file.

In windows

  • There is a system function GetModuleFileName , which can be used to get the path to the executable file. When you have a path, the last Path Element is the name of the executable.

On unix

  • This is fundamentally impossible. When starting a new process, Unix accepts separate arguments for the path to the executable file and for which it ends in argv[0] , so they can potentially have nothing to do with each other. It all depends on who starts your process. bash will put the full path to the executable in the environment variable "_" , so you can use getenv to get it. But this only works if your program was started by bash . In most Unices, you can also find it in the /proc file system if you know your way there; but the organization of this varies from one Unix to another. Note also that due to hard links, you can only have one name.

The real question is why you want to do this. What is the problem? trying to solve?

+6
source

In your main function, argv[0] is the name of the executable from the command line

 #include <stdio.h> int main(int argc, char ** argv) { printf("%s", argv[0]); return 0; } 

Live demo

This prints the name of the command, which is the directory relative to the current working directory, plus the executable name (if available, which is not guaranteed) To get the current working directory, use the getcwd() function of the standard C library.

Retrieving the file name from the command pool in argv[0] is platform dependent: unix uses slashes " / ", windows allow mixed use of slash / and backslash \ , and any other platform can use any other path delimiter. To extract a file name from a path, a cross-platform library such as Qt or Boost is required. In POSIX environments, you can use the base name.

+16
source
 #include <stdio.h> int main(int argc, char *argv[]) { printf("%s\n", argv[0]); return 0; } 

Please note that your program may be launched as:

 /home/user/./app 

In this case, you can get the name using strrchr :

 #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { char *appname; appname = strrchr(argv[0], '/'); /* '\\' on Windows */ printf("%s\n", appname ? ++appname : argv[0]); return 0; } 
+11
source

On Linux systems, I think you can also use basename(char *path); from libgen.h , try $ man basename :

Print NAME with the removed source components. If indicated, also remove the trailing SUFFIX.

I tried this as:

 // filename.c #include<stdio.h> #include<stdlib.h> #include<libgen.h> int main(int argc, char* argv[]){ char* exe_name = basename(argv[0]); printf(" Executable Name: %s", exe_name); printf("\n"); return EXIT_SUCCESS; } 

Observations compiled and tested as:

 taxspanner@ :~$ ls filename.c filename.c taxspanner@ :~$ gcc -std=gnu99 -Wall -pedantic filename.c -o filename taxspanner@ :~$ ls filename* filename filename.c taxspanner@ :~$ 

Now run it in the current directory:

 taxspanner@ :~$ ./filename Executable Name: filename 

Using the absolute path:

 taxspanner@ :~$ pwd /home/taxspanner taxspanner@ :~$ /home/taxspanner/filename Executable Name: filename 

Relative path:

 taxspanner@ :~$ cd study/divide-5/ taxspanner@ :~/study/divide-5$ pwd /home/taxspanner/study/divide-5 taxspanner@ :~/study/divide-5$ ls ../../filename* ../../filename ../../filename.c taxspanner@ :~/study/divide-5$ ../../filename Executable Name: filename taxspanner@ :~/study/divide-5$ 

another attempt with an executable with a suffix:

 taxspanner@ :~$ gcc -std=gnu99 -Wall -pedantic filename.c -o filename.out taxspanner@ :~$ ./filename.out Executable Name: filename.out taxspanner@ :~$ cd study/divide-5/ taxspanner@ :~/study/divide-5$ ../../filename.out Executable Name: filename.out 

Be careful when using : Both dirname() and basename() can modify the contents of the path, so it may be advisable to pass a copy when calling one of these functions.

Give it a try!

+3
source

On Linux specifically:

you can use proc (5) and the symbolic link /proc/self/exe , so use readlink (2) . Once you have done this, you can use basename (3) or realpath (3) on the resulting symbolic link.

However, remember that a program may not always have a file path. It can have several file paths (for example, /bin/rpath is a symbolic link to /bin/bash , and the shell process behaves differently when rbash called or as bash ). Sometimes a given file (actually an inode ) has several hard links to it. In strange cases, they are not. And it may happen that the program execve (2) -ed, and then removed using unlink (2) (possibly from another process scheduled to run before yours), etc.

(BTW, your question is OS specific, readdir (3) is POSIX, and there are some operating systems that don't even have directories and readdir not mentioned by the C11 standard, checking by reading n1570 )

I experimented with the following (pathological) program ./selfremove (in my directory /home/basile/tmp/ ), which deletes its own binary:

  // file selfremove.c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> int main (int argc, char **argv) { char selfpath[128]; memset (selfpath, 0, sizeof (selfpath)); if (readlink ("/proc/self/exe", selfpath, sizeof (selfpath) - 1) < 0) { perror ("first readlink"); exit (EXIT_FAILURE); }; printf ("initial /proc/self/exe -> %s\n", selfpath); if (unlink (argv[0])) { fprintf (stderr, "unlink %s: %m\n", argv[0]); exit (EXIT_FAILURE); }; printf ("%s unlinked\n", argv[0]); if (readlink ("/proc/self/exe", selfpath, sizeof (selfpath) - 1) < 0) { perror ("second readlink"); exit (EXIT_FAILURE); }; printf ("final /proc/self/exe -> %s\n", selfpath); return 0; } 

It works, and the kernel creates a symbolic link * (deleted) (since a distorted encoder can rename the executable file as selfremove (deleted) , so the kernel added with the suffix is ​​only an indication ....):

  % ./selfremove initial /proc/self/exe -> /home/basile/tmp/selfremove ./selfremove unlinked final /proc/self/exe -> /home/basile/tmp/selfremove (deleted) 

So even with /proc/self/exe you cannot always trust the result.

If you assume that your program was execve (2) -ed by some kind of shell (or a similar program executing execvp (3) ) - and this is not always the case, then the PATH variable may have been used (and searched from your main argv[0] if she does not have / ). You can use getenv (3) as getenv("PATH") to get it from your environment (see environment (7) for more). This $PATH is usually installed and used, but they are also pathological cases.

Thus, in the general case, it is not possible to reliably print your own executable file (as my pathological selfremove.c ). In most cases, you can find it (for example, readlink from /proc/self/exe or by searching in $PATH using argv[0] ).

+2
source

Source: https://habr.com/ru/post/1207737/


All Articles