Hello,
I found out that there are several places inside wine's C code that use
the BINDIR macro. This is not good and leads to strange behavior when I
try to run wine before properly installing it in /usr/local (yes, I set up
PATH and LD_LIBRARY_PATH to prefer my temporary directories first).
BINDIR is used in:
scheduler/client.c: execl( BINDIR "/wineserver", "wineserver", NULL );
scheduler/process.c: argv[0] = BINDIR "/wine"
windows/x11drv/clipboard.c: execl( BINDIR "/wineclipsrv", "wineclipsrv",
Instead, I suggest detecting the BINDIR during the initialization of wine.
Using argv[0] of wine's main it is possible to figure out where wine
executable came from.
I have written a short code that detects the directory of an executable,
based on its argv[0] value. Since I am not an expert in wine, I thought it
was not a good idea to integrate into wine myself.
Michael
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
/* Find full path to the given executable.
* Assuming that input executable name does not contain a '/' and assuming
* that $PATH is to be used for its search.
*
* exe_name: the name of the executable read from argv[0]
* return: heap-allocated full path.
*/
static char *get_fullpath_from_path(const char*exe_name)
{
const char *path= getenv("PATH");
const char *begin, *end;
unsigned size;
char *fullpath;
struct stat stat_buf;
assert(path != NULL); /* $PATH *should*i be defined here */
/* allocate enough memory */
fullpath= malloc( strlen(path) + 1 + strlen(exe_name) + 1 );
assert(fullpath != NULL);
/* I don't like strtok, so instead it is all done by hand */
for (begin= path ; begin ; begin= end)
{
end= strchr(begin, ':');
/* find the last '\0' character instead of NULL */
if (end == NULL)
{
size= strlen(begin);
}
else
{
size= end-begin;
end++;
}
memcpy(fullpath, begin, size);
fullpath[size]='/';
strcpy(fullpath + size + 1, exe_name);
/* Here, fullpath contains a potential full path to the executable:
* Test it.
*/
if (stat(fullpath,&stat_buf) == 0 && S_ISREG(stat_buf.st_mode) )
{
/* FIXME: This check may give executables that we have no
* permissions to execute.
*/
if ( (stat_buf.st_mode & S_IXUSR) == S_IXUSR)
return fullpath;
}
}
abort(); /* The executable must be somewhere */
}
/* Find the full path where the given executable is in.
* Assuming that $PATH is not to be used for its search.
*
* exe_name: the name of the executable read from argv[0]
* return: heap-allocated full path.
*/
static char *get_fullpath_from_name(const char*exe_name)
{
char *fullpath= NULL;
char *cwd;
int size;
if (exe_name[0] == '/')
{
fullpath= strdup(exe_name);
}
else
{
/* Get rid of the annoying ./ prefix */
if (exe_name[0] == '.' && exe_name[1] == '/')
exe_name += 2;
/* get the current directory - without relying on PATH_MAX */
size= 1024;
cwd= malloc(size);
assert(cwd!=NULL);
while(getcwd(cwd, size-1) == NULL)
{
size *=2;
cwd= realloc(cwd, size);
assert(cwd!=NULL);
}
/* construct the full path to the executable using cwd */
fullpath = malloc( strlen(cwd) + 1 + strlen(exe_name) + 1);
assert(fullpath != NULL);
sprintf(fullpath, "%s/%s", cwd, exe_name);
free(cwd);
}
return fullpath;
}
/* Find the full path to the directory where the given executable is in.
* The executable is given in the the same format as used by argv[0]
*
* exe_name: the name of the executable read from argv[0]
* return: heap-allocated full path to a '/' terminated directory.
*/
char *get_bindir(const char* exe_name)
{
char *bindir;
char *tmp;
if (strrchr(exe_name, '/' ) == NULL)
{
tmp= get_fullpath_from_path(exe_name);
bindir= get_fullpath_from_name(tmp);
free(tmp);
}
else
{
bindir= get_fullpath_from_name(exe_name);
}
/* strip the name of the executable from the full path */
tmp= strrchr(bindir, '/');
++tmp;
*tmp= '\0';
return bindir;
}
int main(int argc, char* argv[])
{
char *bindir=get_bindir(argv[0]);
printf("bindir=%s\n", bindir);
free(bindir);
return 0;
}