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.
Related
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)
I'm writing an application with Producer who makes and sends messages and Consumer who is getting the messages. I have to set environment variable in producer app and read it in consumer app.
In producer app I did this command
putenv("MSG_KEY=15");
And in the consumer app i tried to get the variable like this
char *z=getenv("MSG_KEY");
But it doesn't return any value (I get nil value). If I write the same command in producer it works if I use putenv() few lines before. I think the problem is that it sets variable only locally so I cannot access it from another program but I don't know how to solve it.
Don't know if it matters but I'm using Linux system.
Environment variables are private to a process. You cannot set them in one process and expect to read them in another process.
The only time you can communicate anything via environment variables to another process is from a parent process to a child, and only at the time that the parent spawns the child. The parent may copy, modify, add, or remove environment variables when it spawns the child. From then on they become entirely separated. Change that one process makes to the variables, is not visible to the other.
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.
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.
I have a directory monitoring application which works recursively by launching new processes.
I'd like to know if I'm the "root" process in this tree. I thought about trying to get the name of the caller process and check if it's the same as argv[0].
Is there a smarter way of doing this? Keep in mind, this is a Linux app.
Keep in mind, I don't have much time for this and I'm but a student, so a simple solution would be great.
Thanks for your time.
If you use fork() to create new processes, you can have a local variable initially set at zero that each child sets to 1 immediately after forking. Only the root process would still have it set at zero after a fork.
You could even increase it after each fork, which would let you know how deep in your process tree each process is.
EDIT:
If you cannot use this (e.g. because you do an exec() after fork), you can use any of the common ways that shells use to pass information to the programs that you launch:
Environment variables: call setenv() after fork() but before exec() - or add it in the environment when calling exec().
Use a special command line argument.
Use a special value for argv[0] when doing exec().
Have you the possibility to add an argument meaning "I'm not the root"? That seems the simplest approach.
If you are calling exec, add a special argument, or environment variable called "I_AM_NOT_THE_ROOT" which the child processes get, but the parent does not.
I recently used a command-line argument for this, but env variables might be more convenient.