C++ getenv doesnt update - c++

I'm trying to make a program that a bash script runs. I want the bash script to be able to change the state of the c++ program, and the only thing I could find was to use environment variables. Thing is, its seems getenv only gets the value at the time when the program was run.
Bash
export BLINK=1
./blink &
sleep 5s
unset BLINK
C++
int main(int args, char **argv) {
char *blink = getenv("BLINK");
while(blink && blink[0] == '1')
{
std::cout << getenv("BLINK") << std::endl;
usleep(500000);
}
return 1;
}
So what this does is run the blink program, wait 5 seconds then unset the environment. The C++ program however always sees the enviorment value as 1 and never stops. How do I get an updated environment variable while the program is running? Or is there a better way to have a bash script control the state of a c++ program.
EDIT I should note, I do not want to just kill the process either because it has to turn off hardware when it ends.

It is not possible to modify program environment after it is started. You have to use another method of interprocess communication. The simplest one is to register handler for some signal to your app (e.g. SIGUSR1), and then send it using kill -SIGUSR1 <pid> command.
There are also other solutions available, e.g. create named pipe (using pipe shell command), and check periodically if someone wrote something to it. If yes, exit loop.
You can also use sockets if you want, but this could be more complicated.

The C++ programs environment is not changing when you change it in bash - since when you start your program it gets a copy of the parent's environment and has no access to the parent process's environment.
You can use a file to easily share data, however.
Bash
echo "1" > blink.txt
./blink &
sleep 5s
echo "0" > blink.txt
C++
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <unistd.h>
using namespace std;
string getfile(const string& filename) {
ifstream in(filename.c_str(), ios_base::binary);
in.exceptions(ios_base::badbit | ios_base::failbit | ios_base::eofbit);
return string(istreambuf_iterator<char>(in), istreambuf_iterator<char>());
}
int main(int argc, char* argv[]) {
string blink = getfile("blink.txt");
while(blink[0] == '1')
{
std::cout << getfile("blink.txt") << std::endl;
usleep(500000);
}
return 1;
}

Related

Sending user inputted commands to an arduino in c++ using system() on a linux terminal

Using a c++ program i can successfully send commands to an arduino. The code uses the command:
system("$echo [command] > dev/ttyACM0");
Currently i must manually input the commands into this space, I was wondering if it's possible for a user to input the command, and for it to then be added to the string within system()?
This is an approximation of what I think you want:
#include <fstream>
#include <iostream>
#include <string>
int main() {
std::string command;
if(std::getline(std::cin, command)) { // read user input
std::ofstream ard("/dev/ttyACM0"); // open the device
if(ard) {
ard << command << '\n'; // send the command
}
} // here `ard` goes out of scope and is closed automatically
}
Note that you do not need the unsafe system() command at all here. Just open the device and send the string directly.

Passing a command into a shell script through a C++ program

I am trying to pass a command into my shell script via a C++ program, but I am not familiar with C++ at all and, while I know that I must use system(), I am not sure how to set it up effectively.
#include <iostream>
#include <stdlib.h>
int main() {
system("./script $1");
return 0;
}
This is what I currently have.
It seems that I can't use positional parameters in the system command, but I wasn't sure what else to do. I'm trying to pass in an argument to the script via the C++ program.
If you just want to call "./script" with the first argument to the C++ program passed as the first argument to the script, you could do it like this:
#include <iostream>
#include <string>
#include <stdlib.h>
int main(int argc, char ** argv)
{
if (argc < 2)
{
printf("Usage: ./MyProgram the_argument\n");
exit(10);
}
std::string commandLine = "./script ";
commandLine += argv[1];
std::cout << "Executing command: " << commandLine << std::endl;
system(commandLine.c_str());
return 0;
}
Properly executing a shell command from C++ actually takes quite a bit of setup, and understanding exactly how it works requires a lot of explanation about operating systems and how they handle processes. If you want to understand it better, I recommend reading the man pages on the fork() and exec() commands.
For the purposes of just executing a shell process from a C++ program, you will want to do something like so:
#include <unistd.h>
#include <iostream>
int main() {
int pid = fork();
if (pid == 0) {
/*
* A return value of 0 means this is the child process that we will use
* to execute the shell command.
*/
execl("/path/to/bash/binary", "bash", "args", "to", "pass", "in");
}
/*
* If execution reaches this point, you're in the parent process
* and can go about doing whatever else you wanted to do in your program.
*/
std::cout << "QED" << std::endl;
}
To (very) quickly explain what's going on here, the fork() command essentially duplicates the entire C++ program being executed (called a process), but with a different value of pid which is returned from fork(). If pid == 0, then we are currently in the child process; otherwise, we're in the parent process. Since we're in the dispensable child process, we call the execl() command which completely replaces the child process with the shell command you want to execute. The first argument after the path needs to be the filename of the binary, and after that you can pass in as many arguments as you want as null-terminated C strings.
I hope this helps, and please let me know if you need further clarification.
the problem I have understood so far is that you want to pass arguments to c++ executable and it will then pass those arguments further to the system script
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
// argc is the count of the arguments
// args is the array of string (basically the arguments)
int main(int argc, char ** argv) {
// Convetion to check if arguments were provided
// First one or two are the not positional. (these are information related to the binary that is currently being executed)
if (argc < 2) {
printf("Please Provide an Argument");
return 100; // Any number other than 0 (to represent abnormal behaviour)
}
string scriptCommand = "./name-of-script"; // script in your case
// Loop through and add all the arguments.
for (int i = 1; i < argc; i++)
scriptCommand += " " + argv[i];
system(scriptCommand.c_str());
return 0; // Represents a normal exit (execution).
}

