Is there a way to enumerate environment variables and retrieve values using C?
Take a look at the environ global variable.
extern char **environ;
It might be defined in unistd.h (take a look at the environ (5) man page above).
Here's a little code demo I wrote:
#include <stdio.h>
extern char **environ;
int main()
{
for (char **env = environ; *env; ++env)
printf("%s\n", *env);
}
Here's how to use it:
matt#stanley:~/Desktop$ make enumenv CFLAGS=-std=c99
cc -std=c99 enumenv.c -o enumenv
matt#stanley:~/Desktop$ ./enumenv
ORBIT_SOCKETDIR=/tmp/orbit-matt
SSH_AGENT_PID=1474
TERM=xterm
SHELL=/bin/bash
... (so forth)
The environment information can be passed as an extra parameter to main. I don't know if it is compliant or not, but it definitely works (tested on Ubuntu). Just define the extra argument and its an array of char pointers terminated by a NULL pointer. The following will print out the lot.
#include <stdio>
int main(int argc, char *argv[], char *envp[])
{
int index = 0;
while (envp[index])
printf("%s\n", envp[index++];
}
There is a demo in the book "The Linux Programming Interface" at page 127.
Listing 6-3: Displaying the process environment
––––––––––––––––––––––––––––––––––––––––––––––––proc/display_env.c
#include "tlpi_hdr.h"
extern char **environ;
int
main(int argc, char *argv[])
{
char **ep;
for (ep = environ; *ep != NULL; ep++)
puts(*ep);
exit(EXIT_SUCCESS);
}
Related
I am trying to reset my program when it receives a SIGSEGV by using ececl() in my signal handler. But, my current program needs commandline arguments to start that I can pass via execl() + 1 extra argument "RESTART" to notify the program that it just restarted instead of a fresh start.
But how can I pass my argv[] via exec()?
Objective:
execl("./myprog","./myprog",argv[1],argv[2],...,argv[argc],"RESTART");
OR
execl("./myprog","./myprog","RESTART",argv[1],argv[2],...,argv[argc]);
Use execv():
SYNOPSIS
#include <unistd.h>
...
int execv(const char *path, char *const argv[]);
...
The execv(), execvp(), and execvpe() functions provide an array of
pointers to null-terminated strings that represent the argument list
available to the new program. The first argument, by convention,
should point to the filename associated with the file being executed.
The array of pointers must be terminated by a null pointer.
Perhaps like this:
int main( int argc, char **argv )
{
...
int rc = execv( "./myprog", argv );
}
You may need to modify specific values in argv or create an entirely new argument array to fit what you need.
You need to save argv in a global, either from main:
static char **Argv;
int main(int c, char **v) { Argv = v; //...
or from a gcc constructor:
static char **Argv;
__attribute__((constructor))
static void ctor(int c, char **v) { Argv = v; }
Then you can do what you want:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
static char **Argv;
static void hndlr(int s)
{
execv("/proc/self/exe", Argv);
_exit(127);
}
int main(int argc, char **argv)
{
Argv = argv;
struct sigaction sa = { .sa_handler = hndlr, .sa_flags = SA_NODEFER };
sigaction(SIGSEGV, &sa, 0);
sleep(1);
fputs("start\n", stderr);
//keep re-executing the same program
raise(SIGSEGV);
}
Note that without the SA_NODEFER, you'll only see the message twice, because SIGSEGV will be blocked during the second run of the executable.
While this should be defined (especially if you add a signal stack so that you can handle stack overflows with this too), wrappers scripts/programs are a safer and more robust way of doing this. With the SISEGV handler approach, you aren't really starting from scratch -- you are inheriting signal masks, effective uids/gids, workings directories, open file descriptors, etc. etc., whereas with a wrapper script you start from a well defined state.
I was playing around with symbols and function pointers recently and noticed that though the following code runs fine:
#include <stdio.h>
int main(int argc, const char * argv[]) {
printf("%p\n",printf); // <--this line makes it work
int (*printfptr)(const char * restrict, ...);
printfptr = 0x1001fe910;
(*printfptr)("Hello world\n");
return 0;
}
This does not:
#include <stdio.h>
int main(int argc, const char * argv[]) {
// printf("%p\n",printf); // <-- commenting this out breaks it
int (*printfptr)(const char * restrict, ...);
printfptr = 0x1001fe910;
(*printfptr)("Hello world\n");
return 0;
}
(EXC_BAD_ACCESS)
How come dereferencing the exact same pointer causes issues when there is no reference to printf in the code? Even this works fine:
#include <stdio.h>
int main(int argc, const char * argv[]) {
int (*printfptr)(const char * restrict, ...);
printfptr = 0x1001fe910;
(*printfptr)("Hello world\n");
return 0;
}
void *_ = printf; // <-- because of this
Why is this?
On shared objects (.so) the symbols are really resolved only at the moment of first use. By default the linker sets the option -z lazy which tells:
When generating an executable or shared library, mark it to
tell the dynamic linker to defer function call resolution to
the point when the function is called (lazy binding), rather
than at load time. Lazy binding is the default.
You can change that behaviour by providing option -z now.
man ld for all gory details.
EDIT: Resolving a symbol is done with dynamic link API on POSIX systems. Functions dlsym(), dlopen(), dlclose() and dlerror() defined in <dlfcn.h>. This edition added so that you can search for these names.
I have this code:
#include <stdio.h>
#include <strings.h>
int main(int ac, char **av)
{
char text[] = "PASS_KEY";
printf("Hey\n");
return 0;
}
I know those strings are literally next one to one in memory.
How can I redefine printf with LD_Preload to read text?
Defining a shim printf to dump memory around the pointer it is passed is not a difficult task:
#include <stdio.h>
void dump(const char *data) {
fwrite(data - 32, 1, 64, stdout);
}
int printf(const char *data, ...) {
dump(data);
}
Compile with:
gcc -c -fPIC print.c -o print.o
ld -shared -o libprint.so print.o
and now you can LD_PRELOAD=./libprint.so ./program and get the key. Or you could... You have a few separate problems here.
GCC at least optimizes a printf with no placeholders in the format string to a puts. So what gets called by your program is not printf. Well, let's shim puts too:
int puts(const char *data) {
dump(data);
}
now you get the dump on screen:
..............Hey........
so it's working. But there's no trace of the key. Why?
Because text is a local variable (array) and "Hey\n" is a constant string. So text is allocated on the stack and "Hey\n" in the constant pool, which is not exactly "next to it". Your assumption is wrong. If you modify the program as:
#include <stdio.h>
#include <strings.h>
int main(int ac, char **av)
{
char text[] = "PASS_KEY";
char format[] = "Hey\n";
printf(format);
return 0;
}
which, incidentally, is a thing you WOULD THINK TWICE BEFORE DOING because using non-constant format strings for printf is B.A.D. in most cases, it will work:
............Hey
PASS_KEY.
Success!
I saw redefine function here using macro in c. So I am interesting is it possible to redefine main function?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
printf("Original main function\n");
return 0;
}
int _main(int argc, char **argv)
{
printf("New Original main function\n");
return main(argc, argv);
}
#ifdef DEBUG
#define main(argc, argv) _main(argc, argv)
#endif
Code compiled with out any problem but I am getting:
Original main function
So I am wondering why it does not work? When I use same techniques for malloc and free functions it works perfect. So what is wrong?
Why I want to do something like this? I want to do some code before main function will be executed. Is it possible in this way? if not is there are some other way?
P.S.: Sorry I did not mention in question. I am using gcc in Ubuntu OS. If you are down voting please give a reason in comments. You comments is very useful to my further development.
If you want to change entry point of your program, you don't need play with defines. You can use linker's -e option for that:
gcc -Wl,-e,__main ...
Please note extra underscore. Depending on some options, the symbol name can be different.
If your question is really: "can i execute code before main?" Then the answer is an emphatic YES.
Since you are using GCC, you can use function attributes (http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html) to mark a function as a constructor.
void pre_main_function (void) __attribute__ ((constructor));
A useful example can be found at http://www.geeksforgeeks.org/functions-that-are-executed-before-and-after-main-in-c/
EDIT
The following syntax can also be used:
__attribute__ (( constructor(n) ))
where n specifies the priority, allowing you to mark multiple functions to be executed before main whilst giving you control over the execution order ( the lower the value of n, the earlier the function is executed.
Your #define does not change the main function at all - it is a macro preprocessor.
The only effect of your #define will be to change the call to main in _main into a recursive call to _main(). But since _main is not called, this is dead code. This is what your code looks like after the preprocessor has run...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
printf("Original main function\n");
return 0;
}
int _main(int argc, char **argv)
{
printf("New Original main function\n");
return _main(argc, argv); /* recursive call due to macro replace */
}
This then leads to the next question - which is why redefine main at all? If you want some entirely different code to run on debug simply declare main as
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
#ifdef DEBUG
return debugApp( argc, argv);
#else
return productionApp( argc, argv);
#endif
}
N.B Just because you can do something doesn't mean you should do it. :-)
I've got
main.c
something.h
something.c
How can I use
char* argv[]
in something.c file without having to call a function from something.c with argv[] as parameter?
Not that I recommend this in general, but:
main.c:
char **global_argv;
int main(int argc, char *argv[])
{
global_argv = argv;
...
}
something.c:
extern char **global_argv;
You can use global variables, but that isn't really clean code. There is nothing problematic with passing argv as parameter. However, you should do sanity checks in your main to control the data you get from the command line.