c++ bash add to PATH - c++

I'm trying to make an executable that appends export PATH="$PATH:/my/current/directory" to my ~/.bash_profile ( I'm on OSX 10.9.2 compiling w/ g++.) For now I'm just trying to get the current working directory to reach the current shell (I was getting it to a subshell with setenv() I think but I don't know if that helps) and I can take it from there.
OK, source code:
#include <iostream>
#include <string>
using namespace std;
int main(){
/*Add current directory to path (locally)*/
string CWD = getenv("PWD");
string endquote = "\"";
string mystring = "PATH=\"$PATH:";
mystring += CWD;
mystring += endquote;
// JUST TRYING TO GET THE PATH TO UPDATE IN SHELL
// WILL EVENTUALLY UPDATE THIS TO GO INTO .bash_profile
system(mystring);
system("echo $PATH");
return 0;
}
and error:
setup.cpp:11:3: error: no matching function for call to 'system'
system(mystring);
^~~~~~
/usr/include/stdlib.h:177:6: note: candidate function not viable: no known conversion from 'string' (aka 'basic_string<char,
char_traits<char>, allocator<char> >') to 'const char *' for 1st argument
int system(const char *) __DARWIN_ALIAS_C(system);
^
1 error generated.
Is a constructor the way to go here (to change const char * to string)? I don't know much about them but what the heck, I've spent hours on this already so I might as well spend some more time right?

I think that you should rely less on environment variables and external programs, and more on what you can programmatically find and do with the C++ libraries and POSIX APIs. In this case, you don't need much, really:
getuid to find the current user;
getpwuid to find the current user's home directory;
getcwd to get the current working directory;
pretty standard file output stream stuff.
This six-line program appends export PATH="$PATH:current_working_path" to ~/.bash_profile.
#include <fstream>
#include <string>
#include <pwd.h>
#include <unistd.h>
#include <sys/param.h>
using namespace std;
int main()
{
char path[MAXPATHLEN];
struct passwd* user_info = getpwuid(getuid());
string user_directory = user_info->pw_dir;
string current_directory = getcwd(path, sizeof path);
ofstream bash_profile(user_directory + "/.bash_profile", ios_base::app);
bash_profile << "export PATH=\"$PATH:" << current_directory << '"' << endl;
}
Note that this will not affect the bash process from which you call the executable. Environment variables are strictly inherited: modifying them from a child process will not affect the parent process. There is no way to make that happen from a child process, as far as I know. (The commands that let you manipulate the environment of the bash process are built into the shell and do not run as a separate process, precisely for this reason.)
However, you could make it print the same string to the standard output and run it with backticks, or run source ~/.bash_profile after you run this program.

You'll need to call it
system(mystring.c_str());
The system() function has no notion about std::string, it requires a const char* parameter, which can be aquired from a std::string using the c_str() method.
Also note that the applied system() command doesn't export the path anywhere than to the (sub-)shell started from it, neither it goes to your local profile.
To really achieve what you intend, you'll need to open and modify your ~/.bashrc file (you can simply append another export PATH=$PATH:<your stuff> line there)! (see here for more information)

Related

Open an ofstream with tilde (~) in path name [duplicate]

This question already has an answer here:
C++ paths beginning with ~ [duplicate]
(1 answer)
Closed 3 years ago.
I have to open some file for writing, and its name contains the tilde sign (~). The following code fails to create the desired text file. If I replace the ~ with /home/oren then everything works fine.
#include <fstream>
#include <string>
const std::string dirname = "/home/oren/GIT/";
// const std::string dirname = "~/GIT/";
const std::string filename = "someTextFile";
int main(int argc, char **argv)
{
std::ofstream log_file(dirname+filename+".txt");
log_file << "lorem ipsum";
log_file.close();
}
Is there any way to (easily) handle a file with ~ in its name?
The ~ shortcut in paths is not something magical at the filesystem level, opening ~/GIT literally tries to access ~/GIT, i.e: a file named GIT in the ~ directory. You can verify this by creating ~ and GIT first.
In the command line, ~ is typically resolved by your shell. e.g: in bash:
~ : The value of $HOME
https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html
Therefore, to achieve the same effect, you have to query the $HOME envvar, and replace the usage of leading ~/ in the path:
#include <stdlib.h>
const char* home = getenv("HOME")
if (home) { /* replace ~/ with home */ }
In addition, on linux, the wordexp function can be used to perform these replacements (~ to current user, ~other_user to home of other user)
The tilde is part of the shell expansion, it's not something handled by the underlying operating system. You need to resolve it yourself.
One simple way is to replace leading "~/" with the contents of the environment variable HOME (if it exists).
The tilde is expanded to the home directory by the shell. The iostreams don't use a shell, so you have to take care of the expansion for them. Tilde is a actually a valid character to use in a file name so without expansion, a file is created into a directory named ~ - which fails if the directory does not exist.
There is no standard way in C++ for shell expansions, nor a way to get the home directory, but there are several ways in POSIX systems:
wordexp is probably one of the most useful functions for this case. You can pass the path to the function and it will expand the tilde, as well as variables and braces. An example:
std::string full = dirname+filename+".txt"
wordexp_t p;
wordexp(full.c_str(), &p, 0);
std::string expanded = p.we_wordv[p.we_offs];
wordfree(&p);
std::ofstream log_file(expanded);
Other alternatives:
getpwuid gives you a structure with the home directory as a member. This can be used to get home directory of another user as well, in case that is needed.
HOME environment variable should also be available. It can be accessed with the standard std::getenv.

How to get current working directory of a c++ file

I'm using the following code to get the current working directory of a C++ file
//Getting current working directory
getcwd( wd, 1024 );
std::string cwd = wd;
If the function in this file is called from another function, the current working directory becomes the path of the calling function.
How do I get the current directory of where the original file/binary is located?
I'm adding details as the question was confusing.
I've created a .so file which is called from Scilab. If I use readlink(), I get the path to be /usr/bin/scilab-bin which is not what I want. How do I get the path of the so file, the current function is in?
This question is a near-duplicate of How to check what shared libraries are loaded at run time for a given process?. The information you need is only available from the /proc file system, telling you what files have been dynamically mapped into memory in your process.
You mention .so files in the comments, so I will assume your target is GNU/Linux. You can use the dladdr1 function to obtain the pathname of the .so file which contains an address, like this:
#include <string>
#include <vector>
#include <dlfcn.h>
#include <libgen.h>
#include <link.h>
#include <string.h>
static std::string
get_path ()
{
Dl_info info;
void *extra_info;
if (dladdr1 (reinterpret_cast <void *> (&get_path),
&info, &extra_info, RTLD_DL_LINKMAP) == 0)
// Some form of error handling.
return "";
link_map *lm = static_cast<link_map *> (extra_info);
// Make a copy of l_name because dirname modifies its argument.
std::vector<char> buffer (lm->l_name, lm->l_name + strlen (lm->l_name) + 1);
return dirname (buffer.data ());
}
The first argument to dladdr1 is quite arbitrary, but it is better not to use a symbol exported from the DSO because it could end up referring to something in a different object (due to PLT stubs and copy relocations).

execve(...) does not execute program despite passing in PATH variable

I'm executing a simple shell program from the directory:
/home/user/shell.exe
Using the code below, I'm able to run files that are in the same folder as my shell executable, but am unable to run programs such as ls.exe.
The tokens container includes the file name as the first element and any subsequent tokens (such as "-l" in the input "ls.exe -l") in the following elements.
if (fork())
{
int status;
wait(&status);
}
else
{
std::vector<const char*> exeArgs;
std::vector<const char*> envArgs;
std::for_each(tokens.begin(), tokens.end(),
[&exeArgs](const string& elem){ exeArgs.push_back(elem.c_str()); }
);
exeArgs.push_back(nullptr);
string path = "PATH=";
path.append(getenv("PATH"));
envArgs.push_back(path.c_str());
envArgs.push_back(nullptr);
if (execve(exeArgs[0], const_cast<char *const *>(&exeArgs[0]),
const_cast<char *const *>(&envArgs[0])))
{
std::cout << word << ": command not found" << std::endl;
exit(0);
}
}
I've spent countless hours just googling and reading the man pages over and over but can't seem to get a clue why this code doesn't work.
The idea is that my shell program should allow users to set the PATH variable and then execute programs with that PATH variable, which is why I have to make execve() work properly instead of just using execvp().
I have a map of shell variables in a separate part of the file but since I can't even get this to work, I thought it would be pointless to include that.
You do know that the exec family of functions replaces the current process with the image of the new program? That's why it's so common to use fork before exec.
Armed with that knowledge, it's easy to find a solution for you, and how you can use execvp (which you need to use, execve doesn't really use the environment you pass, it just passes it along to the new program): You fork and use setenv to set the PATH of the new process, before calling execvp.

