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;
}

Reply via email to