I am trying some exec family functions in C and I have few questions concerning environment variables, here's my code:
find.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv){
char *line = getenv("LINE");
char *target = getenv("TARGET");
if(!line || !target){
printf("LINE or/and TARGET not found\n");
return 1;
}
if(strstr(line,target))
puts(line);
return 0;
}
process.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(){
putenv("LINE=Hello world");
putenv("TARGET=Hello");
execl("./find","./find",NULL);
return 0;
}
output on "gcc process.c -o process && ./process"
Hello world
Quick explanation of the code.
find.c needs to read two environment variables and check if the TARGET variable value is a substring of the LINE variable value. If so, then print the LINE variable value.
process.c replace itself by executing find.c.
Questions
Knowing that the correct way of doing this is using execle, why did the program process.c work using execl and putenv ? In other words, creating environment variable in a process that get replaced doesn't replace the environment variable as well if not passed via execle ?
Does forking a process has the same answer to the above question ? So forking a process copies, replace or share the environment variables ?
Thank you
Knowing that the correct way of doing this is using execle, why did the program process.c work using execl and putenv?
This is explained in the man page:
The execle() and execvpe() functions allow the caller to specify the environment of the executed program via the argument envp. [...] The other functions take the environment for the new process image from the external variable environ in the calling process.
Note that environ is what's modified by putenv.
Does forking a process has the same answer to the above question ?
Forking duplicates the environment variables. From the man page:
The new process, referred to as the child, is an exact duplicate of the calling process, referred to as the parent, except for the following points:
[... list of points, none of which refer to environment variables ...]
Related
Say I putenv an environment variable ABC and then do an execl, or I do an execle and add ABC to the envp array of pointers that I pass to execle.
Is there a difference, if any?
putenv adds an environment variable to the current environment. Using execl will then use that environment.
execle will use the environment argument as the entire environment, i.e. it won't inherit the existing environment variables.
It's easy to see this with a simple program that just runs env (which prints out the current environment):
#include <unistd.h>
int main()
{
execl("/bin/env", "/bin/env", NULL);
}
Running this on my machines prints out a lot of environment variables such as HOME, etc.
#include <unistd.h>
int main()
{
char* env[] = { NULL };
execle("/bin/env", "/bin/env", NULL, env);
}
This prints nothing, because the environment is empty.
I'm currently trying to change the process name of a process so I can read the more easily with htop, top, .... I want to LD_PRELOAD this code into another process so it gets renamed by an environemt variable.
I found a lot of stuff in the internet, but nothing works:
prctl(PR_SET_NAME, "Test");
This does not work because htop is not honoring the name.
Nginx setproctitle (Link) doesn't work as well, because it strips the parameters (which are needed by the process).
I tried everything I found and now I'm out of ideas.
Is this even possible in linux? And how?
Just run your program by shell script or your program through exec and pass desired name as argv[0]:
#/bin/bash
exec -a fancy_name a.out ...
or C/C++:
execl( "./a.out", "fancy_name", ... );
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define NEW_NAME "hello_world"
int main(int argc, char **argv) {
if(strcmp(argv[0], NEW_NAME)) {
argv[0] = NEW_NAME;
execv("/proc/self/exe", argv);
fputs("exec failed", stderr);
return 1;
}
while(1) // so it goes to the top
;
}
I want to change the value of PATH variable inside the C program and then see the changed value in the shell using which I run this program.
Doing something like this,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main () {
char *path = getenv ("PATH");
printf ("%s\n\n", path);
setenv ("PATH", strcat (path, ":~/myNewPath/"), 1);
printf ("%s\n\n", path);
int pid = fork ();
if (pid == -1)
abort ();
if (pid == 0) {
} else {
// use execlp? how? source? any hints?
}
return 0;
}
If I use source command in the exec* system call. What will be the syntax to update this PATH variable in the shell backwards?
This is impossible. There is no way for a subprocess to change its parent's environment variables.
To understand why it is impossible, look at the signature of execve
int execve(const char *program, char *const *argv, char *const *envp);
which is paired with the true signature of main on Unix systems
int main(int argc, char **argv, char **envp);
and perhaps you begin to understand that as far as the kernel is concerned, the environment variables are a second set of command line arguments. That they appear to be independently accessible via getenv and setenv etc, and appear to inherit from parent to child, is an illusion maintained by the C library.
For more detail on how this works, study the x86-64 ELF ABI specification, section 3.4.1 "Initial Stack and Register State" paying particular attention to figure 3.9 which shows the layout of the data copied by execve onto the newly created stack. (The document linked is specific to one CPU architecture, but the way this works is generally consistent across modern Unixes; fine details will of course vary from CPU to CPU and OS to OS.)
I have a c program running. I want to make the program sleep for certain period say 5 sec. I want this sleep to be induced from a text file containing command "sleep(5)". I want to pass this file through redirection operator (<) while executing the program
say ./a.out < samplefile.txt
This samplefile.txt contains sleep(5) command in it. I tried the above scenario but the c program is reading it as stream of characters like s,l,e,e,p which is not our intention.
could some one please help me on this issue.
You may make your program read the commands from the text file, parse them and behave as the commands say.
Instead of parsing, you may use the environment variables.
In your program, call to getenv in any place requires configuration. When calling to the program, make sure the environment is set with the required variables, or use this notation:
VAR1=VALUE1 VAR2=VALUE2 ./a.out
I'm not very clear what you want to achieve, but this may be a prompt.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
char buf[512];
scanf("%s", buf);
if (!strcmp(buf, "sleep(5)")) {
printf("sleep...\n");
sleep(5);
}
printf("over\n");
return 0;
}
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
how to find the location of the executable in C
I would like an executable to be able to discover its own path; I have a feeling that the answer is "you can't do this", but I would like this to be confirmed!
I don't think I can use getcwd(), because I might not be executing it from the same directory. I don't think I can use argv[0], because that is based on the string that's used to execute it. Are there any other options?
Rationale
The real problem is that I'd like to place an executable somewhere on a filesystem, and place a default config file alongside it. I want the executable to be able to read its config file at runtime, but I don't want to hardcode this location into the executable, nor do I want the user to have to set environment variables. If there's a better solution to this situation, I'm all ears...
The file /proc/self/exe is a simlink to the currently running executable.
Edit: It was pointed out that using /proc/self/exe is more straightforward. That is entirely true, but I didn't see any benefit in editing the code. Since I still get comments about it, I've edited it.
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
int main()
{
char dest[PATH_MAX];
memset(dest,0,sizeof(dest)); // readlink does not null terminate!
if (readlink("/proc/self/exe", dest, PATH_MAX) == -1) {
perror("readlink");
} else {
printf("%s\n", dest);
}
return 0;
}
Initial answer:
You can use getpid() to find the pid of the current process, then read /proc/<pid>/cmdline (for a human reader) or /proc/<pid>/exe which is a symlink to the actual program. Then, using readlink(), you can find the full path of the program.
Here is an implementation in C:
#include <sys/types.h>
#include <unistd.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
int main()
{
char path[PATH_MAX];
char dest[PATH_MAX];
memset(dest,0,sizeof(dest)); // readlink does not null terminate!
pid_t pid = getpid();
sprintf(path, "/proc/%d/exe", pid);
if (readlink(path, dest, PATH_MAX) == -1) {
perror("readlink");
} else {
printf("%s\n", dest);
}
return 0;
}
If you want to try, you can then compile this, make a symlink from the executable to an other path, and call the link:
$ gcc -o mybin source.c
$ ln -s ./mybin /tmp/otherplace
$ /tmp/otherplace
/home/fser/mybin
Use the proc filesystem
Your flow would be:
Get pid of executable
look at /proc/PID/exe for a symlink
Well, you have to use getcwd() in conjuction with argv[0]. The first one gives you the working directory, the second one gives you the relative location of the binary from the working directory (or an absolute path).
Get your name from argv[0] then call out to the which command. This will obv only work if your executable is in $PATH.