Manually getting the output instead of output redirection in cmd line

I have a C++ program which has the prototype of the main function as follows:
int main(int argc, char * argv[])
The code hasn't been written by me, but this is a single C file available here.
When I compile this code, and through the command line run it as:
someexe in.txt > out.txt
This gives me an output out.txt which is generated in the same directory by operating on some input from in.txt.
someexe in.txt out.txt
This gives me an output on the command line itself. (without using > operator)
However, instead of passing the command line argument and without using the output redirection > operator, I have been trying to call the main function from another function and passing the parameters myself. If I pass an array of char* {fileDirName, in.txt}, I am not sure how to go about generating an out.txt (since I think > output redirection is an operating system level function available in command line).
Any suggestions would be greatly appreciated
The program in the link is readily available as copy paste and can be tried (main function is written at the last in the above program)
Assuming the aim is to mimic the output redirection feature (> out.txt) of the shell you can do something like:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <assert.h>
#include <unistd.h>
#include <iostream>
int main() {
int fd = open("out.txt", O_WRONLY|O_CREAT|O_TRUNC, 0660);
assert(fd >= 0);
const int ret = dup2(fd, 1);
assert(ret >= 0);
std::cout << "Hello redirected world!" << std::endl;
close(fd);
}
You can do similar for stdin also, to mimic the input redirection (< in.txt). These will be preserved across calls to exec() too.
Of course it would be simpler to modify the program to write to the place you wanted given you have the source available.
Note though that dup2(), which "swap" the stdout fd for the one we just opened is non-portable. IIRC open() (as opposed to fopen()) is UNIX specific also)
You can't call another main() from inside the source another program - main() is special.
If you want to reuse this source code as a library you need to rename main() to something else.
However if it is handling input from either a pipe or a file (eg myprog < input.txt or myprog input.txt) in the normal Unix way then that's a little trickier to handle transparently.
The best way would be to call the compiled program as a separate process from within your new program, passing the correct commandline parameters - see the exec() family of calls