How to build your own CMD using C++?

Recently I want to enhance CMD in Win10 by myself using C++. I don't want to change the original framework of it but to translate the command. At first i wrote something like this:
#include <unistd.h>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string initial = "retr0# ";
string s;
while(1)
{
cout << initial;
getline(cin,s);
if(s!="exit")
{
system(s.c_str());
cout << "------" << endl;
}
else break;
}
system("pause");
return 0;
}
But I found that if you entered command like "E:" or something else to change the directory, it is impossible for the new thread to inherit the context. My question is, how to solve the problem like this?
In most operating systems (including 1970 era Unix), the working directory is specific to each process.
The system function will run another process. So even if you change its working directory, it only affects the process started by system, not the process running your program.
So you need to define a syntax (perhaps the same cd as Windows CMD has) and parse and implement that command in your own program. You could use SetCurrentDirectory or _chdir

Send data to another C++ program

Is it possible to send data to another C++ program, without being able to modify the other program (since a few people seem to be missing this important restriction)? If so, how would you do it? My current method involves creating a temporary file and starting the other program with the filename as a parameter. The only problem is that this leaves a bunch of temporary files laying around to clean up later, which is not wanted.
Edit: Also, boost is not an option.
Clearly, building a pipe to stdin is the way to go, if the 2nd program supports it. As Fred mentioned in a comment, many programs read stdin if either there is no named file provided, or if - is used as the filename.
If it must take a filename, and you are using Linux, then try this: create a pipe, and pass /dev/fd/<fd-number> or /proc/self/fd/<fd-number> on the command line.
By way of example, here is hello-world 2.0:
#include <string>
#include <sstream>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main () {
int pfd[2];
int rc;
if( pipe(pfd) < 0 ) {
perror("pipe");
return 1;
}
switch(fork()) {
case -1: // Error
perror("fork");
return 1;
case 0: { // Child
// Close the writing end of the pipe
close(pfd[1]);
// Create a filename that refers to reading end of pipe
std::ostringstream path;
path << "/proc/self/fd/" << pfd[0];
// Invoke the subject program. "cat" will do nicely.
execlp("/bin/cat", "cat", path.str().c_str(), (char*)0);
// If we got here, then something went wrong, then execlp failed
perror("exec");
return 1;
}
default: // Parent
// Close the reading end.
close(pfd[0]);
// Write to the pipe. Since "cat" is on the other end, expect to
// see "Hello, world" on your screen.
if (write(pfd[1], "Hello, world\n", 13) != 13)
perror("write");
// Signal "cat" that we are done writing
close(pfd[1]);
// Wait for "cat" to finish its business
if( wait(0) < 0)
perror("wait");
// Everything's okay
return 0;
}
}
You could use sockets. It sounds like both application are on the same host, so you just identify the peers as localhost:portA and localhost:port B. And if you do it this way you can eventually graduate to do network IO. No temp files, no mystery parse errors or file deletions. TCP guarantees packet delivery and guarantees they will be ordered correctly.
So yeah, I would consider creating an synchronous socket server (use asynchronous if you anticipate having tons of peers). One benefit over pipe oriented IPC is that TCP sockets are completely universal. Piping varies dramatically based upon what system you are on (consider Windows named pipes vs implicit and explicit POSIX pipes -> very different).

Distinguish if program runs by clicking on the icon, typing its name in the console, or from a batch file

