/* The actual code to add aliases. */ static void add_alias2 (const char *from, const char *to, const char *wp, void *modules) { /* Test whether this alias conflicts with any available module. */ if (detect_conflict (from)) /* It does conflict, don't add the alias. */ return; struct gconv_alias *new_alias = (struct gconv_alias *) malloc (sizeof (struct gconv_alias) + (wp - from)); if (new_alias != NULL) { void **inserted; new_alias->fromname = memcpy ((char *) new_alias + sizeof (struct gconv_alias), from, wp - from); new_alias->toname = new_alias->fromname + (to - from); inserted = (void **) __tsearch (new_alias, &__gconv_alias_db, __gconv_alias_compare); if (inserted == NULL || *inserted != new_alias) /* Something went wrong, free this entry. */ free (new_alias); } }
static int add_object (struct ftw_data *data, struct STAT *st) { struct known_object *newp = malloc (sizeof (struct known_object)); if (newp == NULL) return -1; newp->dev = st->st_dev; newp->ino = st->st_ino; return __tsearch (newp, &data->known_objects, object_compare) ? 0 : -1; }
/* Add new alias. */ static inline void add_alias (char *rp, void *modules) { /* We now expect two more string. The strings are normalized (converted to UPPER case) and strored in the alias database. */ struct gconv_alias *new_alias; char *from, *to, *wp; while (__isspace_l (*rp, &_nl_C_locobj)) ++rp; from = wp = rp; while (*rp != '\0' && !__isspace_l (*rp, &_nl_C_locobj)) *wp++ = __toupper_l (*rp++, &_nl_C_locobj); if (*rp == '\0') /* There is no `to' string on the line. Ignore it. */ return; *wp++ = '\0'; to = ++rp; while (__isspace_l (*rp, &_nl_C_locobj)) ++rp; while (*rp != '\0' && !__isspace_l (*rp, &_nl_C_locobj)) *wp++ = __toupper_l (*rp++, &_nl_C_locobj); if (to == wp) /* No `to' string, ignore the line. */ return; *wp++ = '\0'; /* Test whether this alias conflicts with any available module. */ if (detect_conflict (from)) /* It does conflict, don't add the alias. */ return; new_alias = (struct gconv_alias *) malloc (sizeof (struct gconv_alias) + (wp - from)); if (new_alias != NULL) { void **inserted; new_alias->fromname = memcpy ((char *) new_alias + sizeof (struct gconv_alias), from, wp - from); new_alias->toname = new_alias->fromname + (to - from); inserted = (void **) __tsearch (new_alias, &__gconv_alias_db, __gconv_alias_compare); if (inserted == NULL || *inserted != new_alias) /* Something went wrong, free this entry. */ free (new_alias); } }
void * __nss_lookup_function (service_user *ni, const char *fct_name) { void **found, *result; /* We now modify global data. Protect it. */ __libc_lock_lock (lock); /* Search the tree of functions previously requested. Data in the tree are `known_function' structures, whose first member is a `const char *', the lookup key. The search returns a pointer to the tree node structure; the first member of the is a pointer to our structure (i.e. what will be a `known_function'); since the first member of that is the lookup key string, &FCT_NAME is close enough to a pointer to our structure to use as a lookup key that will be passed to `known_compare' (above). */ found = __tsearch (&fct_name, (void **) &ni->known, &known_compare); if (*found != &fct_name) /* The search found an existing structure in the tree. */ result = ((known_function *) *found)->fct_ptr; else { /* This name was not known before. Now we have a node in the tree (in the proper sorted position for FCT_NAME) that points to &FCT_NAME instead of any real `known_function' structure. Allocate a new structure and fill it in. */ known_function *known = malloc (sizeof *known); if (! known) { remove_from_tree: /* Oops. We can't instantiate this node properly. Remove it from the tree. */ __tdelete (&fct_name, (void **) &ni->known, &known_compare); result = NULL; } else { /* Point the tree node at this new structure. */ *found = known; known->fct_name = fct_name; if (ni->library == NULL) { /* This service has not yet been used. Fetch the service library for it, creating a new one if need be. If there is no service table from the file, this static variable holds the head of the service_library list made from the default configuration. */ static name_database default_table; ni->library = nss_new_service (service_table ?: &default_table, ni->name); if (ni->library == NULL) { /* This only happens when out of memory. */ free (known); goto remove_from_tree; } } #if !defined DO_STATIC_NSS || defined SHARED if (ni->library->lib_handle == NULL) { /* Load the shared library. */ size_t shlen = (7 + strlen (ni->library->name) + 3 + strlen (__nss_shlib_revision) + 1); int saved_errno = errno; char shlib_name[shlen]; /* Construct shared object name. */ __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name, "libnss_"), ni->library->name), ".so"), __nss_shlib_revision); ni->library->lib_handle = __libc_dlopen (shlib_name); if (ni->library->lib_handle == NULL) { /* Failed to load the library. */ ni->library->lib_handle = (void *) -1l; __set_errno (saved_errno); } } if (ni->library->lib_handle == (void *) -1l) /* Library not found => function not found. */ result = NULL; else { /* Get the desired function. */ size_t namlen = (5 + strlen (ni->library->name) + 1 + strlen (fct_name) + 1); char name[namlen]; /* Construct the function name. */ __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"), ni->library->name), "_"), fct_name); /* Look up the symbol. */ result = __libc_dlsym (ni->library->lib_handle, name); } #else /* We can't get function address dynamically in static linking. */ { # define DEFINE_ENT(h,nm) \ { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \ { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \ { #h"_set"#nm"ent", _nss_##h##_set##nm##ent }, # define DEFINE_GET(h,nm) \ { #h"_get"#nm"_r", _nss_##h##_get##nm##_r }, # define DEFINE_GETBY(h,nm,ky) \ { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r }, static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] = { # include "function.def" { NULL, NULL } }; size_t namlen = (5 + strlen (ni->library->name) + 1 + strlen (fct_name) + 1); char name[namlen]; /* Construct the function name. */ __stpcpy (__stpcpy (__stpcpy (name, ni->library->name), "_"), fct_name); result = NULL; for (tp = &tbl[0]; tp->fname; tp++) if (strcmp (tp->fname, name) == 0) { result = tp->fp; break; } } #endif /* Remember function pointer for later calls. Even if null, we record it so a second try needn't search the library again. */ known->fct_ptr = result; } } /* Remove the lock. */ __libc_lock_unlock (lock); return result; }
/* Open the gconv database if necessary. A non-negative return value means success. */ struct __gconv_loaded_object * __gconv_find_shlib (const char *name) { struct __gconv_loaded_object *found; void *keyp; /* Search the tree of shared objects previously requested. Data in the tree are `loaded_object' structures, whose first member is a `const char *', the lookup key. The search returns a pointer to the tree node structure; the first member of the is a pointer to our structure (i.e. what will be a `loaded_object'); since the first member of that is the lookup key string, &FCT_NAME is close enough to a pointer to our structure to use as a lookup key that will be passed to `known_compare' (above). */ keyp = __tfind (&name, &loaded, known_compare); if (keyp == NULL) { /* This name was not known before. */ size_t namelen = strlen (name) + 1; found = malloc (sizeof (struct __gconv_loaded_object) + namelen); if (found != NULL) { /* Point the tree node at this new structure. */ found->name = (char *) memcpy (found + 1, name, namelen); found->counter = -TRIES_BEFORE_UNLOAD - 1; found->handle = NULL; if (__builtin_expect (__tsearch (found, &loaded, known_compare) == NULL, 0)) { /* Something went wrong while inserting the entry. */ free (found); found = NULL; } } } else found = *(struct __gconv_loaded_object **) keyp; /* Try to load the shared object if the usage count is 0. This implies that if the shared object is not loadable, the handle is NULL and the usage count > 0. */ if (found != NULL) { if (found->counter < -TRIES_BEFORE_UNLOAD) { assert (found->handle == NULL); found->handle = __libc_dlopen (found->name); if (found->handle != NULL) { found->fct = __libc_dlsym (found->handle, "gconv"); if (found->fct == NULL) { /* Argh, no conversion function. There is something wrong here. */ __gconv_release_shlib (found); found = NULL; } else { found->init_fct = __libc_dlsym (found->handle, "gconv_init"); found->end_fct = __libc_dlsym (found->handle, "gconv_end"); #ifdef PTR_MANGLE PTR_MANGLE (found->fct); PTR_MANGLE (found->init_fct); PTR_MANGLE (found->end_fct); #endif /* We have succeeded in loading the shared object. */ found->counter = 1; } } else /* Error while loading the shared object. */ found = NULL; } else if (found->handle != NULL) found->counter = MAX (found->counter + 1, 1); } return found; }