system() doesn't work for modifying the command line prompt - c++

I'm using C++ in Ubuntu and want to modify the command prompt. If I enter PS1=abc in the command line, the prompt becomes abc.
However, if I execute a program that calls to system("PS1=ABC"), the prompt doesn't change.
On the other hand, system() appears to work fine with different commands and the command line obeys.

PS1 is an environment variable. Every process has its own set of environment variables.
When you start a new process, it inherits a copy of its parent's environment. Any changes to a process's environment will not affect the environment of its parent process.
The system function starts a new child process. That means that system("PS1=ABC") launches a child process that sets its own PS1 variable and then exits.
To modify an environment variable in your own process, use putenv (Linux and other Unix-likes) or SetEnvironmentVariable (Windows). Note that this still won't affect your parent process (likely the shell from which your program was launched), so setting PS1 still won't have any affect unless you then subsequently launch another shell as a child.

system(command) starts a sub process. Whenever it finishes, its whole environment is gone.
If you want to pass environment variables to the subprocess, look up fork() and exec().
Or, if your're using Windows, CreateProcess.

Related

Access C drive using C++ programming

I have a project that must hide a file into an image , first I used command prompt and it goes well. Now I am trying to apply this commands using C++ programming language, but each time it gives me that system can't find the specified path although it exists and work well using command prompt.
This my code:
system("cd\\"); \\access C
system("cd x"); \\X is name of folder in C
system("copy /b pic.jpg + file.rar NEWPICTURE.jpg");
This is the source of commands: http://www.instructables.com/id/How-to-Hide-Files-Inside-Pictures/
Every time you call system(), a new shell process is created to run that single command. When that shell exits, its local context, including working directory and environment variables, is lost. The next call to system() copies the context of the parent process (your program) all over again.
Your options are to pass a command list/pipeline to a single system() call, or to use functions that affect your own process context, such as chdir().

How to return a command from a c++ application to parent terminal?

Is it possible to run a c++ application from a terminal and on certain conditions return a command back into the terminal from which it was called from? For instance, if I were to run an application within my terminal and after my selections; my application needs to change my PATH by running an export command such as:
(USING BASH)
export PATH=.:/home/User/application/bin:$PATH
After I'm done and before my application completely closes can I make the application change my terminals local environment variables with the above command? Does Qt offer a way of doing this? Thanks in advance for any help!
No, you cannot change parent application environment.
Why? When your parent app started yours (probably using system()), it actually fork()ed - child process was born as to be almost exact replica of parent, and then that child used execve() call, which completely replaced executable image of that process with executable image of your application (for scripts it would be image of interpreter like bash).
In addition to that, that process also prepared few more things. One is list of open files, starting with file handles 0,1,2 (stdin, stdout, stderr). Also, it created memory block (which belongs to child process address space) which contains environment variables (as key=value pairs).
Because environment block belongs to your process, you can change your own environment as you please. But, it is impossible for your process to change environment memory block of parent (or any other process for that matter). The only way to possibly achieve this would be to use IPC (inter-process communication) and gently ask parent to do this task inside of it, but parent must be actively listening (on local or network socket) and be willing to fulfill such request from somebody, and child is not any special compared to any other process in that regard.
This also reason why you can change environment in bash using some shell script, but ONLY using source or . bash macro - because it is processed by bash itself, without starting any external process.
However, you cannot change environment by executing any other program or script for reasons stated above.
The common solution is to have your application print the result to standard output, then have the invoker pass it to its environment. A textbook example is ssh-agent which prints an environment variable assigment; you usually invoke it with eval $(ssh-agent)

Permanently setting environment variables from a C++ program after exit

