How to use standard input '<' in execl? - c++

I want to achieve the equivalent of "./myfile < input.txt" using execl():
execl("path/myfile", ",myfile", "< input.txt");
execl("/home/user/Desktop/Fuzzer/clear/easy_fuzzer/buf", "/home/user/Desktop/Fuzzer/clear/easy_fuzzer/buf", "buf < input", NULL);
execlp("/home/user/Desktop/Fuzzer/clear/easy_fuzzer/buf", "/home/user/Desktop/Fuzzer/clear/easy_fuzzer/buf", "input");
but the command fails...
I want 'input.txt' and '<' command through myfile using execl — how do I do it?

Your code has to do the I/O redirection before you run the execl() code.
If you want to achieve the effect of a shell running:
/user/Desktop/Fuzzer/clear/easy_fuzzer/buf < input
then you will need to write something like this in the child code:
const char *filename = "input"; // or "input.txt" — the question uses both
int fd = open(file, O_RDONLY);
if (fd < 0)
err_syserr("failed to open file %s for reading\n", filename);
if (dup2(fd, STDIN_FILENO) < 0)
err_syserr("failed to redirect %s to standard input\n", filename);
close(fd); // In theory, it could fail, but there isn't much you can do about it
const char *cmdpath = "/home/user/Desktop/Fuzzer/clear/easy_fuzzer/buf";
execl(cmdpath, "buf", (char *)NULL);
err_syserr("failed to execute program %s\n", cmdpath);
This should normally all be in the code executed by the child.
You can find the code for the err_syserr() function in stderr.c and stderr.h from https://github.com/jleffler/soq/tree/master/src/libsoq. One line error handling makes it less onerous than writing out multiple lines. Note that there's no reason to check the return value from any of the exec*() functions. If the function returns, it failed. If it succeeds, there's a different process running in place of the current process.
If you like doing things the long-winded way, you can investigate whether your system supports posix_spawn() and its colleagues. You can do all sorts of things by setting up appropriate sequences of attributes. For my money, it is far simpler and clearer to write the code as shown above.
I would probably not use execl() — I'd probably use execv() (or perhaps execvp()) because it allows the argument list to be fixed at run-time instead of mandating that it is fixed at compile time. The code passes buf as the value for argv[0] to the executed program. If you want the full path name as argv[0] you can do that.
Note that if the file name part of the first argument to execlp() (or execvp(), or any other path-searching exec*() function) contains any / at all, then there is no path-based search performed, so it is not appropriate to use them if the command name is an absolute path name as in the example.

Related

How do I get the content of llvm::MemoryBuffer when reading STDIN?

I am using llvm::MemoryBuffer::getFileOrSTDIN("-") and, according to the specification, it should Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
Now, in the following context:
auto Source = llvm::MemoryBuffer::getFileOrSTDIN(File);
if (std::error_code err = Source.getError()) {
llvm::errs() << err.message();
} else{
someFunction(std::move(*Source), File, makeOutputWriter(Format, llvm::outs()),
IdentifiersOnly, DumpAST);
}
it blocks on the first line (when File == "-"); as expected as the STDIN never closes.
When a special *char appears in STDIN, let's say <END_CHAR>, I know that I am finished reading for a given task. How could I close the STDIN in this situations and move on to someFunction ?
Thanks,
You can always close the stdin file descriptor using close, i.e. close(0). If you check llvm::MemoryBuffer's source, you'll see that getFileOrSTDIN() basically boils down to a call to llvm::MemoryBuffer::getMemoryBufferForStream() with the first argument (the file descriptor) set to 0.
Also, see this SO answer.
The special character to close the standard input is ctrl-d (in *nix at least) on the command line (have a look here).

How do I add file paths as nodes to a tree or stack in C++

