Directory of running program on Linux? - c++

Hey, I've been writing a program (a sort of e-Book viewing type thing) and it loads text files from a folder within the folder of which the executable is located. This gives me a bit of a problem since if I run the program from another directory with the command "./folder/folder/program" for example, my program will not find the text, because the working directory isn't correct. I cannot have an absolute directory because I would like the program to be portable. Is there any way to get the precise directory that the executable is running from even if it has been run from a different directory. I've heard could combine argc[0] and getcwd() but argc is truncated when there is a space in the directory, (I think?) so I would like to avoid that if possible.
I'm on Linux using g++, Thanx in advance

EDIT - don't use getcwd(), it's just where the user is not where the executable is.
See here for details.
On linux /proc/<pid>/exe or /proc/self/exe should be a symbolic link to your executable. Like others, I think the more important question is "why do you need this?" It's not really UNIX form to use the executable path to find ancillary files. Instead you use an environment variable or a default location, or follow one of the other conventions for finding the location of ancillary files (ie, ~/.<myapp>rc).

When you add a book to your library you can remember its absolute path.
It is not a bad when your program rely on the fact that it will be launched from the working dir and not from some other dir. That's why there are all kinds of "links" with "working dir" parameter.
You don't have to handle such situations in the way you want. Just check if all necessary files and dirs structure are in place and log an error with the instructions if they are not.
Or every time when your program starts and doesn't find necessary files the program can ask to point the path to the Books Library.
I still don't see the reason to know your current dir name.
#include <boost/filesystem/convenience.hpp>
#include <iostream>
#include <ostream>
int main(int argc, char** argv)
{
boost::filesystem::path argvPath( argv[0] );
boost::filesystem::path executablePath( argvPath.parent_path() );
boost::filesystem::path runPath( boost::filesystem::initial_path() );
std::cout << executablePath << std::endl;
std::cout << runPath << std::endl;
return 0;
}

You can get the path of the running program by reading the command line. In linux you can get the command line by reading /proc folder as /proc/PID/CommandLine

argv[0] is not truncated when there are spaces. However, it will only have the program name and not the path when a program is run from a directory listed in the PATH environment variable.
In any case, what you are trying to do here is not good design for a Unix/Linux program. Data files are not stored in the same directory as program files because doing so makes it difficult to apply proper security policies.
The best way to get what you want in my opinion is to use a shell script to launch the actual program. This is very similar to how Firefox launches on Linux systems. The shell places the name of the script into $0 and this variable will always have a path. Then you can use an environment variable or command line argument to give your program the location of the data files, like this:
dir=`dirname "$0"`
cd "$dir/../data/"
"$dir/real-program"
And I would arrange your program so that it's files are somewhat like this:
install-dir/bin/program
install-dir/bin/real-program
install-dir/etc/config
install-dir/data/book-file.mobi

Related

File path issue in C++ program when executing from a shell script on Linux [duplicate]

Hey, I've been writing a program (a sort of e-Book viewing type thing) and it loads text files from a folder within the folder of which the executable is located. This gives me a bit of a problem since if I run the program from another directory with the command "./folder/folder/program" for example, my program will not find the text, because the working directory isn't correct. I cannot have an absolute directory because I would like the program to be portable. Is there any way to get the precise directory that the executable is running from even if it has been run from a different directory. I've heard could combine argc[0] and getcwd() but argc is truncated when there is a space in the directory, (I think?) so I would like to avoid that if possible.
I'm on Linux using g++, Thanx in advance
EDIT - don't use getcwd(), it's just where the user is not where the executable is.
See here for details.
On linux /proc/<pid>/exe or /proc/self/exe should be a symbolic link to your executable. Like others, I think the more important question is "why do you need this?" It's not really UNIX form to use the executable path to find ancillary files. Instead you use an environment variable or a default location, or follow one of the other conventions for finding the location of ancillary files (ie, ~/.<myapp>rc).
When you add a book to your library you can remember its absolute path.
It is not a bad when your program rely on the fact that it will be launched from the working dir and not from some other dir. That's why there are all kinds of "links" with "working dir" parameter.
You don't have to handle such situations in the way you want. Just check if all necessary files and dirs structure are in place and log an error with the instructions if they are not.
Or every time when your program starts and doesn't find necessary files the program can ask to point the path to the Books Library.
I still don't see the reason to know your current dir name.
#include <boost/filesystem/convenience.hpp>
#include <iostream>
#include <ostream>
int main(int argc, char** argv)
{
boost::filesystem::path argvPath( argv[0] );
boost::filesystem::path executablePath( argvPath.parent_path() );
boost::filesystem::path runPath( boost::filesystem::initial_path() );
std::cout << executablePath << std::endl;
std::cout << runPath << std::endl;
return 0;
}
You can get the path of the running program by reading the command line. In linux you can get the command line by reading /proc folder as /proc/PID/CommandLine
argv[0] is not truncated when there are spaces. However, it will only have the program name and not the path when a program is run from a directory listed in the PATH environment variable.
In any case, what you are trying to do here is not good design for a Unix/Linux program. Data files are not stored in the same directory as program files because doing so makes it difficult to apply proper security policies.
The best way to get what you want in my opinion is to use a shell script to launch the actual program. This is very similar to how Firefox launches on Linux systems. The shell places the name of the script into $0 and this variable will always have a path. Then you can use an environment variable or command line argument to give your program the location of the data files, like this:
dir=`dirname "$0"`
cd "$dir/../data/"
"$dir/real-program"
And I would arrange your program so that it's files are somewhat like this:
install-dir/bin/program
install-dir/bin/real-program
install-dir/etc/config
install-dir/data/book-file.mobi

