Changing a environmental variable through a C program - c

Anyone knows how can I change the Linux environmental variables through a C program? I dont want to change the environmental variables that are copied for the execution of that program. I want to be able to change its value from a C program and then when executing the command 'env' in linux I can see its value changed.
Any tips?

I dont want to change the environmental variables that are copied for
the execution of that program. I want to be able to change its value
from a C program and then when executing the command 'env' in linux I
can see its value changed
You can't. You can only change the environment of your own process. You have no way of ever touching the environment of the parent. Put another way, anything you do (setting / clearing environment variables, changing local directory, etc.) will be invisible for the parent process.
The standard clearly states:
The setenv() function shall update or add a variable in the
environment of the calling process.
The only way to change the environment of the parent is to get it to do it himself.

See POSIX functions setenv and putenv.
setenv http://pubs.opengroup.org/onlinepubs/009604599/functions/setenv.html
putenv http://pubs.opengroup.org/onlinepubs/009604599/functions/putenv.html
As POSIX says The setenv() function is preferred over this function. (putenv)
I dont want to change the environmental variables that are copied for the execution of that program.
As #cnicutar put in his answer you can only change the environment variable for your current process and not for its parent process or another process.

Related

How to not propagate environmental variables to command of a child process?

I am trying to understand the specifications of a C coding project using fork() and execv().
Essentially, I am told I need to either propagate or not propagate the environment variables of the shell to the command I am executing in a child process depending on a binary value.
Though, regardless, I am supposed to pass in any additional environmental variables I am provided to the command I am executing in the child.
This whole idea is new information to me, so I am just trying to understand what exactly this means.
To my understanding, when a child is created using fork(), the environmental variables of the parent process are passed on to the child, and then any additional environmental variable changes can be made as an argument of the execve() function when it is run within the child.
But if this is the case, then the environmental variables are always propagated from the parent/shell anyway right? So what is the difference and how would I not propagate those variables?
Thanks for your time.
You're still in control after the fork() and before the execv().
You can make changes to your child's environment that you don't want to make to your parent -- including calls to unsetenv() -- in that process.
Alternately, you can construct a new environment entirely and pass it in the envp argument to execve().
If you understood fork(2) then you'll know that the parent and the child are exactly the same (except for the value returned by fork()), so the environment of the parent process is exactly the same as the environment of the child. there's no other way to pass environment to a child process... because execve(2) doesn't create a new process. You only load the process' virtual space by loading a new program on it. And this allows you to change the environment, as it happens with the argument list. Think of argc and argv as some way of passing positional parameters to a program, and the environment as some way to pass named parameters to a program. Both are exactly the same kind of things, but ones are seek by position, while the others are accessed by name.
But no new process is created on execve(2) (nor in any of its variants)

Reading global environment variables

I have a process which is created by execve() from another program and a specific set of environment is passed to it. However, I would need to read a global environment variable that may or may not be set by the user based on certain aspects. For example, $PATH is set when the execve() is called, but if the user stes $LOWMEM=1 (export LOWMEM=1)
before the program is exec'ed, then the program will not make malloc() calls larger than 1KB.
when I do a getenv("LOWMEM") call from the program it returns NULL where as I have added LOWMEM=1 in /etc/enviroment and echo $LOWMWM shows the value as 1. But I don't see LOWMEM entry in /proc/<PID>/environ. Whereas I had rebooted the system after adding the entry to the /etc/environment.
Is it not possible to read global environment from a process running under specific environment without explicitly passing it from the parent process?
It seems most likely that you're clearing out the entry for LOWMEM while using execve. Instead, it might be better to call setenv for the new variables you want, either in the parent or in the child and then call execv.

unix "clear" TERM environment variable not set