I am writing a bash script that runs a C++ program multiple times. I use getenv() and putenv() to create, get, and update environment variables in the C++ program. After the C++ program ends, the bash script needs to grab these variables and perform some basic logic. The problem is that when the C++ program exits, the environment variables disappear. Is there any way to permanently store these variables after the program's termination so that the bash script can use them? If not, what is the best way to share variables between a bash script and a C++ program? The only solution I can think of is writing output to files. I do not want to print this data in the console. Any help would be greatly appreciated.
Each process has its own copy of the environment variables, which are initialised by copying them from the parent process when the new process is launched. When you change an environment variable in your process, the parent process has no knowledge of this.
In order to pass back information from a child to a parent, you will need to set up some other kind of communications channel. It could be files on disk, or a pipe, or (depending on the capabilities of your parent, bash might not be able to do all this) shared memory or some other IPC mechanism. The parent program would then be responsible for changing its own environment variables based on information received from the child.
I personally have only ever been able to do this in 16-bit DOS assembler, by tracing the pointer to the previous process until it points at itself, which means that you've reached the first instance of COMMAND.COM, and then altered its environment manually.
If your program returned the variables via standard output as string, like this:
FOO=23; BAR=45;
Then, bash could call it like this:
eval `./your_program`
end $FOO and $BAR will be accessible to bash.
To test this try:
eval `echo "FOO=23; BAR=45;"`
echo "$FOO $BAR"
Of course, in this method the program does not change environment variables of calling process (which is not possible), but just returns a string that is then evaluated by bash and the evaluation sets the variables.
Do not use this method if your program processes input from not trusted source. If someone tricked your program to print "rm -rf /" to the standard output you would be doomed.
As far as i know under a "standard" GNU/Linux environment you can set environment variables in 3 ways:
using command line utilities like export
editing files like ~/.profile or ~/.bashrc for an user or the equivalent files under /etc for system
feeding temporary values to a command like this CXX=g++ CUSTOM_VERSION=2.5 command
the last one is usually used to customize builds and it's good because doesn't harm the system and does not interfere with any system settings or values or files and everything is back to normal after the execution of the command. It's the best way if you like to have a temporary modification for a particular set of variables.
There is no way for a program to set environment variables in its parent. Or, well, no legitimate way. Hacking into its process with ptrace does not count. :-)
What you should do is output the environment variables on standard output. Have the shell script read them and set them. If the environment variables are all that you output the call is very simple:
`program`
The back-ticks will capture the output of the program. Then it will replace the back-ticks with the output. Which will be commands to set shell variables. Then later in your shell script be sure to do:
export VAR1
export VAR2
You need the export commands in order to move them into the environment that is passed to programs launched from the shell.
You cannot set environment variables which survive the life-time of your process, so the easiest solution is to write to output files as you suggested or write to specific filehandles handed down from Bash:
C++:
int main (int argc, char* argv[])
{
// missing error handling
int fd = atoi(argv[1]);
const char* env = "BLAH=SMURF";
write(5, env, strlen(env));
return 0;
}
Bash:
# discard stdout and stderr, redirect 5 to stdout so that it can be captured
# and tell the process that it should write to 5 (the first 5)
VARIABLES=`./command 5 2>&1 1>/dev/null 5>&1`
This is probably a crack-pot idea but it should work :)

Is it possible to send command to console window in which my program is running?

I know the system() function but that creates it's own environment so every variable set here isn't forwarded to main console. I wonder is it possible to send command as it would be written by the user or as it would be executed by *.bat file ?
The reason I need this is that I look for a way to set env variable of parent CMD process. And yes I know that system doesn't want me to do it, but maybe there is a some workaround for that...
Idea is to create app that would set as a variable anything that is send to it via input pipe, like this:
echo Bob| setvar name
so then:
echo %name%
would produce Bob
The whole idea is to make easier setting a variable from any program output (I know how to do it with for command) with taking account of peculiarities with special batch characters like ^!% since these are allowed in file names. It would make simpler many cmd scripts.
You can certainly run programs in the same console window as your program. That's the default behavior for CreateProcess. MSDN has more details on what happens between related processes sharing a console. You'll probably want to wait for the child process to terminate before continuing to run your own program.
However, that won't help with your real goal. The window where a program runs has absolutely nothing to do with the environment variables of any of its ancestor processes. You'll have to look elsewhere for a solution to your real problem.

How can I change Windows shell (cmd.exe) environment variables from C++?

I would like to write a program that sets an environment variable in an instance of the shell (cmd.exe) it was called from. The idea is that I could store some state in this variable and then use it again on a subsequent call.
I know there are commands like SetEnvironmentVariable, but my understanding is that those only change the variable for the current process and won't modify the calling shell's variables.
Specifically what I would like to be able to do is create a command that can bounce between two directories. Pushd/Popd can go to a directory and back, but don't have a way of returning a 2nd time to the originally pushed directory.
MSDN states the following:
Calling SetEnvironmentVariable has no
effect on the system environment
variables. To programmatically add or
modify system environment variables,
add them to the
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session
Manager\Environment registry key, then
broadcast a WM_SETTINGCHANGE message
with lParam set to the string
"Environment". This allows
applications, such as the shell, to
pick up your updates. Note that the
values of the environment variables
listed in this key are limited to 1024
characters.
Considering that there are two levels of environment - System and Process - changing those in the shell would constitute changing the environment of another process. I don't believe that this is possible.
A common techniques is the write an env file, that is then "call"ed from the script.
del env.var
foo.exe ## writes to env.var
call env.var
In Windows when one process creates another, it can simply let the child inherit the current environment strings, or it can give the new child process a modified, or even completely new environment.
See the full info for the CreateProccess() win32 API
There is no supported way for a child process to reach back to the parent process and change the parent's environment.
That being said, with CMD scripts and PowerShell, the parent command shell can take output from the child process and update its own environment. This is a common technique.
personly, I don't like any kind of complex CMD scripts - they are a bitch to write an debug. You may want to do this in PowerShell - there is a learning curve to be sure, but it is much richer.
There is a way...
Just inject your code into parent process and call SetEnvironmentVariableA inside
cmd's process memory. After injecting just free the allocated memory.