Controlling the environ passed to child process by bash - linux

I am using x86_64 GNU/Linux with bash
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
system("set > setc"); // A subset of `$ set`
return 0;
}
I can see the file setc contains a subset of $ set.
I am feeling curious as to know how the shell (parent process) decides what to supply to child process and what not to?
What if I want to supply more environ variables to child process? How one can control that?

A shell variable can be either exported or not exported. The shell will only pass exported variables to child processes. In bash, you can export a variable(for example, $var) by executing export var.

Related

Environment variables set with setenv() aren't shown in /proc/<PID>/environ

The app with setenv() C function sets values of three environment variables. By the app behavior it is clear that env. vars are set properly. They configure paths for OpenSSL config file, config files and modules folder.
Below is a minimum example that illustrates the issue.
// setenv_example.c
#include <stdlib.h>
#include <stdio.h>
int main() {
setenv("my_var", "my_value", 1);
printf("Press any key to exit");
getchar();
return 0;
}
In one terminal window ($ is command prompt):
$ gcc setenv_example.c -o setenv_example
$ ./setenv_example
Press any key to exit
In another terminal window
$ ps -a | grep setenv
164615 pts/5 00:00:00 setenv_example
$ cat /proc/164615/environ | tr '\0' '\n' | grep my
<empty output>
How does one see environment variables set with setenv() of the running process on Linux (Debian 11)?
How does one see environment variables set with setenv() of the running process
It is not (that easily) possible.
/proc/<pid>/environ contains initial program environment, as passed when invoked exec.
If your program is compiled with debugging symbols, you can attach a debugger to your program and read the global environ variable.

execv system call not running as desired

I use Linux and while compiling any c or cpp file, I use gcc or g++ respectively in terminal.
Common syntax : g++ program.cpp
But now I wish to compile files using flags.
Eg: g++ -Wall -Wextra -std=c++11 program.cpp
I will use more 10 flags to compile my program. But I don't want to remember and type that while compiling in terminal.
Now I wish to create a c program involving syscalls (exec) to get my job done using below syntax:
./compile program.cpp
But there's some problem while using exec in my below code
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int main(int args, char* argv[]){
char* arguments[10]={"-std=c++11","-Wall","-Wextra","-pedantic","-Wshadow","-fsanitize=address","-fsanitize=undefined","-fstack-protector"}; //consists of flags with which i will compile the program passed as argument
printf("%s\t %s",argv[0],argv[1]);
if(args==2){
arguments[8]=argv[1];
arguments[9]=(char*)NULL;
}else{
printf("only one argument allowed!");// just to check if i pass arguments correctly
}
printf("%s\t %s",arguments[8],arguments[9]);// just to check if my arguments array is correct
if(execv("/bin/g++",arguments)==-1){ // to my suprise this line runs before above printing lines. What is the reason/solution?
perror("execv failed!");
exit(1);
}
return 0;
}
The above code compiles successfully without error.
But I think execv runs even before I insert passed argument in argument array.
Because of which, program runs with error execv failed: no such file or directory
Followed by the printfs.
Please tell me where I went wrong.
So I finally solved the ambiguity in the above code. I made two radical changes to my code.
Instead of directly assigning argument strings while declaration of string array,
char* arguments[10]={"-std=c++11","-Wall","-Wextra","-pedantic","-Wshadow","-fsanitize=address","-fsanitize=undefined","-fstack-protector"};
I chose to just assign strings one by one.
char* arguments[10];
arguments[0]="g++";
arguments[1]="-Wall";
arguments[2]="-Wextra";
and so on
And this fixed the segmentation faults in my code.
This time I used execvp() instead of execv() system call because of which I don't need to explicitly declare full path to the command usr/bin/g++ and so on. In execvp only command name is enough.
So my new code looks like this:
#include<stdio.h>
//#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
int main(int args, char* argv[]){
char* arguments[10];
//printf("%s\t %s\n",argv[0],argv[1]);
arguments[0]="g++";
arguments[1]="-Wall";
arguments[2]="-Wextra";
arguments[3]="-pedantic";
arguments[4]="-Wshadow";
arguments[5]="-fsanitize=address";
arguments[6]="-fsanitize=undefined";
arguments[7]="-fstack-protector";// to add more flags make changes in this array.
if(args==2){
arguments[8]=argv[1];
arguments[9]=(char*)NULL;
if(execvp(arguments[0],arguments)==-1){
perror("execv failed!");
exit(1);
}
}else{
printf("->Only one argument(c/cpp file) allowed.\n->Requtired syntax: ./compile program.cpp\n");
}
return 0;
}
Another question I had was that all printfs that were before execv() system call would get printed only after execv() got executed. And as #MYousefi Sir commented, it was because of buffer not being full. And as suggested, adding "\n" in printfs solved the problem.

