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.
Related
I'm currently working on creating a simple Linux shell. I have a Shell class, with a vector I am treating as a sort of queue. The user could input something like
$ ls -l /
and the program would put this into my vector through a private method, with "ls" being at the 0th position, "/" in the 2nd position, you get the idea. Then I go into my "interpretation" stage:
First I check to make sure the user has put something into the prompt.
Then it checks to see if the user typed in the word "exit", and if so it exits.
If neither of these checks go off, the program forks. It then checks to make sure the fork didn't fail.
This is where I'm stumbling. If the second to last character string in the queue is ">" we know that the last string is going to be a file that we need to create and/or open (and/or truncate?) and write the results of the command given by the user to said file.
I need to do this using the bash command open and using flags, I cannot use c++ openers like ofstream. I then need to execute the input using the bash command exec.
Below is how my code has this written as of the submission of this post.
if (commandQueue.size() >= 3 && commandQueue.at(commandQueue.size() - 2) == ">") {
//commandQueue.at(commandQueue.size() - 1) is fileName open
//commandQueue.at(0) is name of program to run exec
//remaining substrings are args
}; //commandQueue.at(0) is name of program to run exec
// remaining substrings are args
How should I format these commands? fork was easy, it was just
pid_t pid = fork();
and a check. But I'm unsure as to how I'm supposed to open a file using flags, or how to format the exec command. I appreciate any help I receive, thank you.
Edit: I should probably put the second part of the if statement I provided in an else statement, or else return from the if statement.
Edit 2: I should probably mention I'm pretty new to bash commands, I've used a few of them before, but this is the first program I've written using them inside.
Edit 3 (reply to Galik):
Like, if you were using execve you'd have something like
const char *path = "/bin/ls";
char *const argv[] = { "/bin/ls", "/", NULL };
execve(path, argv, environ);
(this is c code though, not c++) you see the "execve(path, argv, environ)"? That's what I'm curious about.
The man page for open has
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
but since I'm not using c, and I have my user's input stored as strings, I'm not sure how to deal with the const char*, or the flags or mode.
I am trying to get my C++ program to open up an existing Excel spreadsheet (along with a bunch of applications), however it keeps returning an error that a file does not exist. I am using the following code:
int main(){
system("open ~/path/file");
//--open applications using same command--//
}
The file is definitely there and this command works to open all the applications, so I'm not sure what I am doing wrong.
Thanks in advance!!
Very probably, the system /bin/sh -which by definition is used by system(3)- does not expand ~.
You might try something like
char cmd[256];
snprintf(cmd, sizeof(cmd), "open %s/path/file", getenv("HOME"));
if (0 != system(cmd))
{ fprintf(stderr, "%s failed\n", cmd); exit(EXIT_FAILURE); };
since interactive shells usually expand ~ as $HOME and HOME is generally an environment variable.
(With C++, you could use std::string operations instead of snprintf)
My snprintf + system trick is not at all failproof. If $HOME contains spaces or bizarre characters like ; or ', it wont work. And snprintf itself might fail (e.g. because $HOME is huge).
Of course, you'll better test before that getenv("HOME") is not NULL. You might use getpwuid(3) with getuid(2) if getenv("HOME") fails by returning NULL.
On Linux you probably want xdg-open instead of open.
So i have an issue that i have an application that gets started. Then through a test i need to turn it off and start it again. But it needs t obe done without hard coding.
So is there a way of finding where a process was run from? I can find a list of all processes running but dont know if this is even possible.
EDIT: Its on a windows 7 OS.
QueryFullProcessImageName() will provide the path to the executable image for a process:
#include <windows.h>
#include <iostream>
int main()
{
char exe_path[MAX_PATH];
DWORD exe_path_size = MAX_PATH;
if (QueryFullProcessImageName(GetCurrentProcess(),
0,
exe_path,
&exe_path_size))
{
std::cout << exe_path << "\n";
}
return 0;
}
Easy and portable way would be using argv[0].
It returns the full .exe file path which is all you need
First, what do you mean by "find where the process is run from"? I'm assuming you mean the parent's process id, but it could mean current working directory, ip of remote call, etc...
To find the parent's process id, look into getppid().
Edit: this assumes that you (like any sane programmer) are using a unix-like machine.
Edit #2: You're on Windows, so I have no idea.
Edit #3: Since you're looking for the path to the program you are executing, use argv[0]. The first command line arg to int main(int argc, char* argv[]) is always the path to the binary.
I'm building a plugin using Firebreath. I made a personal method in ABCPluginAPI.cpp called exe_program() and I would like to call another program using popen called my_program. All the files are into firebreath/projects/ABCPlugin/.
My method is:
string ABCPluginAPI::exe_program()
{
FILE * pPipe;
fd_set readfd;
char buff[1024];
char command[128];
int ret;
strcpy(command, "my_program");
if (!(pPipe = popen(command, "r"))) {
// Problem to execute the command
return "failed";
}
while(fgets(buff, sizeof(buff), pPipe)!=NULL){
cout << buff;
return buff;
}
}
The problem I have is that the plugin is not running my_program, actually if I execute the pwd command, it shows my $HOME directory. pwd works because is a general command but I don't want to put my program into $PATH variable because this plugin must be portable.
Probably Firebreath use a special directory to refer to this kind of files or something similar.
You probably need to specify a full path and filename of the application you want to run; the current working directory is not garanteed to always be the same value.
From the Tips and Tricks page of firebreath.org there is code you can add to your PluginCore-derived object that will give you the full path and filename of your plugin file:
// From inside your Plugin class (that extends PluginCore)
std::string MyPlugin::getFilesystemPath()
{
return m_filesystemPath;
}
You can take that path, strip off the last part, and change it to your executable filename; as long as you place the executable in the same directory as your plugin that should work fine. Alternately you could install it in some other well-known location.
Note that to call a method on your main Plugin object from your JSAPI object there should be a helper method getPlugin() on your JSAPI object (if you used fbgen to generate it):
std::string pluginPath = getPlugin()->getFilesystemPath();
Hope that helps
Is there an exec variant that will use the current application directory to locate the target program?
I am using C++ and Qt to implement a "last ditch" error reporting system. Using Google Breakpad, I can create a minidump and direct execution to a handler. Because my application is in an unstable state, I just want to fork and start a separate error handling process using minimal dependencies. The error reporting application will be deployed in the same directory as the application executable.
I am quite unfamiliar with the fork and exec options, and am not finding an exec option that includes the current application directory in the search path. Here is what I have so far:
static bool dumpCallback(const char* /*dump_path*/,
const char* /*minidump_id*/,
void* /*context*/,
bool succeeded)
{
pid_t pid = fork();
if (pid == 0)
{
// This is what I would *like* to work.
const char* error_reporter_path = "error_reporter";
// This works, but requires hard-coding the entire path, which seems lame,
// and really isn't an option, given our deployment model.
//
// const char* error_reporter_path = "/path/to/app/error_reporter";
// This also works, but I don't like the dependency on QApplication at this
// point, since the application is unstable.
//
// const char* error_reporter_path =
// QString("%1/%2")
// .arg(QApplication::applicationDirPath())
// .arg("error_reporter").toLatin1().constData();
execlp(error_reporter_path,
error_reporter_path,
(char *) 0);
}
return succeeded;
}
Any other suggestions on best practices for using fork and exec would be appreciated as well; this is my first introduction to using them. I'm only concerned about Linux (Ubuntu, Fedora) at this point; I will work on handlers for other operating systems later.
What you asked for is actually quite easy:
{
pid_t pid = fork();
if (pid == 0)
{
const char* error_reporter_path = "./error_reporter";
execl(error_reporter_path,
error_reporter_path,
(char *) 0);
_exit(127);
}
else
return pid != -1;
}
but it doesn't do what you want. The current working directory is not necessarily the same thing as the directory containing the current executable -- in fact, under almost all circumstances, it won't be.
What I would recommend you do is make error_reporter_path a global variable, and initialize it at the very beginning of main, using your "option 2" code
QString("%1/%2")
.arg(QApplication::applicationDirPath())
.arg("error_reporter").toLatin1().constData();
The QString object (not just its constData) then has to live for the lifetime of the program, but that shouldn't be a problem. Note that you should be converting to UTF-8, not Latin1 (I guess QString uses wide characters?)
I think you have 2 choices:
Add '.' to $PATH.
Prepend the result of getcwd() to the executable name.
You should build the path to your helper executable at your program's startup, and save it somewhere (in a global or static variable). If you only need to run on Linux, you can do this by reading /proc/self/exe to get the location of your executable. Something like this:
// Locate helper binary next to the current binary.
char self_path[PATH_MAX];
if (readlink("/proc/self/exe", self_path, sizeof(self_path) - 1) == -1) {
exit(1);
}
string helper_path(self_path);
size_t pos = helper_path.rfind('/');
if (pos == string::npos) {
exit(1);
}
helper_path.erase(pos + 1);
helper_path += "helper";
Excerpted from a full working example here: http://code.google.com/p/google-breakpad/source/browse/trunk/src/client/linux/minidump_writer/linux_dumper_unittest.cc#92
Never, ever, under any circumstances add "." to $PATH !!
If you prepend getcwd() to the executable name (argv[0]), you have to do is as the first thing in main, before anything has the chance to change the current working directory. Then you have to consider what to do about symbolic links in the resulting filename. And even after that you can never be sure that argv[0] is set to the command used to execute your program
Option 3:
Hardcode the full filename in your executable, but use the configure script to set the filename. (You are using a configure script, right?)
Option 4;
Don't call exec. You don't have to call exec after a fork. Just pretend you have just entered "main", and call "exit" when your error reporting has finished.