Get System Environmental Variables In C - c

I've written an application in C that is supposed to be reading environmental variables and handling those changes appropriately. When the application starts, I've set it up to go ahead and initialize the variable (to prevent any null pointers from returning) via setenv("MYVARIABLE", "TEST", 1).
This application loops often and, during those loops, one of its jobs is to check that global variable via getenv("MYVARIABLE").
The plan then was to have either a shell script or a python script change these environmental variables. The C application is full screen, so I have no way of testing this process without another terminal entry. In my other terminal (c2) I run commands such as:
MYVARIABLE="My New Value"
or
export MYVARIABLE="My New Value"
My application doesn't seem to catch the environmental update, though. Instead it continues to insist that MYVARIABLE is "test," and not "My New Value." I'm not sure why these two environments are separate, but I need them to work together. Does anyone know what I'm doing wrong?
My system is running Archlinux for anyone who is interested

The problem you're facing right now is that you've only set your variable in the local shell session's scope. EX:
(Assuming bash) When you set a variable such as:
MYVARIABLE="My New Value"
it only effects the current shell, when you set it as:
export MYVARIABLE="My New Value"
it effects the current shell and all processes started from the current shell.
If you set it in your .bashrc file it will set it permanently for all future sessions, but you'll need to source that file for it to work in your current session.
The best solution is to fork off a process. For example if your program is called a.out you can execute:
> ./a.out &
This will allow you to continue to work in the shell session while the program is running, then you can set variables in that same session.
The only other option I've ever seen is to force your shell session to "auto" source things as they come in:
1) In your first session enter:
trap 'source ~/.bashrc' DEBUG
2) Then start your program in the same session:
./a.out
3) In a second window edit your .bashrc file to add the new env var
4) in the second window source the new version of the file:
source ~/.bashrc
Now the first window running your program has the new var set to its session. I've used that before and I know it works, but I've never tried it on an applications that was already spawned.. but I suspect it should work for you.

Your process environment is not dynamically changeable!!!
Remember this main() prototype...
int main (int argc, char *argv[], char *envp[])
{
char *path;
/*
Searches in this process envp[] only,
There is no way it can access changes happening in Shell command prompt...
User shell does not communicate with this process, if not piped.
This will always return PATH, that was set at the time of starting.
*/
while (1)
{
path = getenv("PATH");
sleep (5);
printf("PATH = %s\n", path);
free(path);
};
}
Your understanding of getenv() library function is WRONG. To achieve your expectation, You need to use any form of IPC.
setenv() works with calling process own environment. That will be passed on to it own child process through fork(), exec() syscalls. This will will not do anything in the parent process, your shell.

Related

In C, how to create and send shell variable?

I would like to get the following result, let me explain, we have a file "test.sh", in which we call a command written in c (mycmd.c), and we assign it an argument. We want it to create a variable whose name is the argument passed and then return the result in the "test.sh" file.
Example :
In the file test.sh, we call our command, we assign as argument the name of the variable to create, then we display the extracted result with an echo.
#!/bin/bash
./mycmd myvar
echo "OK : $myvar"
In the mycmd.c file, we create a shell variable named myvar (the passed argument), then we assign a value to this variable (myvar = foo), and then we return it to the script "test.sh", who returns so "OK : foo".
It's possible ? Thanks.
What you request cannot be done. Every program you run, including shells and subshells, gets its own environment. By default, the contents of that environment is a copy of that of its parent process, but it is separate and independent. A process can modify only its own environment, not that of any other process.
I was going to suggest you use setenv, but after some thinking and testing, it is in fact not possible to do what you want with an arbitrary compiled program. Process environments are protected, and your program gets a new process and therefore a new environment when it runs.
The best way to do this would be to have your program output some shell commands to run. So if your program were the following
#include <stdlib.h>
#include <stdio.h>
int main() {
printf("export MYENV=helloworld");
return 0;
}
And you invoked it as $(./myprogram), the result of echo $MYENV would be helloworld. Tested on Bash with Arch Linux. I know this is not exactly what you want, and may not work for your purposes, but it is the best I know.

How to execute commands in chroot?

