/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #define LOG_TAG "PropertyManager" #include #include "PropertyManager.h" PropertyManager::PropertyManager() { mNamespaces = new PropertyNamespaceCollection(); pthread_mutex_init(&mLock, NULL); } PropertyManager::~PropertyManager() { PropertyNamespaceCollection::iterator it; for (it = mNamespaces->begin(); it != mNamespaces->end();) { delete (*it); it = mNamespaces->erase(it); } delete mNamespaces; } PropertyNamespace *PropertyManager::lookupNamespace_UNLOCKED(const char *ns) { PropertyNamespaceCollection::iterator ns_it; for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { if (!strcasecmp(ns, (*ns_it)->getName())) return (*ns_it); } errno = ENOENT; return NULL; } Property *PropertyManager::lookupProperty_UNLOCKED(PropertyNamespace *ns, const char *name) { PropertyCollection::iterator it; for (it = ns->getProperties()->begin(); it != ns->getProperties()->end(); ++it) { if (!strcasecmp(name, (*it)->getName())) return (*it); } errno = ENOENT; return NULL; } int PropertyManager::attachProperty(const char *ns_name, Property *p) { PropertyNamespace *ns; LOGD("Attaching property %s to namespace %s", p->getName(), ns_name); pthread_mutex_lock(&mLock); if (!(ns = lookupNamespace_UNLOCKED(ns_name))) { LOGD("Creating namespace %s", ns_name); ns = new PropertyNamespace(ns_name); mNamespaces->push_back(ns); } if (lookupProperty_UNLOCKED(ns, p->getName())) { errno = EADDRINUSE; pthread_mutex_unlock(&mLock); LOGE("Failed to register property %s.%s (%s)", ns_name, p->getName(), strerror(errno)); return -1; } ns->getProperties()->push_back(p); pthread_mutex_unlock(&mLock); return 0; } int PropertyManager::detachProperty(const char *ns_name, Property *p) { PropertyNamespace *ns; LOGD("Detaching property %s from namespace %s", p->getName(), ns_name); pthread_mutex_lock(&mLock); if (!(ns = lookupNamespace_UNLOCKED(ns_name))) { pthread_mutex_unlock(&mLock); LOGE("Namespace '%s' not found", ns_name); return -1; } PropertyCollection::iterator it; for (it = ns->getProperties()->begin(); it != ns->getProperties()->end(); ++it) { if (!strcasecmp(p->getName(), (*it)->getName())) { delete ((*it)); ns->getProperties()->erase(it); pthread_mutex_unlock(&mLock); return 0; } } LOGE("Property %s.%s not found", ns_name, p->getName()); pthread_mutex_unlock(&mLock); errno = ENOENT; return -1; } int PropertyManager::doSet(Property *p, int idx, const char *value) { if (p->getReadOnly()) { errno = EROFS; return -1; } if (p->getType() == Property::Type_STRING) { return p->set(idx, value); } else if (p->getType() == Property::Type_INTEGER) { int tmp; errno = 0; tmp = strtol(value, (char **) NULL, 10); if (errno) { LOGE("Failed to convert '%s' to int", value); errno = EINVAL; return -1; } return p->set(idx, tmp); } else if (p->getType() == Property::Type_IPV4) { struct in_addr tmp; if (!inet_aton(value, &tmp)) { LOGE("Failed to convert '%s' to ipv4", value); errno = EINVAL; return -1; } return p->set(idx, &tmp); } else { LOGE("Property '%s' has an unknown type (%d)", p->getName(), p->getType()); errno = EINVAL; return -1; } errno = ENOENT; return -1; } int PropertyManager::doGet(Property *p, int idx, char *buffer, size_t max) { if (p->getType() == Property::Type_STRING) { if (p->get(idx, buffer, max)) { LOGW("String property %s get failed (%s)", p->getName(), strerror(errno)); return -1; } } else if (p->getType() == Property::Type_INTEGER) { int tmp; if (p->get(idx, &tmp)) { LOGW("Integer property %s get failed (%s)", p->getName(), strerror(errno)); return -1; } snprintf(buffer, max, "%d", tmp); } else if (p->getType() == Property::Type_IPV4) { struct in_addr tmp; if (p->get(idx, &tmp)) { LOGW("IPV4 property %s get failed (%s)", p->getName(), strerror(errno)); return -1; } strncpy(buffer, inet_ntoa(tmp), max); } else { LOGE("Property '%s' has an unknown type (%d)", p->getName(), p->getType()); errno = EINVAL; return -1; } return 0; } /* * IPropertyManager methods */ int PropertyManager::set(const char *name, const char *value) { LOGD("set %s = '%s'", name, value); pthread_mutex_lock(&mLock); PropertyNamespaceCollection::iterator ns_it; for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { PropertyCollection::iterator p_it; for (p_it = (*ns_it)->getProperties()->begin(); p_it != (*ns_it)->getProperties()->end(); ++p_it) { for (int i = 0; i < (*p_it)->getNumElements(); i++) { char fqn[255]; char tmp[8]; sprintf(tmp, "_%d", i); snprintf(fqn, sizeof(fqn), "%s.%s%s", (*ns_it)->getName(), (*p_it)->getName(), ((*p_it)->getNumElements() > 1 ? tmp : "")); if (!strcasecmp(name, fqn)) { pthread_mutex_unlock(&mLock); return doSet((*p_it), i, value); } } } } LOGE("Property %s not found", name); pthread_mutex_unlock(&mLock); errno = ENOENT; return -1; } const char *PropertyManager::get(const char *name, char *buffer, size_t max) { pthread_mutex_lock(&mLock); PropertyNamespaceCollection::iterator ns_it; for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { PropertyCollection::iterator p_it; for (p_it = (*ns_it)->getProperties()->begin(); p_it != (*ns_it)->getProperties()->end(); ++p_it) { for (int i = 0; i < (*p_it)->getNumElements(); i++) { char fqn[255]; char tmp[8]; sprintf(tmp, "_%d", i); snprintf(fqn, sizeof(fqn), "%s.%s%s", (*ns_it)->getName(), (*p_it)->getName(), ((*p_it)->getNumElements() > 1 ? tmp : "")); if (!strcasecmp(name, fqn)) { pthread_mutex_unlock(&mLock); if (doGet((*p_it), i, buffer, max)) return NULL; return buffer; } } } } LOGE("Property %s not found", name); pthread_mutex_unlock(&mLock); errno = ENOENT; return NULL; } android::List *PropertyManager::createPropertyList(const char *prefix) { android::List *c = new android::List(); pthread_mutex_lock(&mLock); PropertyNamespaceCollection::iterator ns_it; for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { PropertyCollection::iterator p_it; for (p_it = (*ns_it)->getProperties()->begin(); p_it != (*ns_it)->getProperties()->end(); ++p_it) { for (int i = 0; i < (*p_it)->getNumElements(); i++) { char fqn[255]; char tmp[8]; sprintf(tmp, "_%d", i); snprintf(fqn, sizeof(fqn), "%s.%s%s", (*ns_it)->getName(), (*p_it)->getName(), ((*p_it)->getNumElements() > 1 ? tmp : "")); if (!prefix || (prefix && !strncasecmp(fqn, prefix, strlen(prefix)))) { c->push_back(strdup(fqn)); } } } } pthread_mutex_unlock(&mLock); return c; }