I am making my own shell and have set up the fork/exec stuff to execute programs. for commands without a '/' I search the PATH environment for directories with the executable in it. However when I try to use clear in my shell, tells me TERM environment variable not set. I am wondering if it has something to do with this:
execve(args[0], args, environ);
where environ =
char* environ[] = {NULL};
Is there something I need to put in there? Would prefer not using execvp. Any help is appreciated
The shell is supposed to provide its own environment variables to child processes. In fact, pretty much all processes which spawn children are supposed to do that. Normally you'd use execv for that (note the lack of e), which doesn't take the environment as a parameter.
A shell is a special case too, since it's one of the processes which may legitimately modify the environment before passing it to its children. This means you probably will end up needing execve, but you cannot simply pass a fixed array there. You will need to manage the environment you want to pass to your children, loading your own environment at shell start-up, modifying it during each environment modification command, and passing that as environ.

change terminal directory using c language

i am trying to change the directory of my linux terminal using c language. the thing is i am using threads. i have tried to use chdir() but its not working, n yes chdir() is also a process function.
Actually the thing i am trying to implement is, i am trying to make a multi threaded program which compiles Linux kernel, and that is not possible without specifying directories( i have tried to do it without specifying directories but failed :) )
can anybody help me out with this issue?
Thanks in advance :)
You can't! No process can change the working directory of another. A process can only change its own WD. When you launch an external command such like your C program, then a new process is launched.
The cd command of your shell is an internal one.
It isn't very clear what you are trying to achieve. It appears that somehow you wish to emulate the behaviour of a script (or the make tool) using a C program, that is to say having the C program you wrote launch new processes (using system or perhaps a combination of fork and exec*). If that is the case, then what you actually want is to modify the environment variables of these processes for them to find the files they need. A forked process will inherit the environment of its parent, so all you need is to use getenv, putenv, setenv and unsetenv to retrieve and set the environment variables you want to add, update or remove; or you may use the specific execve, execvpe which let you specify exactly what environment should be available to the new program.
references:
fork system call
exec family of system calls
unix environment

Set an environment variable from a process that will be visible by all processes

How to set an envirnoment variable from a process that will be visible by all processes?
I'm using C with Glib.
I have 10 processes that use the same library. The problem is that in that library a checking procedure (which is CPU hungry) is performed. I want to avoid that library checking procedure to be executed for every process. For the first process that is using the library it will be enough.
This is simply not possible.
Setting an environment variable (or changing your current environment) is only visible from the children (and descendants) processes of your current process.
Other processes, in particular the parent process (usually the shell running in the terminal where you start your program) are not affected.
You might play dirty tricks like e.g. adding lines into $HOME/.bashrc etc. But you should not.
You just need to document what environment variables are relevant. It is the user's responsibility to set environment variables (perhaps by manually editing his $HOME/.bashrc etc etc). Leave that freedom to your user. Explain to him how to do that and why.
You edited your question to explain that
I have 10 processes that use the same library. The problem is that in that library a checking procedure ( which is CPU hungry ) is performed. I want to avoid that library checking procedure to be executed for every process.
But you definitely should not need to change environment variable for that.
You could
decide and document that the checking is not performed, unless some particular environment variable (or some program argument) is given
decide that the checking is given a particular file name, and use file locked write to write that file, and use file locked reads to read it again
Have the checking write its result in some known in advance file, and read that file before deciding it you want to make the costly checks
Have one process starting all the others, and inform them about the check (perhaps indeed setting some environment variable or some program argument) or use some Inter Process Communication trick to communicate with the others (you could use sockets, locked files, shared memory, etc etc...)
Do many other tricks.
That's not possible. You can set the environment for child processes only.
flock() sounds like it may be your friend.
http://beej.us/guide/bgipc/html/multi/flocking.html
You may also want to look at Semaphores or SHM (Shared Memory).
https://beej.us/guide/bgipc/html/multi/semaphores.html
http://beej.us/guide/bgipc/html/multi/shm.html
It all depends on the level of coordination you want. File locks will be good enough for one process to say stay out while I'm working. Semaphores and shared memory would allow you to coordinate access.

Resources