|
Packit |
0021fb |
/*
|
|
Packit |
0021fb |
* This file is part of ltrace.
|
|
Packit |
0021fb |
* Copyright (C) 2012,2013 Petr Machata, Red Hat Inc.
|
|
Packit |
0021fb |
*
|
|
Packit |
0021fb |
* This program is free software; you can redistribute it and/or
|
|
Packit |
0021fb |
* modify it under the terms of the GNU General Public License as
|
|
Packit |
0021fb |
* published by the Free Software Foundation; either version 2 of the
|
|
Packit |
0021fb |
* License, or (at your option) any later version.
|
|
Packit |
0021fb |
*
|
|
Packit |
0021fb |
* This program is distributed in the hope that it will be useful, but
|
|
Packit |
0021fb |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
0021fb |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
0021fb |
* General Public License for more details.
|
|
Packit |
0021fb |
*
|
|
Packit |
0021fb |
* You should have received a copy of the GNU General Public License
|
|
Packit |
0021fb |
* along with this program; if not, write to the Free Software
|
|
Packit |
0021fb |
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
|
Packit |
0021fb |
* 02110-1301 USA
|
|
Packit |
0021fb |
*/
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
#include <alloca.h>
|
|
Packit |
0021fb |
#include <errno.h>
|
|
Packit |
0021fb |
#include <stdlib.h>
|
|
Packit |
0021fb |
#include <string.h>
|
|
Packit |
0021fb |
#include <stdio.h>
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
#include "common.h"
|
|
Packit |
0021fb |
#include "callback.h"
|
|
Packit |
0021fb |
#include "param.h"
|
|
Packit |
0021fb |
#include "prototype.h"
|
|
Packit |
0021fb |
#include "type.h"
|
|
Packit |
0021fb |
#include "options.h"
|
|
Packit |
0021fb |
#include "read_config_file.h"
|
|
Packit |
0021fb |
#include "backend.h"
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct protolib_cache g_protocache;
|
|
Packit |
0021fb |
static struct protolib legacy_typedefs;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
prototype_init(struct prototype *proto)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
VECT_INIT(&proto->params, struct param);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
proto->return_info = NULL;
|
|
Packit |
0021fb |
proto->own_return_info = 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
param_destroy_cb(struct param *param, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
param_destroy(param);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
prototype_destroy(struct prototype *proto)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (proto == NULL)
|
|
Packit |
0021fb |
return;
|
|
Packit |
0021fb |
if (proto->own_return_info) {
|
|
Packit |
0021fb |
type_destroy(proto->return_info);
|
|
Packit |
0021fb |
free(proto->return_info);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
VECT_DESTROY(&proto->params, struct param, ¶m_destroy_cb, NULL);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
prototype_push_param(struct prototype *proto, struct param *param)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
return VECT_PUSHBACK(&proto->params, param);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
size_t
|
|
Packit |
0021fb |
prototype_num_params(struct prototype *proto)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
return vect_size(&proto->params);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
prototype_destroy_nth_param(struct prototype *proto, size_t n)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(n < prototype_num_params(proto));
|
|
Packit |
0021fb |
VECT_ERASE(&proto->params, struct param, n, n+1,
|
|
Packit |
0021fb |
¶m_destroy_cb, NULL);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct param *
|
|
Packit |
0021fb |
prototype_get_nth_param(struct prototype *proto, size_t n)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(n < prototype_num_params(proto));
|
|
Packit |
0021fb |
return VECT_ELEMENT(&proto->params, struct param, n);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct each_param_data {
|
|
Packit |
0021fb |
struct prototype *proto;
|
|
Packit |
0021fb |
enum callback_status (*cb)(struct prototype *, struct param *, void *);
|
|
Packit |
0021fb |
void *data;
|
|
Packit |
0021fb |
};
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static enum callback_status
|
|
Packit |
0021fb |
each_param_cb(struct param *param, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct each_param_data *cb_data = data;
|
|
Packit |
0021fb |
return (cb_data->cb)(cb_data->proto, param, cb_data->data);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct param *
|
|
Packit |
0021fb |
prototype_each_param(struct prototype *proto, struct param *start_after,
|
|
Packit |
0021fb |
enum callback_status (*cb)(struct prototype *,
|
|
Packit |
0021fb |
struct param *, void *),
|
|
Packit |
0021fb |
void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct each_param_data cb_data = { proto, cb, data };
|
|
Packit |
0021fb |
return VECT_EACH(&proto->params, struct param, start_after,
|
|
Packit |
0021fb |
&each_param_cb, &cb_data);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
named_type_init(struct named_type *named,
|
|
Packit |
0021fb |
struct arg_type_info *info, int own_type)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
named->info = info;
|
|
Packit |
0021fb |
named->own_type = own_type;
|
|
Packit |
0021fb |
named->forward = 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
named_type_destroy(struct named_type *named)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (named->own_type) {
|
|
Packit |
0021fb |
type_destroy(named->info);
|
|
Packit |
0021fb |
free(named->info);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
protolib_init(struct protolib *plib)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
DICT_INIT(&plib->prototypes, char *, struct prototype,
|
|
Packit |
0021fb |
dict_hash_string, dict_eq_string, NULL);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
DICT_INIT(&plib->named_types, char *, struct named_type,
|
|
Packit |
0021fb |
dict_hash_string, dict_eq_string, NULL);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
VECT_INIT(&plib->imports, struct protolib *);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
plib->refs = 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
destroy_prototype_cb(struct prototype *proto, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
prototype_destroy(proto);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
destroy_named_type_cb(struct named_type *named, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
named_type_destroy(named);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
protolib_destroy(struct protolib *plib)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib->refs == 0);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
VECT_DESTROY(&plib->imports, struct prototype *, NULL, NULL);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
DICT_DESTROY(&plib->prototypes, const char *, struct prototype,
|
|
Packit |
0021fb |
dict_dtor_string, destroy_prototype_cb, NULL);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
DICT_DESTROY(&plib->named_types, const char *, struct named_type,
|
|
Packit |
0021fb |
dict_dtor_string, destroy_named_type_cb, NULL);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static struct protolib **
|
|
Packit |
0021fb |
each_import(struct protolib *plib, struct protolib **start_after,
|
|
Packit |
0021fb |
enum callback_status (*cb)(struct protolib **, void *), void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
return VECT_EACH(&plib->imports, struct protolib *,
|
|
Packit |
0021fb |
start_after, cb, data);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static enum callback_status
|
|
Packit |
0021fb |
is_or_imports(struct protolib **plibp, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plibp != NULL);
|
|
Packit |
0021fb |
assert(*plibp != NULL);
|
|
Packit |
0021fb |
struct protolib *import = data;
|
|
Packit |
0021fb |
if (*plibp == import
|
|
Packit |
0021fb |
|| each_import(*plibp, NULL, &is_or_imports, import) != NULL)
|
|
Packit |
0021fb |
return CBS_STOP;
|
|
Packit |
0021fb |
else
|
|
Packit |
0021fb |
return CBS_CONT;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
protolib_add_import(struct protolib *plib, struct protolib *import)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
assert(import != NULL);
|
|
Packit |
0021fb |
if (is_or_imports(&import, plib) == CBS_STOP) {
|
|
Packit |
0021fb |
fprintf(stderr, "Recursive import rejected.\n");
|
|
Packit |
0021fb |
return -2;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return VECT_PUSHBACK(&plib->imports, &import) < 0 ? -1 : 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static int
|
|
Packit |
0021fb |
bailout(const char *name, int own)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
int save_errno = errno;
|
|
Packit |
0021fb |
if (own)
|
|
Packit |
0021fb |
free((char *)name);
|
|
Packit |
0021fb |
errno = save_errno;
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
protolib_add_prototype(struct protolib *plib, const char *name, int own_name,
|
|
Packit |
0021fb |
struct prototype *proto)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
if (strdup_if(&name, name, !own_name) < 0)
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
if (DICT_INSERT(&plib->prototypes, &name, proto) < 0)
|
|
Packit |
0021fb |
return bailout(name, own_name);
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
protolib_add_named_type(struct protolib *plib, const char *name, int own_name,
|
|
Packit |
0021fb |
struct named_type *named)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
if (strdup_if(&name, name, !own_name) < 0)
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
if (DICT_INSERT(&plib->named_types, &name, named) < 0)
|
|
Packit |
0021fb |
return bailout(name, own_name);
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct lookup {
|
|
Packit |
0021fb |
const char *name;
|
|
Packit |
0021fb |
struct dict *(*getter)(struct protolib *plib);
|
|
Packit |
0021fb |
bool imports;
|
|
Packit |
0021fb |
void *result;
|
|
Packit |
0021fb |
};
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static struct dict *
|
|
Packit |
0021fb |
get_prototypes(struct protolib *plib)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
return &plib->prototypes;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static struct dict *
|
|
Packit |
0021fb |
get_named_types(struct protolib *plib)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
return &plib->named_types;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static enum callback_status
|
|
Packit |
0021fb |
protolib_lookup_rec(struct protolib **plibp, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plibp != NULL);
|
|
Packit |
0021fb |
assert(*plibp != NULL);
|
|
Packit |
0021fb |
struct lookup *lookup = data;
|
|
Packit |
0021fb |
struct dict *dict = (*lookup->getter)(*plibp);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
lookup->result = dict_find(dict, &lookup->name);
|
|
Packit |
0021fb |
if (lookup->result != NULL)
|
|
Packit |
0021fb |
return CBS_STOP;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (lookup->imports && each_import(*plibp, NULL, &protolib_lookup_rec,
|
|
Packit |
0021fb |
lookup) != NULL) {
|
|
Packit |
0021fb |
assert(lookup->result != NULL);
|
|
Packit |
0021fb |
return CBS_STOP;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return CBS_CONT;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void *
|
|
Packit |
0021fb |
protolib_lookup(struct protolib *plib, const char *name,
|
|
Packit |
0021fb |
struct dict *(*getter)(struct protolib *),
|
|
Packit |
0021fb |
bool imports)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
struct lookup lookup = { name, getter, imports, NULL };
|
|
Packit |
0021fb |
if (protolib_lookup_rec(&plib, &lookup) == CBS_STOP)
|
|
Packit |
0021fb |
assert(lookup.result != NULL);
|
|
Packit |
0021fb |
else
|
|
Packit |
0021fb |
assert(lookup.result == NULL);
|
|
Packit |
0021fb |
return lookup.result;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct prototype *
|
|
Packit |
0021fb |
protolib_lookup_prototype(struct protolib *plib, const char *name, bool imports)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
return protolib_lookup(plib, name, &get_prototypes, imports);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct named_type *
|
|
Packit |
0021fb |
protolib_lookup_type(struct protolib *plib, const char *name, bool imports)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plib != NULL);
|
|
Packit |
0021fb |
return protolib_lookup(plib, name, &get_named_types, imports);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
destroy_protolib_cb(struct protolib **plibp, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
assert(plibp != NULL);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (*plibp != NULL
|
|
Packit |
0021fb |
&& --(*plibp)->refs == 0) {
|
|
Packit |
0021fb |
protolib_destroy(*plibp);
|
|
Packit |
0021fb |
free(*plibp);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
protolib_cache_destroy(struct protolib_cache *cache)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
DICT_DESTROY(&cache->protolibs, const char *, struct protolib *,
|
|
Packit |
0021fb |
dict_dtor_string, destroy_protolib_cb, NULL);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct load_config_data {
|
|
Packit |
0021fb |
struct protolib_cache *self;
|
|
Packit |
0021fb |
const char *key;
|
|
Packit |
0021fb |
struct protolib *result;
|
|
Packit |
0021fb |
};
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static struct protolib *
|
|
Packit |
0021fb |
consider_config_dir(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *path, const char *key)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
size_t len = sizeof ".conf";
|
|
Packit |
0021fb |
char slash[2] = {'/'};
|
|
Packit |
0021fb |
char *buf = alloca(strlen(path) + 1 + strlen(key) + len);
|
|
Packit |
0021fb |
strcpy(stpcpy(stpcpy(stpcpy(buf, path), slash), key), ".conf");
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return protolib_cache_file(cache, buf, 0);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static enum callback_status
|
|
Packit |
0021fb |
consider_confdir_cb(struct opt_F_t *entry, void *d)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (opt_F_get_kind(entry) != OPT_F_DIR)
|
|
Packit |
0021fb |
return CBS_CONT;
|
|
Packit |
0021fb |
struct load_config_data *data = d;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
data->result = consider_config_dir(data->self,
|
|
Packit |
0021fb |
entry->pathname, data->key);
|
|
Packit |
0021fb |
return data->result != NULL ? CBS_STOP : CBS_CONT;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static int
|
|
Packit |
0021fb |
load_dash_F_dirs(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *key, struct protolib **retp)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct load_config_data data = {cache, key};
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (VECT_EACH(&opt_F, struct opt_F_t, NULL,
|
|
Packit |
0021fb |
consider_confdir_cb, &data) == NULL)
|
|
Packit |
0021fb |
/* Not found. That's fine. */
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (data.result == NULL)
|
|
Packit |
0021fb |
/* There were errors. */
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
*retp = data.result;
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static int
|
|
Packit |
0021fb |
load_config(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *key, int private, struct protolib **retp)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
const char **dirs = NULL;
|
|
Packit |
0021fb |
if (os_get_config_dirs(private, &dirs) < 0
|
|
Packit |
0021fb |
|| dirs == NULL)
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
for (; *dirs != NULL; ++dirs) {
|
|
Packit |
0021fb |
struct protolib *plib = consider_config_dir(cache, *dirs, key);
|
|
Packit |
0021fb |
if (plib != NULL) {
|
|
Packit |
0021fb |
*retp = plib;
|
|
Packit |
0021fb |
break;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static enum callback_status
|
|
Packit |
0021fb |
import_legacy_file(char **fnp, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct protolib_cache *cache = data;
|
|
Packit |
0021fb |
struct protolib *plib = protolib_cache_file(cache, *fnp, 1);
|
|
Packit |
0021fb |
if (plib != NULL) {
|
|
Packit |
0021fb |
/* The cache now owns the file name. */
|
|
Packit |
0021fb |
*fnp = NULL;
|
|
Packit |
0021fb |
if (protolib_add_import(&cache->imports, plib) < 0)
|
|
Packit |
0021fb |
return CBS_STOP;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return CBS_CONT;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static int
|
|
Packit |
0021fb |
add_ltrace_conf(struct protolib_cache *cache)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
/* Look into private config directories for .ltrace.conf and
|
|
Packit |
0021fb |
* into system config directories for ltrace.conf. If it's
|
|
Packit |
0021fb |
* found, add it to implicit import module. */
|
|
Packit |
0021fb |
struct vect legacy_files;
|
|
Packit |
0021fb |
VECT_INIT(&legacy_files, char *);
|
|
Packit |
0021fb |
if (os_get_ltrace_conf_filenames(&legacy_files) < 0) {
|
|
Packit |
0021fb |
vect_destroy(&legacy_files, NULL, NULL);
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int ret = VECT_EACH(&legacy_files, char *, NULL,
|
|
Packit |
0021fb |
import_legacy_file, cache) == NULL ? 0 : -1;
|
|
Packit |
0021fb |
VECT_DESTROY(&legacy_files, char *, vect_dtor_string, NULL);
|
|
Packit |
0021fb |
return ret;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static enum callback_status
|
|
Packit |
0021fb |
add_imports_cb(struct opt_F_t *entry, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct protolib_cache *self = data;
|
|
Packit |
0021fb |
if (opt_F_get_kind(entry) != OPT_F_FILE)
|
|
Packit |
0021fb |
return CBS_CONT;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct protolib *new_import
|
|
Packit |
0021fb |
= protolib_cache_file(self, entry->pathname, 0);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (new_import == NULL
|
|
Packit |
0021fb |
|| protolib_add_import(&self->imports, new_import) < 0)
|
|
Packit |
0021fb |
/* N.B. If new_import is non-NULL, it has been already
|
|
Packit |
0021fb |
* cached. We don't therefore destroy it on
|
|
Packit |
0021fb |
* failures. */
|
|
Packit |
0021fb |
return CBS_STOP;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return CBS_CONT;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
protolib_cache_init(struct protolib_cache *cache, struct protolib *import)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
DICT_INIT(&cache->protolibs, char *, struct protolib *,
|
|
Packit |
0021fb |
dict_hash_string, dict_eq_string, NULL);
|
|
Packit |
0021fb |
protolib_init(&cache->imports);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
/* At this point the cache is consistent. This is important,
|
|
Packit |
0021fb |
* because next we will use it to cache files that we load
|
|
Packit |
0021fb |
* due to -F.
|
|
Packit |
0021fb |
*
|
|
Packit |
0021fb |
* But we are about to construct the implicit import module,
|
|
Packit |
0021fb |
* which means this module can't be itself imported to the
|
|
Packit |
0021fb |
* files that we load now. So remember that we are still
|
|
Packit |
0021fb |
* bootstrapping. */
|
|
Packit |
0021fb |
cache->bootstrap = 1;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (protolib_add_import(&cache->imports, &legacy_typedefs) < 0
|
|
Packit |
0021fb |
|| (import != NULL
|
|
Packit |
0021fb |
&& protolib_add_import(&cache->imports, import) < 0)
|
|
Packit |
0021fb |
|| add_ltrace_conf(cache) < 0
|
|
Packit |
0021fb |
|| VECT_EACH(&opt_F, struct opt_F_t, NULL,
|
|
Packit |
0021fb |
add_imports_cb, cache) != NULL) {
|
|
Packit |
0021fb |
protolib_cache_destroy(cache);
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
cache->bootstrap = 0;
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static enum callback_status
|
|
Packit |
0021fb |
add_import_cb(struct protolib **importp, void *data)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct protolib *plib = data;
|
|
Packit |
0021fb |
if (protolib_add_import(plib, *importp) < 0)
|
|
Packit |
0021fb |
return CBS_STOP;
|
|
Packit |
0021fb |
else
|
|
Packit |
0021fb |
return CBS_CONT;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static struct protolib *
|
|
Packit |
0021fb |
build_default_config(struct protolib_cache *cache, const char *key)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct protolib *new_plib = malloc(sizeof(*new_plib));
|
|
Packit |
0021fb |
if (new_plib == NULL) {
|
|
Packit |
0021fb |
fprintf(stderr, "Couldn't create config module %s: %s\n",
|
|
Packit |
0021fb |
key, strerror(errno));
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
protolib_init(new_plib);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
/* If bootstrapping, copy over imports from implicit import
|
|
Packit |
0021fb |
* module to new_plib. We can't reference the implicit
|
|
Packit |
0021fb |
* import module itself, because new_plib will become part of
|
|
Packit |
0021fb |
* this same implicit import module itself. */
|
|
Packit |
0021fb |
if ((cache->bootstrap && each_import(&cache->imports, NULL,
|
|
Packit |
0021fb |
add_import_cb, new_plib) != NULL)
|
|
Packit |
0021fb |
|| (!cache->bootstrap
|
|
Packit |
0021fb |
&& protolib_add_import(new_plib, &cache->imports) < 0)) {
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
fprintf(stderr,
|
|
Packit |
0021fb |
"Couldn't add imports to config module %s: %s\n",
|
|
Packit |
0021fb |
key, strerror(errno));
|
|
Packit |
0021fb |
protolib_destroy(new_plib);
|
|
Packit |
0021fb |
free(new_plib);
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return new_plib;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
attempt_to_cache(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *key, struct protolib *plib)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (protolib_cache_protolib(cache, key, 1, plib) == 0
|
|
Packit |
0021fb |
|| plib == NULL)
|
|
Packit |
0021fb |
/* Never mind failing to store a NULL. */
|
|
Packit |
0021fb |
return;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
/* Returning a protolib that hasn't been cached would leak
|
|
Packit |
0021fb |
* that protolib, but perhaps it's less bad then giving up
|
|
Packit |
0021fb |
* outright. At least print an error message. */
|
|
Packit |
0021fb |
fprintf(stderr, "Couldn't cache prototype library for %s\n", key);
|
|
Packit |
0021fb |
free((void *) key);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
protolib_cache_maybe_load(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *key, int own_key, bool allow_private,
|
|
Packit |
0021fb |
struct protolib **retp)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (DICT_FIND_VAL(&cache->protolibs, &key, retp) == 0)
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (strdup_if(&key, key, !own_key) < 0) {
|
|
Packit |
0021fb |
fprintf(stderr, "Couldn't cache %s: %s\n",
|
|
Packit |
0021fb |
key, strerror(errno));
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
*retp = NULL;
|
|
Packit |
0021fb |
if (load_dash_F_dirs(cache, key, retp) < 0
|
|
Packit |
0021fb |
|| (*retp == NULL && allow_private
|
|
Packit |
0021fb |
&& load_config(cache, key, 1, retp) < 0)
|
|
Packit |
0021fb |
|| (*retp == NULL
|
|
Packit |
0021fb |
&& load_config(cache, key, 0, retp) < 0))
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (!own_key)
|
|
Packit |
0021fb |
free((void *) key);
|
|
Packit |
0021fb |
fprintf(stderr,
|
|
Packit |
0021fb |
"Error occurred when attempting to load a prototype "
|
|
Packit |
0021fb |
"library for %s.\n", key);
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (*retp != NULL)
|
|
Packit |
0021fb |
attempt_to_cache(cache, key, *retp);
|
|
Packit |
0021fb |
else if (!own_key)
|
|
Packit |
0021fb |
free((void *) key);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return 0;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct protolib *
|
|
Packit |
0021fb |
protolib_cache_load(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *key, int own_key, bool allow_private)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct protolib *plib;
|
|
Packit |
0021fb |
if (protolib_cache_maybe_load(cache, key, own_key,
|
|
Packit |
0021fb |
allow_private, &plib) < 0)
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (plib == NULL)
|
|
Packit |
0021fb |
plib = protolib_cache_default(cache, key, own_key);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return plib;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct protolib *
|
|
Packit |
0021fb |
protolib_cache_default(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *key, int own_key)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (strdup_if(&key, key, !own_key) < 0) {
|
|
Packit |
0021fb |
fprintf(stderr, "Couldn't cache default %s: %s\n",
|
|
Packit |
0021fb |
key, strerror(errno));
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct protolib *plib = build_default_config(cache, key);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
/* Whatever came out of this (even NULL), store it in
|
|
Packit |
0021fb |
* the cache. */
|
|
Packit |
0021fb |
attempt_to_cache(cache, key, plib);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
return plib;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct protolib *
|
|
Packit |
0021fb |
protolib_cache_file(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *filename, int own_filename)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
struct protolib *plib;
|
|
Packit |
0021fb |
if (DICT_FIND_VAL(&cache->protolibs, &filename, &plib) == 0)
|
|
Packit |
0021fb |
return plib;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
FILE *stream = fopen(filename, "r");
|
|
Packit |
0021fb |
if (stream == NULL)
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (strdup_if(&filename, filename, !own_filename) < 0) {
|
|
Packit |
0021fb |
fprintf(stderr, "Couldn't cache %s: %s\n",
|
|
Packit |
0021fb |
filename, strerror(errno));
|
|
Packit |
0021fb |
fclose(stream);
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct protolib *new_plib = build_default_config(cache, filename);
|
|
Packit |
0021fb |
if (new_plib == NULL
|
|
Packit |
0021fb |
|| read_config_file(stream, filename, new_plib) < 0) {
|
|
Packit |
0021fb |
fclose(stream);
|
|
Packit |
0021fb |
if (own_filename)
|
|
Packit |
0021fb |
free((char *) filename);
|
|
Packit |
0021fb |
if (new_plib != NULL) {
|
|
Packit |
0021fb |
protolib_destroy(new_plib);
|
|
Packit |
0021fb |
free(new_plib);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
return NULL;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
attempt_to_cache(cache, filename, new_plib);
|
|
Packit |
0021fb |
fclose(stream);
|
|
Packit |
0021fb |
return new_plib;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int
|
|
Packit |
0021fb |
protolib_cache_protolib(struct protolib_cache *cache,
|
|
Packit |
0021fb |
const char *filename, int own_filename,
|
|
Packit |
0021fb |
struct protolib *plib)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
if (strdup_if(&filename, filename, !own_filename) < 0) {
|
|
Packit |
0021fb |
fprintf(stderr, "Couldn't cache %s: %s\n",
|
|
Packit |
0021fb |
filename, strerror(errno));
|
|
Packit |
0021fb |
return -1;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
int rc = DICT_INSERT(&cache->protolibs, &filename, &plib);
|
|
Packit |
0021fb |
if (rc < 0 && own_filename)
|
|
Packit |
0021fb |
free((char *) filename);
|
|
Packit |
0021fb |
if (rc == 0 && plib != NULL)
|
|
Packit |
0021fb |
plib->refs++;
|
|
Packit |
0021fb |
return rc;
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
static void
|
|
Packit |
0021fb |
destroy_global_config(void)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
protolib_cache_destroy(&g_protocache);
|
|
Packit |
0021fb |
protolib_destroy(&legacy_typedefs);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
void
|
|
Packit |
0021fb |
init_global_config(void)
|
|
Packit |
0021fb |
{
|
|
Packit |
0021fb |
protolib_init(&legacy_typedefs);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
struct arg_type_info *ptr_info = type_get_voidptr();
|
|
Packit |
0021fb |
static struct named_type voidptr_type;
|
|
Packit |
0021fb |
named_type_init(&voidptr_type, ptr_info, 0);
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
/* Build legacy typedefs first. This is used by
|
|
Packit |
0021fb |
* protolib_cache_init call below. */
|
|
Packit |
0021fb |
if (protolib_add_named_type(&legacy_typedefs, "addr", 0,
|
|
Packit |
0021fb |
&voidptr_type) < 0
|
|
Packit |
0021fb |
|| protolib_add_named_type(&legacy_typedefs, "file", 0,
|
|
Packit |
0021fb |
&voidptr_type) < 0) {
|
|
Packit |
0021fb |
fprintf(stderr,
|
|
Packit |
0021fb |
"Couldn't initialize aliases `addr' and `file'.\n");
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
exit(1);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
if (protolib_cache_init(&g_protocache, NULL) < 0) {
|
|
Packit |
0021fb |
fprintf(stderr, "Couldn't init prototype cache\n");
|
|
Packit |
0021fb |
exit(1);
|
|
Packit |
0021fb |
}
|
|
Packit |
0021fb |
|
|
Packit |
0021fb |
atexit(destroy_global_config);
|
|
Packit |
0021fb |
}
|