Does LoadLibrary parse environment variables such as %windir% - c

If I do LoadLibrary("%windir%\\system32\\ole32.dll") does that mean Windows will ONLY load from "c:\windows\system32\ole32.dll" ? Also does LoadLibrary() in C understand the environment variable?

as Serge said and carefully tested, LoadLibrary does not do environment variable substitution in path.
however, there is a function in the windows API to replace environment variables in strings: ExpandEnvironmentStrings(). you can perform the required substitution on your path before calling LoadLibrary().

The docs for LoadLibrary clearly state that:
If the string specifies a full path, the function searches only that
path for the module.
That said, they don't mention support for environment variables substitution. I seriously doubt they do support environment variables substitution: That's a shell feature, not a kernel API one.
BTW, that means LoadLibrary() would consider %windir%\blah.dll as a relative path since it doesn't start with a drive letter or a UNC path. Hence it would look through the whole series of directories, looking for a subdir named %windir%, which it's not likely to find!
I gave it a quick test: It confirms my opinion. Error = 126 : The specified module could not be found.

Related

File Config, creation and usage in C unix

I'm trying to understand how I can create a ".config" file containing a bunch of parameters to later use to set up the variables in my C project on Unix.
I created my ".config" file using sudo nano test.config and wrote some stuff inside such as:
#N is this
N 10
#p is that
p 0.002
#T is this
T 10
Now that I did that how can I read its content and use it to initialize my variables?
The several answers to this question explain how to parse that config file, but you could use standard parsing techniques (perhaps your own recursive descent parser) or Glib's lexical scanning or key-value pair parser (or use something else). You certainly should define and document (perhaps using EBNF) what is the format of that textual configuration file (and what the various entries there represent: for example, if that configuration file refers to other files, how do you handle spaces in such file paths, etc....). A common (but not universal) convention is to consider as comments so skip any line starting with #.
Another question is how to get that config file while running in an arbitrary working directory. You just need to build the absolute path of your file (for fopen(3) or open(2)), e.g. with
char configpath[100];
snprintf(configpath, sizeof(configpath), "%s/.test.config", getenv("HOME"));
You could test before that getenv("HOME") is not NULL, but in practice that is very unlikely; see environ(7) and getenv(3); and the case when it gives a very long file path is also unlikely; you might test that snprintf(3) returns a count less than sizeof(configpath) or use asprintf(3).
You might use other functions, e.g. glob(3) or wordexp(3) to get that file path (but you probably should stick to snprintf or asprintf with getenv("HOME")...).
You might consider instead embedding some scriptable interpreter like lua or guile in your program (but that is a strong architectural design decision). Then the configuration file becomes some (Turing-complete!) script.
BTW, there is no need to use sudo to edit that configuration file (under your home directory), and you might decide to also read some system-wide configuration under /etc/

How to know the path of current binary file? [duplicate]

This question already has answers here:
Finding current executable's path without /proc/self/exe
(14 answers)
Closed 7 years ago.
Is there a way in C/C++ to find the location (full path) of the current executed program?
(The problem with argv[0] is that it does not give the full path.)
To summarize:
On Unixes with /proc really straight and realiable way is to:
readlink("/proc/self/exe", buf, bufsize) (Linux)
readlink("/proc/curproc/file", buf, bufsize) (FreeBSD)
readlink("/proc/self/path/a.out", buf, bufsize) (Solaris)
On Unixes without /proc (i.e. if above fails):
If argv[0] starts with "/" (absolute path) this is the path.
Otherwise if argv[0] contains "/" (relative path) append it to cwd
(assuming it hasn't been changed yet).
Otherwise search directories in $PATH for executable argv[0].
Afterwards it may be reasonable to check whether the executable isn't actually a symlink.
If it is resolve it relative to the symlink directory.
This step is not necessary in /proc method (at least for Linux).
There the proc symlink points directly to executable.
Note that it is up to the calling process to set argv[0] correctly.
It is right most of the times however there are occasions when the calling process cannot be trusted (ex. setuid executable).
On Windows: use GetModuleFileName(NULL, buf, bufsize)
Use GetModuleFileName() function if you are using Windows.
Please note that the following comments are unix-only.
The pedantic answer to this question is that there is no general way to answer this question correctly in all cases. As you've discovered, argv[0] can be set to anything at all by the parent process, and so need have no relation whatsoever to the actual name of the program or its location in the file system.
However, the following heuristic often works:
If argv[0] is an absolute path, assume this is the full path to the executable.
If argv[0] is a relative path, ie, it contains a /, determine the current working directory with getcwd() and then append argv[0] to it.
If argv[0] is a plain word, search $PATH looking for argv[0], and append argv[0] to whatever directory you find it in.
Note that all of these can be circumvented by the process which invoked the program in question. Finally, you can use linux-specific techniques, such as mentioned by emg-2. There are probably equivalent techniques on other operating systems.
Even supposing that the steps above give you a valid path name, you still might not have the path name you actually want (since I suspect that what you actually want to do is find a configuration file somewhere). The presence of hard links means that you can have the following situation:
-- assume /app/bin/foo is the actual program
$ mkdir /some/where/else
$ ln /app/bin/foo /some/where/else/foo # create a hard link to foo
$ /some/where/else/foo
Now, the approach above (including, I suspect, /proc/$pid/exe) will give /some/where/else/foo as the real path to the program. And, in fact, it is a real path to the program, just not the one you wanted. Note that this problem doesn't occur with symbolic links which are much more common in practice than hard links.
In spite of the fact that this approach is in principle unreliable, it works well enough in practice for most purposes.
Not an answer actually, but just a note to keep in mind.
As we could see, the problem of finding the location of running executable is quite tricky and platform-specific in Linux and Unix. One should think twice before doing that.
If you need your executable location for discovering some configuration or resource files, maybe you should follow the Unix way of placing files in the system: put configs to /etc or /usr/local/etc or in current user home directory, and /usr/share is a good place to put your resource files.
In many POSIX systems you could check a simlink located under /proc/PID/exe. Few examples:
# file /proc/*/exe
/proc/1001/exe: symbolic link to /usr/bin/distccd
/proc/1023/exe: symbolic link to /usr/sbin/sendmail.sendmail
/proc/1043/exe: symbolic link to /usr/sbin/crond
Remember that on Unix systems the binary may have been removed since it was started. It's perfectly legal and safe on Unix. Last I checked Windows will not allow you to remove a running binary.
/proc/self/exe will still be readable, but it will not be a working symlink really. It will be... odd.
On Mac OS X, use _NSGetExecutablePath.
See man 3 dyld and this answer to a similar question.
For Linux you can find the /proc/self/exe way of doing things bundled up in a nice library called binreloc, you can find the library at:
http://autopackage.org/docs/binreloc/
I would
1) Use the basename() function: http://linux.die.net/man/3/basename
2) chdir() to that directory
3) Use getpwd() to get the current directory
That way you'll get the directory in a neat, full form, instead of ./ or ../bin/.
Maybe you'll want to save and restore the current directory, if that is important for your program.

