2018-02-26 01:42:24 -08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
|
2018-02-18 13:12:58 -08:00
|
|
|
#include <Eina.h>
|
|
|
|
|
2018-02-22 14:57:36 -08:00
|
|
|
#include "eina_internal.h"
|
2018-02-18 13:12:58 -08:00
|
|
|
#include "eina_private.h"
|
|
|
|
|
|
|
|
static Eina_Hash *vpath_data = NULL;
|
|
|
|
|
|
|
|
#ifdef CRI
|
|
|
|
#undef CRI
|
|
|
|
#endif
|
|
|
|
#define CRI(...) EINA_LOG_DOM_CRIT(_eina_vpath_log_dom, __VA_ARGS__)
|
|
|
|
|
|
|
|
#ifdef ERR
|
|
|
|
#undef ERR
|
|
|
|
#endif
|
|
|
|
#define ERR(...) EINA_LOG_DOM_ERR(_eina_vpath_log_dom, __VA_ARGS__)
|
|
|
|
|
|
|
|
#ifdef DBG
|
|
|
|
#undef DBG
|
|
|
|
#endif
|
|
|
|
#define DBG(...) EINA_LOG_DOM_DBG(_eina_vpath_log_dom, __VA_ARGS__)
|
|
|
|
|
|
|
|
static int _eina_vpath_log_dom = -1;
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
_eina_vpath_data_add(const char *key, const char *value)
|
|
|
|
{
|
|
|
|
eina_hash_add(vpath_data, key, eina_stringshare_add(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline Eina_Stringshare*
|
|
|
|
_eina_vpath_data_get(const char *key)
|
|
|
|
{
|
|
|
|
return eina_hash_find(vpath_data, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-22 23:26:30 -08:00
|
|
|
static char *
|
2018-02-18 13:12:58 -08:00
|
|
|
_fallback_runtime_dir(const char *home)
|
|
|
|
{
|
|
|
|
char buf[PATH_MAX];
|
2018-02-26 01:42:24 -08:00
|
|
|
#if defined(HAVE_GETUID)
|
|
|
|
uid_t uid = getuid();
|
|
|
|
#endif
|
2018-02-18 13:12:58 -08:00
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
|
|
|
|
if (setuid(geteuid()) != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"FATAL: Cannot setuid - errno=%i\n",
|
|
|
|
errno);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
// fallback - make ~/.run
|
|
|
|
snprintf(buf, sizeof(buf), "%s/.run", home);
|
|
|
|
if (!!mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR))
|
|
|
|
{
|
|
|
|
if (errno == EEXIST)
|
|
|
|
{
|
|
|
|
if (stat(buf, &st) == 0)
|
|
|
|
{
|
|
|
|
// some sanity checks - but not for security
|
|
|
|
if (!(st.st_mode & S_IFDIR))
|
|
|
|
{
|
|
|
|
// fatal - exists but is not a dir
|
|
|
|
fprintf(stderr,
|
|
|
|
"FATAL: run dir '%s' exists but not a dir\n",
|
|
|
|
buf);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
|
|
|
|
if (st.st_uid != geteuid())
|
|
|
|
{
|
|
|
|
// fatal - run dir doesn't belong to user
|
|
|
|
fprintf(stderr,
|
|
|
|
"FATAL: run dir '%s' not owned by uid %i\n",
|
|
|
|
buf, (int)geteuid());
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// fatal - we cant create our run dir in ~/
|
|
|
|
fprintf(stderr,
|
|
|
|
"FATAL: Cannot verify run dir '%s' errno=%i\n",
|
|
|
|
buf, errno);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// fatal - we cant create our run dir in ~/
|
|
|
|
fprintf(stderr,
|
|
|
|
"FATAL: Cannot create run dir '%s' - errno=%i\n",
|
|
|
|
buf, errno);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if defined(HAVE_GETUID) && defined(HAVE_GETEUID)
|
|
|
|
if (setreuid(uid, geteuid()) != 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"FATAL: Cannot setreuid - errno=%i\n",
|
|
|
|
errno);
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return strdup(buf);
|
|
|
|
}
|
|
|
|
|
2018-02-22 23:26:30 -08:00
|
|
|
static char *
|
2018-02-18 13:12:58 -08:00
|
|
|
_fallback_home_dir()
|
|
|
|
{
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
/* Windows does not have getuid(), but home can't be NULL */
|
|
|
|
#ifdef HAVE_GETEUID
|
|
|
|
uid_t uid = geteuid();
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), "/tmp/%i", (int)uid);
|
|
|
|
if (mkdir(buf, S_IRUSR | S_IWUSR | S_IXUSR) < 0)
|
|
|
|
{
|
|
|
|
if (errno != EEXIST)
|
|
|
|
{
|
|
|
|
if (stat("/tmp", &st) == 0)
|
|
|
|
snprintf(buf, sizeof(buf), "/tmp");
|
|
|
|
else
|
|
|
|
snprintf(buf, sizeof(buf), "/");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (stat(buf, &st) != 0)
|
|
|
|
{
|
|
|
|
if (stat("/tmp", &st) == 0)
|
|
|
|
snprintf(buf, sizeof(buf), "/tmp");
|
|
|
|
else
|
|
|
|
snprintf(buf, sizeof(buf), "/");
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
snprintf(buf, sizeof(buf), "/");
|
|
|
|
#endif
|
|
|
|
return strdup(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eina_vpath_interface_sys_init(void)
|
|
|
|
{
|
|
|
|
const char *home, *tmp;
|
|
|
|
|
|
|
|
// $HOME / ~/ etc.
|
|
|
|
home = eina_environment_home_get();
|
|
|
|
if (!home)
|
|
|
|
home = _fallback_home_dir();
|
|
|
|
|
|
|
|
// tmp dir - system wide
|
|
|
|
tmp = eina_environment_tmp_get();
|
|
|
|
|
|
|
|
_eina_vpath_data_add("home", home);
|
|
|
|
_eina_vpath_data_add("tmp", tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
eina_vpath_init(void)
|
|
|
|
{
|
|
|
|
vpath_data = eina_hash_string_superfast_new((Eina_Free_Cb)eina_stringshare_del);
|
|
|
|
|
|
|
|
_eina_vpath_interface_sys_init();
|
2018-08-20 09:57:57 -07:00
|
|
|
eina_xdg_env_init();
|
2018-02-18 13:12:58 -08:00
|
|
|
|
|
|
|
_eina_vpath_log_dom = eina_log_domain_register("vpath", "cyan");
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
eina_vpath_shutdown(void)
|
|
|
|
{
|
|
|
|
eina_log_domain_unregister(_eina_vpath_log_dom);
|
|
|
|
_eina_vpath_log_dom = -1;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
2018-08-20 09:56:30 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_fetch_user_homedir(char **str, const char *name, const char *error)
|
|
|
|
{
|
|
|
|
*str = NULL;
|
|
|
|
#ifdef HAVE_GETPWENT
|
|
|
|
struct passwd *pwent;
|
|
|
|
|
|
|
|
pwent = getpwnam(name);
|
|
|
|
if (!pwent)
|
|
|
|
{
|
|
|
|
ERR("User %s not found\nThe string was: %s", name, error);
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
*str = pwent->pw_dir;
|
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
#else
|
|
|
|
ERR("User fetching is disabled on this system\nThe string was: %s", error);
|
|
|
|
return EINA_FALSE;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-02-22 23:26:30 -08:00
|
|
|
EAPI char *
|
2018-02-18 13:12:58 -08:00
|
|
|
eina_vpath_resolve(const char* path)
|
|
|
|
{
|
2018-08-20 09:56:51 -07:00
|
|
|
char buf[PATH_MAX];
|
|
|
|
|
|
|
|
if (eina_vpath_resolve_snprintf(buf, sizeof(buf), path) > 0)
|
|
|
|
return strdup(buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI int
|
|
|
|
eina_vpath_resolve_snprintf(char *str, size_t size, const char *format, ...)
|
|
|
|
{
|
|
|
|
va_list args;
|
|
|
|
char *path;
|
|
|
|
int len;
|
2018-02-18 13:12:58 -08:00
|
|
|
// XXX: implement parse of path then look up in hash if not just create
|
|
|
|
// object where path and result are the same and return that with
|
|
|
|
// path set and result set to resolved path - return obj handler calls
|
|
|
|
// "do" on object to get the result inside fetched or failed callback.
|
|
|
|
// if it's a url then we need a new classs that overrides the do and
|
|
|
|
// begins a fetch and on finish calls the event cb or when wait is called
|
|
|
|
/* FIXME: not working for WIndows */
|
|
|
|
// /* <- full path
|
|
|
|
|
2018-08-20 09:56:51 -07:00
|
|
|
path = alloca(size + 1);
|
|
|
|
|
|
|
|
va_start(args, format);
|
|
|
|
len = vsnprintf(path, size, format, args);
|
|
|
|
va_end(args);
|
2018-02-18 13:12:58 -08:00
|
|
|
|
|
|
|
if (path[0] == '~')
|
|
|
|
{
|
2018-08-20 09:56:30 -07:00
|
|
|
char *home = NULL;
|
2018-02-18 13:12:58 -08:00
|
|
|
// ~/ <- home directory
|
|
|
|
if (path[1] == '/')
|
|
|
|
{
|
2018-08-20 09:56:30 -07:00
|
|
|
home = eina_hash_find(vpath_data, "home");
|
|
|
|
path ++;
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
// ~username/ <- homedir of user "username"
|
|
|
|
else
|
|
|
|
{
|
2018-08-20 09:56:51 -07:00
|
|
|
char *p, *name;
|
2018-02-18 13:12:58 -08:00
|
|
|
|
|
|
|
for (p = path + 1; *p; p++)
|
|
|
|
{
|
|
|
|
if (*p =='/') break;
|
|
|
|
}
|
|
|
|
name = alloca(p - path);
|
|
|
|
strncpy(name, path + 1, p - path - 1);
|
|
|
|
name[p - path - 1] = 0;
|
2018-08-20 09:56:30 -07:00
|
|
|
|
|
|
|
if (!_fetch_user_homedir(&home, name, path))
|
2018-08-20 09:56:51 -07:00
|
|
|
return 0;
|
2018-08-20 09:56:30 -07:00
|
|
|
path = p;
|
|
|
|
}
|
|
|
|
if (home)
|
|
|
|
{
|
2018-08-20 09:56:51 -07:00
|
|
|
return snprintf(str, size, "%s%s", home, path);
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// (:xxx:)/* ... <- meta hash table
|
|
|
|
else if ((path[0] == '(') && (path[1] == ':'))
|
|
|
|
{
|
|
|
|
const char *p, *end, *meta;
|
2018-08-20 09:56:51 -07:00
|
|
|
char *name;
|
2018-02-18 13:12:58 -08:00
|
|
|
int max_len = strlen(path);
|
|
|
|
Eina_Bool found = EINA_FALSE;
|
|
|
|
|
|
|
|
for (p = path + 2; p <= path + max_len - 2; p++)
|
|
|
|
{
|
|
|
|
if ((p[0] ==':') && (p[1] == ')'))
|
|
|
|
{
|
|
|
|
end = p;
|
|
|
|
found = EINA_TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
ERR("(: Needs to have a matching ':)'\nThe string was: %s", path);
|
2018-08-20 09:56:51 -07:00
|
|
|
return 0;
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (*p != '/')
|
|
|
|
{
|
|
|
|
ERR("A / is expected after :)\nThe string was: %s", path);
|
2018-08-20 09:56:51 -07:00
|
|
|
return 0;
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
{
|
|
|
|
name = alloca(end - path);
|
|
|
|
strncpy(name, path + 2, end - path - 2);
|
|
|
|
name[end - path - 2] = 0;
|
|
|
|
meta = _eina_vpath_data_get(name);
|
|
|
|
if (meta)
|
|
|
|
{
|
2018-08-20 09:56:51 -07:00
|
|
|
return snprintf(str, size, "%s%s", meta, end + 2);
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ERR("Meta key '%s' was not registered!\nThe string was: %s", name, path);
|
2018-08-20 09:56:51 -07:00
|
|
|
return 0;
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//just return the path, since we assume that this is a normal path
|
|
|
|
else
|
|
|
|
{
|
2018-08-20 09:56:51 -07:00
|
|
|
return snprintf(str, size, "%s", path);
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
ERR("The path has to start with either '~/' or '(:NAME:)/' or be a normal path \nThe string was: %s", path);
|
|
|
|
|
2018-08-20 09:56:51 -07:00
|
|
|
return 0;
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
eina_vpath_interface_app_set(const char *app_domain, Eina_Prefix *app_pfx)
|
|
|
|
{
|
|
|
|
char buf[PATH_MAX];
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(app_domain);
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(app_pfx);
|
|
|
|
|
|
|
|
_eina_vpath_data_add("app.dir", eina_prefix_get(app_pfx));
|
|
|
|
_eina_vpath_data_add("app.bin", eina_prefix_bin_get(app_pfx));
|
|
|
|
_eina_vpath_data_add("app.lib", eina_prefix_lib_get(app_pfx));
|
|
|
|
_eina_vpath_data_add("app.data", eina_prefix_data_get(app_pfx));
|
|
|
|
_eina_vpath_data_add("app.locale", eina_prefix_locale_get(app_pfx));
|
|
|
|
snprintf(buf, sizeof(buf), "%s/%s",
|
2018-02-22 23:26:30 -08:00
|
|
|
_eina_vpath_data_get("usr.config"), app_domain);
|
2018-02-18 13:12:58 -08:00
|
|
|
_eina_vpath_data_add("app.config", buf);
|
|
|
|
snprintf(buf, sizeof(buf), "%s/%s",
|
2018-02-22 23:26:30 -08:00
|
|
|
_eina_vpath_data_get("usr.cache"), app_domain);
|
2018-02-18 13:12:58 -08:00
|
|
|
_eina_vpath_data_add("app.cache", buf);
|
|
|
|
snprintf(buf, sizeof(buf), "%s/%s",
|
2018-02-22 23:26:30 -08:00
|
|
|
_eina_vpath_data_get("usr.data"), app_domain);
|
2018-02-18 13:12:58 -08:00
|
|
|
_eina_vpath_data_add("app.local", buf);
|
2018-02-22 23:26:30 -08:00
|
|
|
snprintf(buf, sizeof(buf), "%s/%s",
|
|
|
|
_eina_vpath_data_get("usr.tmp"), app_domain);
|
|
|
|
_eina_vpath_data_add("app.tmp", buf);
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
eina_vpath_interface_user_set(Eina_Vpath_Interface_User *user)
|
|
|
|
{
|
|
|
|
Eina_Bool free_run = EINA_FALSE;
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(user);
|
|
|
|
|
|
|
|
if (!user->run)
|
|
|
|
{
|
|
|
|
user->run = _fallback_runtime_dir(_eina_vpath_data_get("home"));
|
|
|
|
free_run = EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ADD(a) _eina_vpath_data_add("usr." #a , user->a)
|
|
|
|
ADD(desktop);
|
|
|
|
ADD(documents);
|
|
|
|
ADD(downloads);
|
|
|
|
ADD(music);
|
|
|
|
ADD(pictures);
|
|
|
|
ADD(pub);
|
|
|
|
ADD(templates);
|
|
|
|
ADD(videos);
|
|
|
|
ADD(data);
|
|
|
|
ADD(config);
|
|
|
|
ADD(cache);
|
|
|
|
ADD(run);
|
2018-02-22 23:26:30 -08:00
|
|
|
ADD(tmp);
|
2018-02-18 13:12:58 -08:00
|
|
|
#undef ADD
|
|
|
|
|
|
|
|
if (free_run)
|
2018-02-22 23:26:30 -08:00
|
|
|
free((char *)user->run);
|
2018-02-18 13:12:58 -08:00
|
|
|
}
|