4
* Copyright 2013 Alex <alex@linuxonly.ru>
6
* This program is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 3 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program. If not, see <http://www.gnu.org/licenses/>.
33
#define MMGUI_LIBPATHS_CACHE_FILE "/etc/ld.so.cache"
34
#define MMGUI_LIBPATHS_CACHE_SOEXT ".so"
35
#define MMGUI_LIBPATHS_CACHE_LIB_TEMP "/usr/lib/%s.so"
36
#define MMGUI_LIBPATHS_CACHE_PATH_TEMP "/usr/lib/%s.so"
38
#define MMGUI_LIBPATHS_LOCAL_CACHE_XDG ".cache"
39
#define MMGUI_LIBPATHS_LOCAL_CACHE_DIR "modem-manager-gui"
40
#define MMGUI_LIBPATHS_LOCAL_CACHE_FILE "libpaths.conf"
41
#define MMGUI_LIBPATHS_LOCAL_CACHE_PERM 0755
42
/*Cache file sections*/
43
#define MMGUI_LIBPATHS_FILE_ROOT_SECTION "cache"
44
#define MMGUI_LIBPATHS_FILE_TIMESTAMP "timestamp"
45
#define MMGUI_LIBPATHS_FILE_NAME "name"
46
#define MMGUI_LIBPATHS_FILE_PATH "path"
49
struct _mmgui_libpaths_entry {
55
typedef struct _mmgui_libpaths_entry *mmgui_libpaths_entry_t;
58
static gboolean mmgui_libpaths_cache_open_local_cache_file(mmgui_libpaths_cache_t libcache, guint64 dbtimestamp)
60
const gchar *homepath;
62
guint64 localtimestamp;
65
if (libcache == NULL) return FALSE;
67
homepath = g_get_home_dir();
69
if (homepath == NULL) return FALSE;
71
confpath = g_build_filename(homepath, MMGUI_LIBPATHS_LOCAL_CACHE_XDG, MMGUI_LIBPATHS_LOCAL_CACHE_DIR, NULL);
73
if (g_mkdir_with_parents(confpath, MMGUI_LIBPATHS_LOCAL_CACHE_PERM) != 0) {
74
g_debug("No write access to program settings directory");
81
libcache->localfilename = g_build_filename(homepath, MMGUI_LIBPATHS_LOCAL_CACHE_XDG, MMGUI_LIBPATHS_LOCAL_CACHE_DIR, MMGUI_LIBPATHS_LOCAL_CACHE_FILE, NULL);
83
libcache->localkeyfile = g_key_file_new();
87
if (!g_key_file_load_from_file(libcache->localkeyfile, libcache->localfilename, G_KEY_FILE_NONE, &error)) {
88
libcache->updatelocal = TRUE;
89
g_debug("Local cache file loading error: %s", error->message);
93
if (g_key_file_has_key(libcache->localkeyfile, MMGUI_LIBPATHS_FILE_ROOT_SECTION, MMGUI_LIBPATHS_FILE_TIMESTAMP, &error)) {
95
localtimestamp = g_key_file_get_uint64(libcache->localkeyfile, MMGUI_LIBPATHS_FILE_ROOT_SECTION, MMGUI_LIBPATHS_FILE_TIMESTAMP, &error);
97
if (localtimestamp == dbtimestamp) {
98
libcache->updatelocal = FALSE;
100
libcache->updatelocal = TRUE;
103
libcache->updatelocal = TRUE;
104
g_debug("Local cache contain unreadable timestamp: %s", error->message);
108
libcache->updatelocal = TRUE;
109
g_debug("Local cache does not contain timestamp: %s", error->message);
114
return !libcache->updatelocal;
117
static gboolean mmgui_libpaths_cache_close_local_cache_file(mmgui_libpaths_cache_t libcache, gboolean update)
123
if (libcache == NULL) return FALSE;
124
if ((libcache->localfilename == NULL) || (libcache->localkeyfile == NULL)) return FALSE;
128
g_key_file_set_int64(libcache->localkeyfile, MMGUI_LIBPATHS_FILE_ROOT_SECTION, MMGUI_LIBPATHS_FILE_TIMESTAMP, (gint64)libcache->modtime);
131
filedata = g_key_file_to_data(libcache->localkeyfile, &datasize, &error);
132
if (filedata != NULL) {
133
if (!g_file_set_contents(libcache->localfilename, filedata, datasize, &error)) {
134
g_debug("No data saved to local cache file file: %s", error->message);
141
g_free(libcache->localfilename);
142
g_key_file_free(libcache->localkeyfile);
147
static gboolean mmgui_libpaths_cache_add_to_local_cache_file(mmgui_libpaths_cache_t libcache, mmgui_libpaths_entry_t cachedlib)
149
if ((libcache == NULL) || (cachedlib == NULL)) return FALSE;
151
if ((libcache->updatelocal) && (libcache->localkeyfile != NULL)) {
152
if (cachedlib->id != NULL) {
154
if (cachedlib->libname != NULL) {
155
g_key_file_set_string(libcache->localkeyfile, cachedlib->id, MMGUI_LIBPATHS_FILE_NAME, cachedlib->libname);
158
if (cachedlib->libpath != NULL) {
159
g_key_file_set_string(libcache->localkeyfile, cachedlib->id, MMGUI_LIBPATHS_FILE_PATH, cachedlib->libpath);
167
static gboolean mmgui_libpaths_cache_get_from_local_cache_file(mmgui_libpaths_cache_t libcache, mmgui_libpaths_entry_t cachedlib)
171
if ((libcache == NULL) || (cachedlib == NULL)) return FALSE;
173
if ((!libcache->updatelocal) && (libcache->localkeyfile != NULL)) {
174
if (cachedlib->id != NULL) {
177
if (g_key_file_has_key(libcache->localkeyfile, cachedlib->id, MMGUI_LIBPATHS_FILE_NAME, &error)) {
179
cachedlib->libname = g_key_file_get_string(libcache->localkeyfile, cachedlib->id, MMGUI_LIBPATHS_FILE_NAME, &error);
181
g_debug("Local cache contain unreadable library name: %s", error->message);
185
cachedlib->libname = NULL;
186
g_debug("Local cache does not contain library name: %s", error->message);
191
if (g_key_file_has_key(libcache->localkeyfile, cachedlib->id, MMGUI_LIBPATHS_FILE_PATH, &error)) {
193
cachedlib->libpath = g_key_file_get_string(libcache->localkeyfile, cachedlib->id, MMGUI_LIBPATHS_FILE_PATH, &error);
195
g_debug("Local cache contain unreadable library path: %s", error->message);
199
cachedlib->libpath = NULL;
200
g_debug("Local cache does not contain library path: %s", error->message);
209
static void mmgui_libpaths_cache_destroy_entry(gpointer data)
211
mmgui_libpaths_entry_t cachedlib;
213
cachedlib = (mmgui_libpaths_entry_t)data;
215
if (cachedlib == NULL) return;
217
if (cachedlib->id != NULL) {
218
g_free(cachedlib->id);
220
if (cachedlib->libname != NULL) {
221
g_free(cachedlib->libname);
223
if (cachedlib->libpath != NULL) {
224
g_free(cachedlib->libpath);
229
static gboolean mmgui_libpaths_cache_get_entry(mmgui_libpaths_cache_t libcache, gchar *libpath)
231
mmgui_libpaths_entry_t cachedlib;
232
gchar *libext, *libid;
233
guint pathlen, sym, lnsym, lilen, lnlen;
236
if ((libcache == NULL) || (libpath == NULL)) return FALSE;
238
pathlen = strlen(libpath);
240
if (pathlen == 0) return FALSE;
242
libext = strstr(libpath, MMGUI_LIBPATHS_CACHE_SOEXT);
244
if (libext == NULL) return FALSE;
250
for (sym = libext-libpath; sym >= 0; sym--) {
251
if (libpath[sym] == '/') {
253
lilen = libext - libpath - sym - 1;
254
lnlen = pathlen - sym - 1;
259
if ((lilen == 0) || (lnlen == 0)) return FALSE;
261
/*library identifier*/
262
libid = g_malloc0(lilen+1);
263
strncpy(libid, libpath+lnsym, lilen);
264
/*search in hash table*/
265
cachedlib = (mmgui_libpaths_entry_t)g_hash_table_lookup(libcache->cache, libid);
268
if (cachedlib != NULL) {
269
if (cachedlib->libname == NULL) {
271
cachedlib->libname = g_malloc0(lnlen+1);
272
strncpy(cachedlib->libname, libpath+lnsym, lnlen);
273
/*library name found*/
274
mmgui_libpaths_cache_add_to_local_cache_file(libcache, cachedlib);
275
g_debug("Library name: %s (%s)\n", cachedlib->libname, libid);
277
if (cachedlib->libpath == NULL) {
278
/*full library path*/
279
cachedlib->libpath = g_strdup(libpath);
280
/*library path found*/
281
mmgui_libpaths_cache_add_to_local_cache_file(libcache, cachedlib);
282
g_debug("Library path: %s (%s)\n", cachedlib->libpath, libid);
292
static guint mmgui_libpaths_cache_parse_db(mmgui_libpaths_cache_t libcache)
294
guint ptr, start, end, entry, entries;
295
gchar *entryhash, *entryname, *entryext;
297
if (libcache == NULL) return;
299
/*Cache file must be terminated with value 0x00*/
300
if (libcache->mapping[libcache->mapsize-1] != 0x00) {
301
g_debug("Cache file seems to be non-valid\n");
306
end = libcache->mapsize-1;
310
for (ptr = libcache->mapsize-1; ptr > 0; ptr--) {
311
if (libcache->mapping[ptr] == 0x00) {
312
/*String separator - value 0x00*/
313
if ((end - ptr) == 1) {
314
/*Termination sequence - two values 0x00 0x00*/
316
if (libcache->mapping[start] == '/') {
317
mmgui_libpaths_cache_get_entry(libcache, libcache->mapping+start);
324
/*Regular cache entry*/
326
if (libcache->mapping[start] == '/') {
327
mmgui_libpaths_cache_get_entry(libcache, libcache->mapping+start);
332
/*Set end pointer to string end*/
335
} else if (isprint(libcache->mapping[ptr])) {
336
/*Move start pointer because this value is print symbol*/
344
mmgui_libpaths_cache_t mmgui_libpaths_cache_new(gchar *libname, ...)
350
mmgui_libpaths_cache_t libcache;
351
mmgui_libpaths_entry_t cachedlib;
353
if (libname == NULL) return NULL;
355
libcache = (mmgui_libpaths_cache_t)g_new0(struct _mmgui_libpaths_cache, 1);
357
if (stat(MMGUI_LIBPATHS_CACHE_FILE, &statbuf) == -1) {
358
g_debug("Failed to get library paths cache file size\n");
363
libcache->modtime = statbuf.st_mtime;
365
localcopy = mmgui_libpaths_cache_open_local_cache_file(libcache, (guint64)libcache->modtime);
368
/*Open system cache*/
369
libcache->fd = open(MMGUI_LIBPATHS_CACHE_FILE, O_RDONLY);
370
if (libcache->fd == -1) {
371
g_debug("Failed to open library paths cache file\n");
372
mmgui_libpaths_cache_close_local_cache_file(libcache, FALSE);
376
/*Memory mapping size*/
377
libcache->mapsize = (size_t)statbuf.st_size;
379
if (libcache->mapsize == 0) {
380
g_debug("Failed to map empty library paths cache file\n");
381
mmgui_libpaths_cache_close_local_cache_file(libcache, FALSE);
386
/*Map file into memory*/
387
libcache->mapping = mmap(NULL, libcache->mapsize, PROT_READ, MAP_PRIVATE, libcache->fd, 0);
389
if (libcache->mapping == MAP_FAILED) {
390
g_debug("Failed to map library paths cache file into memory\n");
391
mmgui_libpaths_cache_close_local_cache_file(libcache, FALSE);
398
/*When no entry found in cache, form safe name adding .so extension*/
399
libcache->safename = NULL;
401
/*Cache for requested libraries*/
402
libcache->cache = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify)mmgui_libpaths_cache_destroy_entry);
404
va_start(libnames, libname);
406
/*Dont forget about first library name*/
407
currentlib = libname;
410
/*Allocate structure*/
411
cachedlib = (mmgui_libpaths_entry_t)g_new0(struct _mmgui_libpaths_entry, 1);
412
cachedlib->id = g_strdup(currentlib);
413
cachedlib->libname = NULL;
414
cachedlib->libpath = NULL;
415
g_hash_table_insert(libcache->cache, cachedlib->id, cachedlib);
416
/*If available, get from local cache*/
418
mmgui_libpaths_cache_get_from_local_cache_file(libcache, cachedlib);
420
/*Next library name*/
421
currentlib = va_arg(libnames, gchar *);
422
} while (currentlib != NULL);
427
/*Parse system database*/
428
mmgui_libpaths_cache_parse_db(libcache);
430
mmgui_libpaths_cache_close_local_cache_file(libcache, TRUE);
432
/*Close used cache file*/
433
mmgui_libpaths_cache_close_local_cache_file(libcache, FALSE);
439
void mmgui_libpaths_cache_close(mmgui_libpaths_cache_t libcache)
441
if (libcache == NULL) return;
443
if (libcache->safename != NULL) {
444
g_free(libcache->safename);
447
g_hash_table_destroy(libcache->cache);
449
munmap(libcache->mapping, libcache->mapsize);
454
gchar *mmgui_libpaths_cache_get_library_name(mmgui_libpaths_cache_t libcache, gchar *libname)
456
mmgui_libpaths_entry_t cachedlib;
458
if ((libcache == NULL) || (libname == NULL)) return NULL;
460
cachedlib = (mmgui_libpaths_entry_t)g_hash_table_lookup(libcache->cache, libname);
462
if (cachedlib != NULL) {
463
if (cachedlib->libname != NULL) {
464
/*Cached library name*/
465
return cachedlib->libname;
467
/*Safe library name*/
468
if (libcache->safename != NULL) {
469
g_free(libcache->safename);
471
libcache->safename = g_strdup_printf(MMGUI_LIBPATHS_CACHE_LIB_TEMP, libname);
472
return libcache->safename;
475
/*Safe library name*/
476
if (libcache->safename != NULL) {
477
g_free(libcache->safename);
479
libcache->safename = g_strdup_printf(MMGUI_LIBPATHS_CACHE_LIB_TEMP, libname);
480
return libcache->safename;
484
gchar *mmgui_libpaths_cache_get_library_path(mmgui_libpaths_cache_t libcache, gchar *libname)
486
mmgui_libpaths_entry_t cachedlib;
488
if ((libcache == NULL) || (libname == NULL)) return NULL;
490
cachedlib = (mmgui_libpaths_entry_t)g_hash_table_lookup(libcache->cache, libname);
492
if (cachedlib != NULL) {
493
if (cachedlib->libpath != NULL) {
494
/*Cached library path*/
495
return cachedlib->libpath;
497
/*Safe library path*/
498
if (libcache->safename != NULL) {
499
g_free(libcache->safename);
501
libcache->safename = g_strdup_printf(MMGUI_LIBPATHS_CACHE_PATH_TEMP, libname);
502
return libcache->safename;
505
/*Safe library path*/
506
if (libcache->safename != NULL) {
507
g_free(libcache->safename);
509
libcache->safename = g_strdup_printf(MMGUI_LIBPATHS_CACHE_PATH_TEMP, libname);
510
return libcache->safename;