How do I get the directory that a program is running from?

Is there a platform-agnostic and filesystem-agnostic method to obtain the full path of the directory from where a program is running using C/C++? Not to be confused with the current working directory. (Please don't suggest libraries unless they're standard ones like clib or STL.)
(If there's no platform/filesystem-agnostic method, suggestions that work in Windows and Linux for specific filesystems are welcome too.)
Here's code to get the full path to the executing app:
Variable declarations:
char pBuf[256];
size_t len = sizeof(pBuf);
Windows:
int bytes = GetModuleFileName(NULL, pBuf, len);
return bytes ? bytes : -1;
Linux:
int bytes = MIN(readlink("/proc/self/exe", pBuf, len), len - 1);
if(bytes >= 0)
pBuf[bytes] = '\0';
return bytes;
If you fetch the current directory when your program first starts, then you effectively have the directory your program was started from. Store the value in a variable and refer to it later in your program. This is distinct from the directory that holds the current executable program file. It isn't necessarily the same directory; if someone runs the program from a command prompt, then the program is being run from the command prompt's current working directory even though the program file lives elsewhere.
getcwd is a POSIX function and supported out of the box by all POSIX compliant platforms. You would not have to do anything special (apart from incliding the right headers unistd.h on Unix and direct.h on windows).
Since you are creating a C program it will link with the default c run time library which is linked to by ALL processes in the system (specially crafted exceptions avoided) and it will include this function by default. The CRT is never considered an external library because that provides the basic standard compliant interface to the OS.
On windows getcwd function has been deprecated in favour of _getcwd. I think you could use it in this fashion.
#include <stdio.h> /* defines FILENAME_MAX */
#ifdef WINDOWS
#include <direct.h>
#define GetCurrentDir _getcwd
#else
#include <unistd.h>
#define GetCurrentDir getcwd
#endif
char cCurrentPath[FILENAME_MAX];
if (!GetCurrentDir(cCurrentPath, sizeof(cCurrentPath)))
{
return errno;
}
cCurrentPath[sizeof(cCurrentPath) - 1] = '\0'; /* not really required */
printf ("The current working directory is %s", cCurrentPath);
This is from the cplusplus forum
On windows:
#include <string>
#include <windows.h>
std::string getexepath()
{
char result[ MAX_PATH ];
return std::string( result, GetModuleFileName( NULL, result, MAX_PATH ) );
}
On Linux:
#include <string>
#include <limits.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
ssize_t count = readlink( "/proc/self/exe", result, PATH_MAX );
return std::string( result, (count > 0) ? count : 0 );
}
On HP-UX:
#include <string>
#include <limits.h>
#define _PSTAT64
#include <sys/pstat.h>
#include <sys/types.h>
#include <unistd.h>
std::string getexepath()
{
char result[ PATH_MAX ];
struct pst_status ps;
if (pstat_getproc( &ps, sizeof( ps ), 0, getpid() ) < 0)
return std::string();
if (pstat_getpathname( result, PATH_MAX, &ps.pst_fid_text ) < 0)
return std::string();
return std::string( result );
}
If you want a standard way without libraries: No. The whole concept of a directory is not included in the standard.
If you agree that some (portable) dependency on a near-standard lib is okay: Use Boost's filesystem library and ask for the initial_path().
IMHO that's as close as you can get, with good karma (Boost is a well-established high quality set of libraries)
I know it is very late at the day to throw an answer at this one but I found that none of the answers were as useful to me as my own solution. A very simple way to get the path from your CWD to your bin folder is like this:
int main(int argc, char* argv[])
{
std::string argv_str(argv[0]);
std::string base = argv_str.substr(0, argv_str.find_last_of("/"));
}
You can now just use this as a base for your relative path. So for example I have this directory structure:
main
----> test
----> src
----> bin
and I want to compile my source code to bin and write a log to test I can just add this line to my code.
std::string pathToWrite = base + "/../test/test.log";
I have tried this approach on Linux using full path, alias etc. and it works just fine.
NOTE:
If you are on windows you should use a '\' as the file separator not '/'. You will have to escape this too for example:
std::string base = argv[0].substr(0, argv[0].find_last_of("\\"));
I think this should work but haven't tested, so comment would be appreciated if it works or a fix if not.
Filesystem TS is now a standard ( and supported by gcc 5.3+ and clang 3.9+ ), so you can use current_path() function from it:
std::string path = std::experimental::filesystem::current_path();
In gcc (5.3+) to include Filesystem you need to use:
#include <experimental/filesystem>
and link your code with -lstdc++fs flag.
If you want to use Filesystem with Microsoft Visual Studio, then read this.
No, there's no standard way. I believe that the C/C++ standards don't even consider the existence of directories (or other file system organizations).
On Windows the GetModuleFileName() will return the full path to the executable file of the current process when the hModule parameter is set to NULL. I can't help with Linux.
Also you should clarify whether you want the current directory or the directory that the program image/executable resides. As it stands your question is a little ambiguous on this point.
On Windows the simplest way is to use the _get_pgmptr function in stdlib.h to get a pointer to a string which represents the absolute path to the executable, including the executables name.
char* path;
_get_pgmptr(&path);
printf(path); // Example output: C:/Projects/Hello/World.exe
Maybe concatenate the current working directory with argv[0]? I'm not sure if that would work in Windows but it works in linux.
For example:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char **argv) {
char the_path[256];
getcwd(the_path, 255);
strcat(the_path, "/");
strcat(the_path, argv[0]);
printf("%s\n", the_path);
return 0;
}
When run, it outputs:
jeremy#jeremy-desktop:~/Desktop$ ./test
/home/jeremy/Desktop/./test
For Win32 GetCurrentDirectory should do the trick.
You can not use argv[0] for that purpose, usually it does contain full path to the executable, but not nessesarily - process could be created with arbitrary value in the field.
Also mind you, the current directory and the directory with the executable are two different things, so getcwd() won't help you either.
On Windows use GetModuleFileName(), on Linux read /dev/proc/procID/.. files.
Just my two cents, but doesn't the following code portably work in C++17?
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main(int argc, char* argv[])
{
std::cout << "Path is " << fs::path(argv[0]).parent_path() << '\n';
}
Seems to work for me on Linux at least.
Based on the previous idea, I now have:
std::filesystem::path prepend_exe_path(const std::string& filename, const std::string& exe_path = "");
With implementation:
fs::path prepend_exe_path(const std::string& filename, const std::string& exe_path)
{
static auto exe_parent_path = fs::path(exe_path).parent_path();
return exe_parent_path / filename;
}
And initialization trick in main():
(void) prepend_exe_path("", argv[0]);
Thanks #Sam Redway for the argv[0] idea. And of course, I understand that C++17 was not around for many years when the OP asked the question.
Just to belatedly pile on here,...
there is no standard solution, because the languages are agnostic of underlying file systems, so as others have said, the concept of a directory based file system is outside the scope of the c / c++ languages.
on top of that, you want not the current working directory, but the directory the program is running in, which must take into account how the program got to where it is - ie was it spawned as a new process via a fork, etc. To get the directory a program is running in, as the solutions have demonstrated, requires that you get that information from the process control structures of the operating system in question, which is the only authority on this question. Thus, by definition, its an OS specific solution.
#include <windows.h>
using namespace std;
// The directory path returned by native GetCurrentDirectory() no end backslash
string getCurrentDirectoryOnWindows()
{
const unsigned long maxDir = 260;
char currentDir[maxDir];
GetCurrentDirectory(maxDir, currentDir);
return string(currentDir);
}
For Windows system at console you can use system(dir) command. And console gives you information about directory and etc. Read about the dir command at cmd. But for Unix-like systems, I don't know... If this command is run, read bash command. ls does not display directory...
Example:
int main()
{
system("dir");
system("pause"); //this wait for Enter-key-press;
return 0;
}
Works with starting from C++11, using experimental filesystem, and C++14-C++17 as well using official filesystem.
application.h:
#pragma once
//
// https://en.cppreference.com/w/User:D41D8CD98F/feature_testing_macros
//
#ifdef __cpp_lib_filesystem
#include <filesystem>
#else
#include <experimental/filesystem>
namespace std {
namespace filesystem = experimental::filesystem;
}
#endif
std::filesystem::path getexepath();
application.cpp:
#include "application.h"
#ifdef _WIN32
#include <windows.h> //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h> //readlink
#endif
std::filesystem::path getexepath()
{
#ifdef _WIN32
wchar_t path[MAX_PATH] = { 0 };
GetModuleFileNameW(NULL, path, MAX_PATH);
return path;
#else
char result[PATH_MAX];
ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
return std::string(result, (count > 0) ? count : 0);
#endif
}
For relative paths, here's what I did. I am aware of the age of this question, I simply want to contribute a simpler answer that works in the majority of cases:
Say you have a path like this:
"path/to/file/folder"
For some reason, Linux-built executables made in eclipse work fine with this. However, windows gets very confused if given a path like this to work with!
As stated above there are several ways to get the current path to the executable, but the easiest way I find works a charm in the majority of cases is appending this to the FRONT of your path:
"./path/to/file/folder"
Just adding "./" should get you sorted! :) Then you can start loading from whatever directory you wish, so long as it is with the executable itself.
EDIT: This won't work if you try to launch the executable from code::blocks if that's the development environment being used, as for some reason, code::blocks doesn't load stuff right... :D
EDIT2: Some new things I have found is that if you specify a static path like this one in your code (Assuming Example.data is something you need to load):
"resources/Example.data"
If you then launch your app from the actual directory (or in Windows, you make a shortcut, and set the working dir to your app dir) then it will work like that.
Keep this in mind when debugging issues related to missing resource/file paths. (Especially in IDEs that set the wrong working dir when launching a build exe from the IDE)
A library solution (although I know this was not asked for).
If you happen to use Qt:
QCoreApplication::applicationDirPath()
Path to the current .exe
#include <Windows.h>
std::wstring getexepathW()
{
wchar_t result[MAX_PATH];
return std::wstring(result, GetModuleFileNameW(NULL, result, MAX_PATH));
}
std::wcout << getexepathW() << std::endl;
// -------- OR --------
std::string getexepathA()
{
char result[MAX_PATH];
return std::string(result, GetModuleFileNameA(NULL, result, MAX_PATH));
}
std::cout << getexepathA() << std::endl;
This question was asked 15 years ago, so the existing answers are now incorrect. If you're using C++17 or greater, the solution is very straightforward today:
#include <filesystem>
std::cout << std::filesystem::current_path();
See cppreference.com for more information.
On POSIX platforms, you can use getcwd().
On Windows, you may use _getcwd(), as use of getcwd() has been deprecated.
For standard libraries, if Boost were standard enough for you, I would have suggested Boost::filesystem, but they seem to have removed path normalization from the proposal. You may have to wait until TR2 becomes readily available for a fully standard solution.
Boost Filesystem's initial_path() behaves like POSIX's getcwd(), and neither does what you want by itself, but appending argv[0] to either of them should do it.
You may note that the result is not always pretty--you may get things like /foo/bar/../../baz/a.out or /foo/bar//baz/a.out, but I believe that it always results in a valid path which names the executable (note that consecutive slashes in a path are collapsed to one).
I previously wrote a solution using envp (the third argument to main() which worked on Linux but didn't seem workable on Windows, so I'm essentially recommending the same solution as someone else did previously, but with the additional explanation of why it is actually correct even if the results are not pretty.
As Minok mentioned, there is no such functionality specified ini C standard or C++ standard. This is considered to be purely OS-specific feature and it is specified in POSIX standard, for example.
Thorsten79 has given good suggestion, it is Boost.Filesystem library. However, it may be inconvenient in case you don't want to have any link-time dependencies in binary form for your program.
A good alternative I would recommend is collection of 100% headers-only STLSoft C++ Libraries Matthew Wilson (author of must-read books about C++). There is portable facade PlatformSTL gives access to system-specific API: WinSTL for Windows and UnixSTL on Unix, so it is portable solution. All the system-specific elements are specified with use of traits and policies, so it is extensible framework. There is filesystem library provided, of course.
The linux bash command
which progname will report a path to program.
Even if one could issue the which command from within your program and direct the output to a tmp file and the program
subsequently reads that tmp file, it will not tell you if that program is the one executing. It only tells you where a program having that name is located.
What is required is to obtain your process id number, and to parse out the path to the name
In my program I want to know if the program was
executed from the user's bin directory or from another in the path
or from /usr/bin. /usr/bin would contain the supported version.
My feeling is that in Linux there is the one solution that is portable.
Use realpath() in stdlib.h like this:
char *working_dir_path = realpath(".", NULL);
The following worked well for me on macOS 10.15.7
brew install boost
main.cpp
#include <iostream>
#include <boost/filesystem.hpp>
int main(int argc, char* argv[]){
boost::filesystem::path p{argv[0]};
p = absolute(p).parent_path();
std::cout << p << std::endl;
return 0;
}
Compiling
g++ -Wall -std=c++11 -l boost_filesystem main.cpp