I have a project to search, rename or delete files and folders on a selected drive on the computer using a data structure(A tree, a stack, or a queue). My question is, how do I add file paths and directories as nodes in C++?
Comment in other answer suggests using one of the exec() functions. Then parsing and studying the output.
I approve of that idea, but I find it easier to use popen(). Each of the following examples are part of the Linux API, so the calls are c compatible and can be used directly by C++. I expect popen() will be available on other OS's.
To clarify,
1) popen() is a function call for your C++ code to invoke.
2) You will also need to create strings for your OS to generate the lists you want, and submit them to your invocation of popen(). The 1st parameter is the command string
3) in read mode, the output of your "ls -lsa " or "dir" command will be written into the output pipe of the spawned process, and your code will need to 'suck it in', I recommend capturing it to a std::stringstream.
4) after capture of the "dir -r" output, then parse and extract dir's and file names from the stringstream.
Examples of C++ access to popen:
FILE* m_pipe = nullptr; // popen return a FILE*
// use m_pipe to read from sub-process std::out
m_pipe = ::popen (m_cmd.c_str(), "r"); // read mode
// ^^ because popen is not in a namespace
m_pipe = ::popen(m_cmd.c_str(), "w"); // write to sub-process std::in
int32_t pcloseStat = ::pclose(m_pipe);
{
(void)memset(buff, 0, BUFF_SIZE);
// Reads characters from stream and stores them as a C string
// into buff until
// a) (BUFF_SIZE-1) characters have been read or
// b) a newline or
// c) the end-of-file is reached,
// whichever happens first.
char* stat = fgets (buff, BUFF_SIZE, m_pipe); // returns buff or null
int myErrno = errno; //^^^^^^ -- created by popen
}
Example of building a linux command for popen 1st parameter ...
std::string md5sumCmd ("head --bytes=1M " + mPFN +" | md5sum");
This command grabs the 1st 1Megabyte of file name in mPFN (a std::string), and pipes that output into md5sum ... essentially generating an md5sum of the 1s Meg of the file. The md5sum output is what will be received by the calling process.
You will need to create appropriate commands (to pass to popen) to show dir's and folder's and file names, etc.
What ever works from the command line should be fine, but some options might make parsing the output easier.
For your node based structures, add a string property that would serve as your file path. You might need to replace "\" with "/" in it however as the forward slash is often an escape character in most languages. For example in a queue:
class Node {
Node next;
char[50] path;
}
And you can create accessors and mutators the same way you would anything else in a class. This will allow you to assign it values and to read the values.
Folders could be used as a parent and the files are children. A tree structure would likely be the easiest way to do this.

Including (linux) bash commands

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.

How do I get warn()'s output into a string?

I'm using the non-standard function warn() (provided by BSD) to output an error message if a file can't be opened, like so:
std::string path = get_path() ;
std::ifstream file(path) ;
if (file.is_open()) { /* do something */ }
else {
warn("%s", path.c_str()) ;
// uses errno to figure out what the error was and outputs it nicely along with the filename
}
That's all very well for outputting it, but what if I want to use the entire string somewhere else, in addition to printing it? The warn() functions don't seem to have a form that writes the error to a string. I've tried rolling my own, but it seems awfully cumbersome in comparison (besides not getting the program's name):
this->foo((boost::format("%s: %s") % path % strerror(errno)).str()) ;
So how do I get warn()'s output as a string?
warn puts its output on the standard error output. So you would have to create a mechanism to redirect standard error output to a location that you can read back into a string. The most straight forward way may be to redirect standard error to a file, and then read the file back as a string. You could, for instance, try to use dup2() to accomplish this (as explained in the answer to this question).
However, wrapping your own version of warn is probably a better choice. You may consider the C vsnprintf() function to implement it, though. There are answers to this question that address both using boost::format and vsnprintf().
You're right — there's no sprintf analog (i.e. that is, no hypothetical swarn function).
Your approach seems viable.
It would appear that your gyrations produce a result similar to:
path + ": " + strerror(errno);
At a guess, the "program's name" that it's including is probably just argv[0], so you could apparently produce a roughly equivalent of your warn that just returns a std::string with something on this general order:
std::string warn_s(std::string const &path) {
char *pname = strrchr(argv[0], '/');
if (pname == NULL)
pname = argv[0];
return path + pname + ": " + strerror(errno);
}
The major difficulty here is that argv is local to main, so you'll probably need to either save it into an accessible location in main, or else use some non-standard mechanism to re-retrieve that data in your function.
Unfortunately, the documentation for warn I was able to find was poor enough that a bit of testing/trial and error will probably be needed if you want to duplicate its output precisely.

exec family with a file input

Hey guys I am trying to write a shell with C++ and I am having trouble with the function of using input file with the exec commands. For example, the bc shell in Linux is able to do “bc < text.txt” which calculate the lines in the text in a batch like fashion. I am trying to do likewise with my shell. Something along the lines of:
char* input = “input.txt”;
execlp(input, bc, …..) // I don’t really know how to call the execlp command and all the doc and search have been kind of cryptic for someone just starting out.
Is this even possible with the exec commands? Or will I have to read in line by line and run the exec commands in a for loop??
You can open the file and then dup2() the file descriptor to standard input, or you can close standard input and then open the file (which works because standard input is descriptor 0 and open() returns the lowest numbered available descriptor).
const char *input = "input.txt";
int fd = open(input, O_RDONLY);
if (fd < 0)
throw "could not open file";
if (dup2(fd, 0) != 0) // Testing that the file descriptor is 0
throw "could not dup2";
close(fd); // You don't want two copies of the file descriptor
execvp(command[0], &command[0]);
fprintf(stderr, "failed to execvp %s\n", command[0]);
exit(1);
You would probably want cleverer error handling than the throw, not least because this is the child process and it is the parent that needs to know. But the throw sites mark points where errors are handled.
Note the close().
the redirect is being performed by the shell -- it's not an argument to bc. You can invoke bash (the equivalent of bash -c "bc < text.txt")
For example, you can use execvp with a file argument of "bash" and argument list
"bash"
"-c"
"bc < text.txt"