ifstream cannot locate file

I'm ashamed for not being able to solve this but i can't make this work. I have this brief test:
std::string archnom = "../data/uniform.txt";
ifstream archin(archnom.c_str());
ASSERT(archin.good());
The assert is throwing error. For some reason it's not locating the uniform.txt file. The project structure is:
project
---> data/uniform.txt
---> a.out
---> main.txt
I've already tried changing archnom as follows without success:
std::string archnom = "/data/uniform.txt";
std::string archnom = "./data/uniform.txt";
std::string archnom = "../data/uniform.txt";
std::string archnom = "data/uniform.txt";
What is the problem here?
In a terminal, you can type ./build/a.out to launch the a.out program with ./ as the current working directory.
When you do this, relative filepaths that are used in your program are relative to the ./ dir -- not the one which contains the program.
For example, if I want to open ex.txt when running ./build/a.out (and ex.txt is in the same directory as build), my program should have the relative path ./ex.txt - not ../ex.txt.
std::string archnom = "../data/uniform.txt";
Tells the program that uniform.txt can be found by going back one directory and then up into data.
But in what directory does the program start looking? Good question. That location is called the Working Directory, and unfortunately it MOVES. Typically the working directory starts as the directory the program is run from, not where the program is. For added excitement your program can change the working directory while running.
So if your program is at /home/bob/code and the uniform.txt file is at /home/bob/data and you run the program from /home/bob/code with ./program all is good. The working directory is /home/bob/code and the program goes back one folder and then up into data.
What if you were in /home/bob/workspace and you ran ../code/program. The working directory is /home/bob/workspace and the program goes back one folder and into data.
But what if you run the program from / with /home/bob/code/program? The working directory is /. You can't really go back anywhere, can you?
Let's try a less extreme case: /etc. Program goes back to / and forward to... rats. No data directory.
If the uniform.txt file is always going to be in the same place and this place is guaranteed, use a fixed path. If uniform.txt is going to be somewhere near the installation directory of the program, your program needs to know where it is and that takes OS specific code.
You need to make sure the current working directory is where you expect it to be. You can do that by using _chdir (win32) or chdir (gcc) and by using argv[0] (which contains the path to the currently running executable).
I showed how to do this in my answer to another question here :
Change the current working directory in C++

How to reference a file to be opened in C++ given that its full path name will change from computer to computer?

Our Computer Science teacher has given us a project to make a fully functioning console application using C++. And I have started to make it. But I got stuck at some point. I want to open an editable text (.txt) file using the open() function. But I made a separate folder for all the text files. Usually I have to provide a full directory path in the open() function, which is F:\Work\C++\SchoolProject\TextFiles in my case. But what if I copy the SchoolProject folder in a portable drive and take it to my friend's home and try to run the program in their computer. Will it work? I'm asking because it is not necessary that they will have the Work folder in the F directory or maybe they may not have the F disk at all. So in that case the path will change. So what path I have to type in the open() function so that the program works in each and every computer without changing the address in the open() function every time I try to run the program in some other computer. A source code may be helpful with explanation. Thank You!
Instead of using absolute paths, you should use relative paths. When you run your program from a folder, this is your working path. You can then open files inside this folder or subfolders of this folder by passing only the file name or folder and file name to the open function. So instead of opening C:\... simply open someFolder\someFile.txt.
You could consider having the filename that you parse in as part of a command line argument, like this:
int main(int arg, char* args[]) {
FILE *newfile = fopen( args[1], "r");
}
You can not be sure all computers have the F: drive mapped correctly so it is better to use
Universal Naming Convention (UNC) names i.e. "\server\share\path\file".
A nice way to achieve the same is by using Boost Filesystem, but this makes your code more complicated since you are depending on an external library (read: the students might be confused). The documentation for Boost Filesystem is found here: http://www.boost.org/doc/libs/1_43_0/libs/filesystem/doc/index.htm

How to get the application running path at runtime in c++ [duplicate]