The program I am writing is a simple console application that gets params, computes, and then returns data.
I am asking this because I am trying to implement a smart "press enter to exit" message that would run only if a console program is called by clicking on its icon in explorer. Without it, the result is that program only flashes for a split of second, but if a program is run from a context of already opened console then the same thing becomes an annoyance. Similar thing arises when program is run inside bat or cmd file, then pausing at the end is also unwelcome since bat files have 'pause' command that is supposed to do it.
So, we have 2 modes:
program says "press enter to exit" when is started by:
direct clicking in explorer
clicking on a shortcut
Simply exit when:
its name is typed in console
it is run from a bat/cmd file
it is run from another console application
Using Windows APIs:
You can use the GetConsoleProcessList API function (available on Windows XP/2003 and higher only). It returns a list of processes that are attached to the current console. When your program is launched in the "no console" mode, your program is the only process attached to the current console. When your program is launched from another process which already has a console, there will be more than one process attached to the current console.
In this case, we don't care about the list of process IDs returned by the function, we only care about the count that is returned.
Example program (I used Visual C++ with a Console Application template):
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
DWORD procIDs[2];
DWORD maxCount = 2;
DWORD result = GetConsoleProcessList((LPDWORD)procIDs, maxCount);
cout << "Number of processes listed: " << result << endl;
if (result == 1)
{
system("pause");
}
return 0;
}
We only need to list up to 2 processes, because we only care whether there is 1 or more than 1.
Using Windows APIs present in Windows 2000:
GetConsoleWindow returns the window handle of the console associated with the current process (if any). GetWindowThreadProcessId can tell you which process created a window. And finally, GetCurrentProcessId tells you the id of current process. You can make some useful deductions based on this information:
#include "stdafx.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
HWND consoleWindow = GetConsoleWindow();
if (consoleWindow != NULL)
{
DWORD windowCreatorProcessId;
GetWindowThreadProcessId(consoleWindow, &windowCreatorProcessId);
if (windowCreatorProcessId == GetCurrentProcessId())
{
cout << "Console window was created by this process." << endl;
system("pause");
}
else
cout << "Console window was not created by this process." << endl;
}
else
cout << "No console window is associated with this process." << endl;
return 0;
}
This technique seems slightly less precise than the first one, but I think in practice it should perform equally well.
The simplest solution I can think of is require the first parameter to be a flag whether or not the program should pause at the end. If the parameter is not there, i.e. it was started via explorer and the user did not have the ability to pass it in, then it should pause.
//Pseudo-code!!
int main(int argc, char** argv) {
//...
if(argv[1] == SHOULD_PAUSE) system("pause");
return 0;
}
There's a simple way to do this, and of course a more complicated way. The more complicated way may be more fun in the end, but probably more trouble than it's worth.
For the simple way, add a command line argument to the program, --pause-on-exit or something similar. Pass the extra arg whan calling it from a batch-file or the launcher icon. You could of course rather check for an environment variable for a similar effect.
For a more complicated (and automatic) way, you could probably try to find out who is the parent process of your application. You may have to go further up the chain than your immediate parent, and it may not work in all cases. I'd go for the command line argument.
Elaborating on my comment, rather than trying to tell how the program was executed (which I don't know is even possible, I'd assume there's no difference/distinction at all), I would implement a similar functionality in either one of two ways:
Add an extra argument to the program that will either make it "pause" at the end before terminating or not. ie. You could have something like -w to make it wait, or -W to make it not wait, and default with not waiting (or vice versa). You can add arguments through shortcuts.
Add a timer at the end of the program so that you wait for a few seconds, long enough for the user to read the input, so that the program doesn't wait infinitely when used in a batch.
Visual Studio introduces a wrinkle to #tcovo's otherwise valid answer when you are debugging. In this situation, it creates a second process and attaches it to the same console as the process you're running in:
So, it's necessary to detect the debugger using the Windows API function IsDebuggerPresent in order to get a definitive answer:
#include <iostream>
#include <Windows.h>
#include "debugapi.h"
int main()
{
DWORD pl[2];
auto np = GetConsoleProcessList(pl, 2);
std::cout << np << " processes\n";
bool shared;
if (IsDebuggerPresent())
shared = np > 2;
else
shared = np > 1;
std::cout << "Shared: ";
std::boolalpha(std::cout);
std::cout << shared << "\n";
std::cin.ignore(1);
return 0;
}
This only matters if you're using the local debugger; when run in a remote debugger there is still only one process attached.