How to find execute files in Linux?

I wants to get the names of execute files in some directory in Linux.
How can I do it?
I tried to use opendir like this:
dir = opendir(directoryName);
I need to get only the names of the execute files.
I programming in C.
thanks :)
You should define what you mean by executable files.
That could be any file with its execute bit (it is the owner, group, or other) set. Then test with access(2) & X_OK and/or use stat(2).
That could also be only ELF executables. See elf(5); then the issue might be to check that a file could indeed be executed, which might be difficult (what about missing library dependencies? or ill-formed ELF files?). Maybe use libelf (and/or libmagic to do the equivalent of file(1) command).
To scan recursively a file tree, use nftw(3); to scan just a directory use opendir(3) & readdir(3) (don't forget the closedir!), then you'll probably need to build the complete file path from each directory entry (perhaps using snprintf(3) or asprintf(3))
See also Advanced Linux Programming

How to package Tcl libraries in my own program?

In my c++ program, I used Tcl library and linked libtcl8.5.so, but the target hosts don't have tcl8.5, so I copied the libtcl8.5.so and tcl8.5 dir which contains init.tcl there, and set the environmet variable TCLLIBPATH to path/to/copied/tcl8.5, but when my program call Tcl_Init, it failed and said “package not known”.
It seems the copied tcl8.5/ cannot be init correctly.
How can I solve this problem?
If you change the location of the script library directory (tcl8.5/ in your case), you need to tell the shared library part of Tcl where it is. You do this using the TCL_LIBRARY environment variable, which if set should contain the absolute path that is the location of that directory (technically, the directory that contains init.tcl).
In a normal installation of Tcl, the correct location of that directory is baked directly into the shared library, but when you move things round (or when you are running Tcl's make test) the environment variable allows you to override.
You might wish to look into alternate packaging mechanisms; there have already been a few questions in the tcl tag on this matter (but the usual favorite — a starkit — is probably not suitable for your case given the fact that the program is mainly C++).

What files does setlocale() use?

Compiling on the shared CentOS server is not allowed. Therefore, I compile my program in my Debian computer, linking it with Debian's system libraries such as libc, etc. Then I upload my program and the Debian system libraries and my program works. The only problem is that setlocale() does not work at CentOS. CentOS has "en_US.utf8" installed and works on all programs except mine. I suspect that I have to also upload Debian's locale files ? How could I link my program to the Debian locale files ? I tried to use LOCPATH but I am unsure of how it works exactly. Which files do I have to link to and how ?
C program:
setenv("LOCPATH", "/", 1);
if (setlocale(LC_ALL, "en_US.utf8") == NULL) {
puts("not set");
}
I used a hex editor to modify the path to /usr/lib/locale/locale-archive which apparently is the only file that setlocale() uses according to strace. This method is dirty but it worked.
According to man LOCPATH, this environment variable is non-standard, so its use is not recommended. No examples are given anywhere of how to use it nor what is meant exactly by a path to "locale's object files".
I guess the only real way of modifying the path is a glibc modification and recompilation.
Quote: LOCPATH is an environment variable that tells the setlocale() function the name of the directory from which to load locale object files. If LOCPATH is not defined, the default directory /usr/lib/nls/locale is searched. LOCPATH is similar to the PATH environment variable; it contains a list of z/OS UNIX directories separated by colons.
So just specifying / and hoping that it does a recursive search will not work.
You could also produce a static binary and upload that to the host.

Resources