This question already has answers here:
Finding current executable's path without /proc/self/exe
(14 answers)
Closed 7 years ago.
Is there a way in C/C++ to find the location (full path) of the current executed program?
(The problem with argv[0] is that it does not give the full path.)
To summarize:
On Unixes with /proc really straight and realiable way is to:
readlink("/proc/self/exe", buf, bufsize) (Linux)
readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)
readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)
On Unixes without /proc (i.e. if above fails):
If argv[0] starts with "/" (absolute path) this is the path.
Otherwise if argv[0] contains "/" (relative path) append it to cwd
(assuming it hasn't been changed yet).
Otherwise search directories in $PATH for executable argv[0].
Afterwards it may be reasonable to check whether the executable isn't actually a symlink.
If it is resolve it relative to the symlink directory.
This step is not necessary in /proc method (at least for Linux).
There the proc symlink points directly to executable.
Note that it is up to the calling process to set argv[0] correctly.
It is right most of the times however there are occasions when the calling process cannot be trusted (ex. setuid executable).
On Windows: use GetModuleFileName(NULL, buf, bufsize)
Use GetModuleFileName() function if you are using Windows.
Please note that the following comments are unix-only.
The pedantic answer to this question is that there is no general way to answer this question correctly in all cases. As you've discovered, argv[0] can be set to anything at all by the parent process, and so need have no relation whatsoever to the actual name of the program or its location in the file system.
However, the following heuristic often works:
If argv[0] is an absolute path, assume this is the full path to the executable.
If argv[0] is a relative path, ie, it contains a /, determine the current working directory with getcwd() and then append argv[0] to it.
If argv[0] is a plain word, search $PATH looking for argv[0], and append argv[0] to whatever directory you find it in.
Note that all of these can be circumvented by the process which invoked the program in question. Finally, you can use linux-specific techniques, such as mentioned by emg-2. There are probably equivalent techniques on other operating systems.
Even supposing that the steps above give you a valid path name, you still might not have the path name you actually want (since I suspect that what you actually want to do is find a configuration file somewhere). The presence of hard links means that you can have the following situation:
-- assume /app/bin/foo is the actual program
$ mkdir /some/where/else
$ ln /app/bin/foo /some/where/else/foo # create a hard link to foo
$ /some/where/else/foo
Now, the approach above (including, I suspect, /proc/$pid/exe) will give /some/where/else/foo as the real path to the program. And, in fact, it is a real path to the program, just not the one you wanted. Note that this problem doesn't occur with symbolic links which are much more common in practice than hard links.
In spite of the fact that this approach is in principle unreliable, it works well enough in practice for most purposes.
Not an answer actually, but just a note to keep in mind.
As we could see, the problem of finding the location of running executable is quite tricky and platform-specific in Linux and Unix. One should think twice before doing that.
If you need your executable location for discovering some configuration or resource files, maybe you should follow the Unix way of placing files in the system: put configs to /etc or /usr/local/etc or in current user home directory, and /usr/share is a good place to put your resource files.
In many POSIX systems you could check a simlink located under /proc/PID/exe. Few examples:
# file /proc/*/exe
/proc/1001/exe: symbolic link to /usr/bin/distccd
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail
/proc/1043/exe: symbolic link to /usr/sbin/crond
Remember that on Unix systems the binary may have been removed since it was started. It's perfectly legal and safe on Unix. Last I checked Windows will not allow you to remove a running binary.
/proc/self/exe will still be readable, but it will not be a working symlink really. It will be... odd.
On Mac OS X, use _NSGetExecutablePath.
See man 3 dyld and this answer to a similar question.
For Linux you can find the /proc/self/exe way of doing things bundled up in a nice library called binreloc, you can find the library at:
http://autopackage.org/docs/binreloc/
I would
1) Use the basename() function: http://linux.die.net/man/3/basename
2) chdir() to that directory
3) Use getpwd() to get the current directory
That way you'll get the directory in a neat, full form, instead of ./ or ../bin/.
Maybe you'll want to save and restore the current directory, if that is important for your program.

std::ifstream::open() not working

I am developing a prototype for a game, and certain gameplay rules are to be defined in an ini file so that the game designers can tweak the game parameters without requiring help from me in addition to a re-compile. This is what I'm doing currently:
std::ifstream stream;
stream.open("rules.ini");
if (!stream.is_open())
{
throw new std::exception("Rule file could not be opened");
}
// read file contents here
stream.close();
However, my stream never opens succesfully. Diving deep into the STL source during debugging reveals that _getstream() (as defined in stream.c) keeps on returning NULL, but I just can't figure out why this is. Help, anyone?
Edit: Rules.ini is in the same directory as the .exe file.
You are assuming that the working directory is the directory that your executable resides in. That is a bad assumption.
Your executable can be run from any working directory, so it's usually a bad idea to hard-code relative paths in your software.
If you want to be able to access files relative to the location of your executable, you should first determine the path of your executable and create a fully qualified path from that.
You can get the name of your executable by examining the argv[0] parameter passed to main(). Alternatively, if you're on Windows, you can get it with GetModuleFileName() by passing NULL as the first parameter.
Is the scope of your open stream correct.
"rules.ini" isn't a full path so it has to be relative so what is it relative to. Or do you need to use full path there.
(wild assumption here) you are using visual studio. During debug, your program is going to search the project directory for "rules.ini"
However, if you try executing your program from "myproject/debug/myexe.exe", it should run fine because it is going to search "/debug" for rules.ini
Like its been mentionned you should specify the full path because relative path tend to lead to errors