In my source code I make chroot and then have some code doing some staff then I want to execute linux command. But the command does not work since I changed the root with chroot.
here after the source code:
int main(void)
{
if (chroot("/tmp") < 0)
printf("error in chroot\n");
/* some source code doing staffs */
system("ls > /logloglog.txt"); // command failed
return 0;
}
How to execute command in chroot?
Or is it possible to exit from chrood then execute the command and then back to the chroot again?
If you use chroot(), you have to consider the consequences of what you do. One of the major consequences is that many (most, all) of the commands normally available are not available unless you make them available in the chroot()'d environment.
Doing that job properly is non-trivial. You may need parts of /dev, /bin, /etc, /usr, /lib (and probably others too) installed appropriately under the new root directory. Symlinks back to 'outside the chroot() environment' won't work, in general. You have to make copies of what's important. One side effect of all this: /tmp is very rarely an appropriate place to create a fully operational chroot() environment. You might get away with a limited access sub-directory under /tmp, but putting a user in /tmp doesn't isolate them from other users, or other users from them, very well.
One other major possibility: you do not give the user access to other commands after you've done chroot(). That is, you do not try to use system() in your code; and you don't give the victim user access to a shell or shell utilities.
Using chroot() is not something you do casually, in other words. To do a good job takes quite a lot of careful thought and preparation.
Would you be better off with a container or virtual machine of some sort instead?
Do use Google or any other search engine to search for terms such as:
'chroot jail escape'
'chroot jail setup'
'chroot jail vs docker'
Is it possible to exit from chroot then execute the command and then back to the chroot again?
Not really. You might be able have a controlling program that forks a child that does chroot() and processes material and then terminates, so that the controlling program can do its job (execute the command) and then you could fork another child that goes back into the chroot() jail. But that's not the same as the current process getting out of jail — it would make chroot() totally ineffective if any program could cancel its jail time on a whim and resume unjailed activity.
What about:
system("chroot /tmp /bin/bash -c \"<COMMAND>\"");
You can just run chroot using system directly and with -c execute command inside /tmp environment

How to export an environment variable for children processes inside a ksh script?

I'm working on an old C software. There is one ksh script which executes a C program, which then creates some other processes and ends. These processes remain alive.
I'm trying to set an environment variable inside my ksh script, so that it could be accessible in the newly created processes that are still alive.
I have tried this way :
#!/bin/ksh
VARIABLE=value
export VARIABLE
my_c_program
But that doesn't work... I have tried to :
change my ksh script to bash
create a wrapper script that creates and exports the variable and then executes the original ksh script (which just executes the C program)
sourcing my ksh script (or my wrapper script when trying with 2.) instead of executing
it
But nothing from that worked.
The only thing that works for now is when I explicitly, by hand, execute the command :
export VARIABLE
In the current bash terminal.
Why? Isn't it possible to do the export inside a script instead of doing it manually?
Everything is ok actually...
The fact is that the process I thought was the child of the C program executed in my ksh script was the child of another process executed before. The C program was just sending a message via shared memory to tell the other program to execute its child.
So indeed the environment variable never went from my C program to the other's child. The only time when I had that variable set in the child is when I executed the other program (the one which is the real parent of the child) in a shell where the variable was exported.
The code above looks correct and it should work. Another way to do it is:
VARIABLE=value my_c_program
which exports the variable just for the program. Afterwards, the variable will be set but other external processes don't get a copy.
So why doesn't your script work? It's hard to tell but here are some tips to debug the issue:
Use #!/bin/ksh -x to enable debug output. Save the output in a file and then grep VARIABLE to make see what happens with it.
Check for typos.
Another shell script is like an external process. So create a script
#!/bin/ksh
echo $VARIABLE
and call it instead of my_c_program just to make sure passing the variable on works.
Maybe the C does something unexpected. Use a debugger to make sure it does what you expect.

Execute SET command in c program

I created a little mini shell and it let's the user enter a command like 'ls' and it will list the contents of the directory like it's supposed to using execv() in my code, but that doesn't seem to work for when the user enters something like 'set name="bob"'. I've been looking all over the place for what I should use in my code to execute a set command when the user enters it and the best I can find is system(), but that still isn't working for me. Any ideas?
set is a shell-builtin command, not an external command (indeed it needs to be to have the intended effect, which is to modify a shell variable within the shell process itself).
This means that you need to look for and handle set within your shell itself, by adding the named variable to some internal data structure that tracks shell variables (or updating it if it already exists there).
Since you're doing a fork-and-exec or a system(), the command is really being run in a separate process. What happens in that process (like setting an environment variable) does not affect the parent's environment. (A separate issue is that set doesn't actually create an environment variable. You'd need export in [ba]sh or setenv in [t]csh to do that.)
So you need to code your mini-shell to handle the set command explicitly, rather than passing it off to another program.
You might want to look at setenv(3) and getenv(3). These are functions for changing and reading environment variables from within a C program.

how to change directory using exec command from C program?

I have to change working directory from my C program. For this I have used the following command:
execl("/bin/cd","cd","..",(char*)0);
but this command is not changing the directory?
Is anything wrong in this command or is there any other way to change working directory from C program?
To change the current directory you should use chdir:
int chdir(const char *path);
On success it returns 0.
You can't use execl for several reasons:
cd is typically a shell builtin command;
on most systems /bin/cd does not exists; on the very very few systems that have it, it changes the current directory and then spawns a child shell process;
the current directory is a process' property: if you change the current directory using /bin/cd, you'd lose the directory change as soon as the process terminates;
if you use a function from the exec family, the current process image is replaced with a new process image - you could use system, but wouldn't fix the previous 3 problems.
What you are doing won't work because the exec family of calls will actually replace your current program in the current process. In other words, you will have been terminated so that, when cd is finished, your parent process will once again take over.
If you want to change the working directory for the current process, use chdir. If you want to change it on exit, you're out of luck because your program itself is running in a separate process from the parent that started it.
So, unless you have some form of communication with the parent, that's not going to work.
You need to use the chdir system call to change the working directory of the calling process.

Resources