elm/quicklaunch: Improve executable path search

Always search executable based on CWD if possible.
This way, elementary_run behaves more like sh where all of
sh script, sh ./script and sh `pwd`/script will work.

Also, remove quicklaunch-specific ELM_MAIN.
This needs some doc, but compiling with -fpie and -pie is much
better.

Note: There's an API/ABI break here, BUT these APIs are marked
as not to be used outside macros. And there isn't any macro
using them :)
This commit is contained in:
Jean-Philippe Andre 2013-11-04 15:12:51 +09:00
parent 9bb1ef2708
commit 9ab6c58530
3 changed files with 79 additions and 45 deletions

View File

@ -151,7 +151,7 @@ handle_run(int fd, unsigned long bytes)
} }
} }
#endif #endif
elm_quicklaunch_prepare(argc, argv); elm_quicklaunch_prepare(argc, argv, cwd);
elm_quicklaunch_fork(argc, argv, cwd, post_fork, NULL); elm_quicklaunch_fork(argc, argv, cwd, post_fork, NULL);
elm_quicklaunch_cleanup(); elm_quicklaunch_cleanup();
} }

View File

@ -143,7 +143,11 @@ extern EAPI double _elm_startup_time;
#ifndef ELM_LIB_QUICKLAUNCH #ifndef ELM_LIB_QUICKLAUNCH
#define ELM_MAIN() int main(int argc, char **argv) { int ret; _elm_startup_time = ecore_time_unix_get(); elm_init(argc, argv); ret = elm_main(argc, argv); return ret; } /**< macro to be used after the elm_main() function */ #define ELM_MAIN() int main(int argc, char **argv) { int ret; _elm_startup_time = ecore_time_unix_get(); elm_init(argc, argv); ret = elm_main(argc, argv); return ret; } /**< macro to be used after the elm_main() function */
#else #else
#define ELM_MAIN() int main(int argc, char **argv) { _elm_startup_time = ecore_time_unix_get(); return elm_quicklaunch_fallback(argc, argv); } /**< macro to be used after the elm_main() function */ /** @deprecated macro to be used after the elm_main() function.
* Do not define ELM_LIB_QUICKLAUNCH
* Compile your programs with -fpie and -pie -rdynamic instead, to generate a single binary (linkable executable).
*/
#define ELM_MAIN() int main(int argc, char **argv) { _elm_startup_time = ecore_time_unix_get(); return elm_quicklaunch_fallback(argc, argv); }
#endif #endif
/**************************************************************************/ /**************************************************************************/
@ -270,7 +274,7 @@ EAPI void elm_quicklaunch_seed(void);
/** /**
* Exposed symbol used only by macros and should not be used by apps * Exposed symbol used only by macros and should not be used by apps
*/ */
EAPI Eina_Bool elm_quicklaunch_prepare(int argc, char **argv); EAPI Eina_Bool elm_quicklaunch_prepare(int argc, char **argv, const char *cwd);
/** /**
* Exposed symbol used only by macros and should not be used by apps * Exposed symbol used only by macros and should not be used by apps
@ -290,7 +294,7 @@ EAPI int elm_quicklaunch_fallback(int argc, char **argv);
/** /**
* Exposed symbol used only by macros and should not be used by apps * Exposed symbol used only by macros and should not be used by apps
*/ */
EAPI char *elm_quicklaunch_exe_path_get(const char *exe); EAPI char *elm_quicklaunch_exe_path_get(const char *exe, const char *cwd);
/** /**
* Set a new policy's value (for a given policy group/identifier). * Set a new policy's value (for a given policy group/identifier).

View File

@ -843,63 +843,87 @@ static int (*qr_main)(int argc,
EAPI Eina_Bool EAPI Eina_Bool
elm_quicklaunch_prepare(int argc, elm_quicklaunch_prepare(int argc,
char **argv) char **argv,
const char *cwd)
{ {
#ifdef HAVE_FORK #ifdef HAVE_FORK
char *exe; char *exe, *exe2, *p;
char *exename;
if (argc <= 0 || argv == NULL) return EINA_FALSE; if (argc <= 0 || argv == NULL) return EINA_FALSE;
exe = elm_quicklaunch_exe_path_get(argv[0]); exe = elm_quicklaunch_exe_path_get(argv[0], cwd);
if (!exe) if (!exe)
{ {
ERR("requested quicklaunch binary '%s' does not exist\n", argv[0]); ERR("requested quicklaunch binary '%s' does not exist\n", argv[0]);
return EINA_FALSE; return EINA_FALSE;
} }
else
{
char *exe2, *p;
char *exename;
exe2 = malloc(strlen(exe) + 1 + 7 + strlen(LIBEXT)); exe2 = malloc(strlen(exe) + 1 + 7 + strlen(LIBEXT));
strcpy(exe2, exe); strcpy(exe2, exe);
p = strrchr(exe2, '/'); p = strrchr(exe2, '/');
if (p) p++; if (p) p++;
else p = exe2; else p = exe2;
exename = alloca(strlen(p) + 1); exename = alloca(strlen(p) + 1);
strcpy(exename, p); strcpy(exename, p);
*p = 0; *p = 0;
strcat(p, "../lib/"); strcat(p, "../lib/");
strcat(p, exename); strcat(p, exename);
strcat(p, LIBEXT); strcat(p, LIBEXT);
if (!access(exe2, R_OK | X_OK)) if (access(exe2, R_OK | X_OK) != 0)
{ {
free(exe); free(exe2);
exe = exe2; exe2 = NULL;
}
else
free(exe2);
} }
/* Try linking to executable first. Works with PIE files. */
qr_handle = dlopen(exe, RTLD_NOW | RTLD_GLOBAL); qr_handle = dlopen(exe, RTLD_NOW | RTLD_GLOBAL);
if (!qr_handle) if (qr_handle)
{ {
fprintf(stderr, "dlerr: %s\n", dlerror()); INF("dlopen('%s') = %p", exe, qr_handle);
WRN("dlopen('%s') failed: %s", exe, dlerror()); qr_main = dlsym(qr_handle, "elm_main");
free(exe); if (qr_main)
return EINA_FALSE; {
} INF("dlsym(%p, 'elm_main') = %p", qr_handle, qr_main);
INF("dlopen('%s') = %p", exe, qr_handle); free(exe2);
qr_main = dlsym(qr_handle, "elm_main"); free(exe);
INF("dlsym(%p, 'elm_main') = %p", qr_handle, qr_main); return EINA_TRUE;
if (!qr_main) }
{
WRN("not quicklauncher capable: no elm_main in '%s'", exe);
dlclose(qr_handle); dlclose(qr_handle);
qr_handle = NULL; qr_handle = NULL;
}
if (!exe2)
{
WRN("not quicklauncher capable: '%s'", exe);
free(exe); free(exe);
return EINA_FALSE; return EINA_FALSE;
} }
free(exe); free(exe);
/* Open companion .so file.
* Support for legacy quicklaunch apps with separate library.
*/
qr_handle = dlopen(exe2, RTLD_NOW | RTLD_GLOBAL);
if (!qr_handle)
{
fprintf(stderr, "dlerr: %s\n", dlerror());
WRN("dlopen('%s') failed: %s", exe2, dlerror());
free(exe2);
return EINA_FALSE;
}
INF("dlopen('%s') = %p", exe2, qr_handle);
qr_main = dlsym(qr_handle, "elm_main");
INF("dlsym(%p, 'elm_main') = %p", qr_handle, qr_main);
if (!qr_main)
{
WRN("not quicklauncher capable: no elm_main in '%s'", exe2);
dlclose(qr_handle);
qr_handle = NULL;
free(exe2);
return EINA_FALSE;
}
free(exe2);
return EINA_TRUE; return EINA_TRUE;
#else #else
(void)argc; (void)argc;
@ -1018,16 +1042,17 @@ elm_quicklaunch_fallback(int argc,
char **argv) char **argv)
{ {
int ret; int ret;
char cwd[PATH_MAX];
elm_quicklaunch_init(argc, argv); elm_quicklaunch_init(argc, argv);
elm_quicklaunch_sub_init(argc, argv); elm_quicklaunch_sub_init(argc, argv);
elm_quicklaunch_prepare(argc, argv); elm_quicklaunch_prepare(argc, argv, getcwd(cwd, sizeof(cwd)));
ret = qr_main(argc, argv); ret = qr_main(argc, argv);
exit(ret); exit(ret);
return ret; return ret;
} }
EAPI char * EAPI char *
elm_quicklaunch_exe_path_get(const char *exe) elm_quicklaunch_exe_path_get(const char *exe, const char *cwd)
{ {
static char *path = NULL; static char *path = NULL;
static Eina_List *pathlist = NULL; static Eina_List *pathlist = NULL;
@ -1035,8 +1060,13 @@ elm_quicklaunch_exe_path_get(const char *exe)
const Eina_List *l; const Eina_List *l;
char buf[PATH_MAX]; char buf[PATH_MAX];
if (exe[0] == '/') return strdup(exe); if (exe[0] == '/') return strdup(exe);
if ((exe[0] == '.') && (exe[1] == '/')) return strdup(exe); if (cwd)
if ((exe[0] == '.') && (exe[1] == '.') && (exe[2] == '/')) return strdup(exe); pathlist = eina_list_append(pathlist, eina_stringshare_add(cwd));
else
{
if ((exe[0] == '.') && (exe[1] == '/')) return strdup(exe);
if ((exe[0] == '.') && (exe[1] == '.') && (exe[2] == '/')) return strdup(exe);
}
if (!path) if (!path)
{ {
const char *p, *pp; const char *p, *pp;