How to get cwd for relative paths?

How can I get current working directory in strace output, for system calls that are being called with relative paths? I'm trying to debug complex application that spawns multiple processes and fails to open particular file.
stat("some_file", 0x7fff6b313df0) = -1 ENOENT (No such file or directory)
Since some_file exists I believe that its located in the wrong directory. I'd tried to trace chdir calls too, but since output is interleaved its hard to deduce working directory that way. Is there a better way?
You can use the -y option and it will print the full path. Another useful flag in this situation is -P which only traces syscalls relating to a specific path, e.g.
strace -y -P "some_file"
Unfortunately -y will only print the path of file descriptors, and since your call doesn't load any it doesn't have one. A possible workaround is to interrupt the process when that syscall is run in a debugger, then you can get its working directory by inspecting /proc/<PID>/cwd. Something like this (totally untested!)
gdb --args strace -P "some_file" -e inject=open:signal=SIGSEGV
Or you may be able to use a conditional breakpoint. Something like this should work, but I had difficulty with getting GDB to follow child processes after a fork. If you only have one process it should be fine I think.
gdb your_program
break open if $_streq((char*)$rdi, "some_file")
run
print getpid()
It is quite easy, use the function char *realpath(const char *path, char *resolved_path) for the current directory.
This is my example:
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
int main(){
char *abs;
abs = realpath(".", NULL);
printf("%s\n", abs);
return 0;
}
output
root#ubuntu1504:~/patches_power_spec# pwd
/root/patches_power_spec
root#ubuntu1504:~/patches_power_spec# ./a.out
/root/patches_power_spec

Unable to make executable that properly communicates with node.js

I'm testing the communication between node.js and executables launched as child processes. An executable will be launched from within node.js via child_process.spawn() and its output will be monitored by node.js. I'm testing this capability both on Linux and Windows OSs.
I've successfully spawned tail -f /var/log/syslog and listened to its output, but my own executables can't seem to write correctly to stdout (in whatever form it exists when captured by node.js).
Test code:
#include <iostream>
#include <stdio.h>
#include <unistd.h>
int main()
{
using namespace std;
long x = 1;
while (true)
{
fprintf(stdout, "xtime - %ld\n", x++);
usleep(1000000);
}
}
(Note: some includes may be useless; I've not checked them)
stdout output is not automatically flushed (at least on *nix) when stdout is not a tty (even if there is a newline in the output, otherwise a newline generally flushes when stdout is a tty).
So you can either disable stdout buffering entirely via setbuf(stdout, NULL); or you can manually flush output via fflush(stdout);.

Getting current working directory within kernel code

I am working on a project in which I need to know the current working directory of the executable which called the system call. I think it would be possible as some system calls like open would make use of that information.
Could you please tell how I can get the current working directory path in a string?
You can look at how the getcwd syscall is implemented to see how to do that.
That syscall is in fs/dcache.c and calls:
get_fs_root_and_pwd(current->fs, &root, &pwd);
root and pwd are struct path variables,
That function is defined as an inline function in include/linux/fs_struct.h, which also contains:
static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd)
and that seems to be what you are after.
How do you do that in a terminal ? You use pwd which looks at the environment variable named PWD.
#include <stdlib.h>
int main(int ac, char **av) {
printf("%s\n", getenv("PWD");
return 0;
}
If you want to know in which directory the executable is located you can combine the information from getenv and from argv[0].

Resources