1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdlib.h> 18 #include <sys/socket.h> 19 #include <netinet/in.h> 20 #include <arpa/inet.h> 21 22 #define LOG_TAG "PropertyManager" 23 24 #include <cutils/log.h> 25 26 #include "PropertyManager.h" 27 28 PropertyManager::PropertyManager() { 29 mNamespaces = new PropertyNamespaceCollection(); 30 pthread_mutex_init(&mLock, NULL); 31 } 32 33 PropertyManager::~PropertyManager() { 34 PropertyNamespaceCollection::iterator it; 35 36 for (it = mNamespaces->begin(); it != mNamespaces->end();) { 37 delete (*it); 38 it = mNamespaces->erase(it); 39 } 40 delete mNamespaces; 41 } 42 43 PropertyNamespace *PropertyManager::lookupNamespace_UNLOCKED(const char *ns) { 44 PropertyNamespaceCollection::iterator ns_it; 45 46 for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { 47 if (!strcasecmp(ns, (*ns_it)->getName())) 48 return (*ns_it); 49 } 50 errno = ENOENT; 51 return NULL; 52 } 53 54 Property *PropertyManager::lookupProperty_UNLOCKED(PropertyNamespace *ns, const char *name) { 55 PropertyCollection::iterator it; 56 57 for (it = ns->getProperties()->begin(); 58 it != ns->getProperties()->end(); ++it) { 59 if (!strcasecmp(name, (*it)->getName())) 60 return (*it); 61 } 62 errno = ENOENT; 63 return NULL; 64 } 65 66 int PropertyManager::attachProperty(const char *ns_name, Property *p) { 67 PropertyNamespace *ns; 68 69 LOGD("Attaching property %s to namespace %s", p->getName(), ns_name); 70 pthread_mutex_lock(&mLock); 71 if (!(ns = lookupNamespace_UNLOCKED(ns_name))) { 72 LOGD("Creating namespace %s", ns_name); 73 ns = new PropertyNamespace(ns_name); 74 mNamespaces->push_back(ns); 75 } 76 77 if (lookupProperty_UNLOCKED(ns, p->getName())) { 78 errno = EADDRINUSE; 79 pthread_mutex_unlock(&mLock); 80 LOGE("Failed to register property %s.%s (%s)", 81 ns_name, p->getName(), strerror(errno)); 82 return -1; 83 } 84 85 ns->getProperties()->push_back(p); 86 pthread_mutex_unlock(&mLock); 87 return 0; 88 } 89 90 int PropertyManager::detachProperty(const char *ns_name, Property *p) { 91 PropertyNamespace *ns; 92 93 LOGD("Detaching property %s from namespace %s", p->getName(), ns_name); 94 pthread_mutex_lock(&mLock); 95 if (!(ns = lookupNamespace_UNLOCKED(ns_name))) { 96 pthread_mutex_unlock(&mLock); 97 LOGE("Namespace '%s' not found", ns_name); 98 return -1; 99 } 100 101 PropertyCollection::iterator it; 102 103 for (it = ns->getProperties()->begin(); 104 it != ns->getProperties()->end(); ++it) { 105 if (!strcasecmp(p->getName(), (*it)->getName())) { 106 delete ((*it)); 107 ns->getProperties()->erase(it); 108 pthread_mutex_unlock(&mLock); 109 return 0; 110 } 111 } 112 113 LOGE("Property %s.%s not found", ns_name, p->getName()); 114 pthread_mutex_unlock(&mLock); 115 errno = ENOENT; 116 return -1; 117 } 118 119 int PropertyManager::doSet(Property *p, int idx, const char *value) { 120 121 if (p->getReadOnly()) { 122 errno = EROFS; 123 return -1; 124 } 125 126 if (p->getType() == Property::Type_STRING) { 127 return p->set(idx, value); 128 } else if (p->getType() == Property::Type_INTEGER) { 129 int tmp; 130 errno = 0; 131 tmp = strtol(value, (char **) NULL, 10); 132 if (errno) { 133 LOGE("Failed to convert '%s' to int", value); 134 errno = EINVAL; 135 return -1; 136 } 137 return p->set(idx, tmp); 138 } else if (p->getType() == Property::Type_IPV4) { 139 struct in_addr tmp; 140 if (!inet_aton(value, &tmp)) { 141 LOGE("Failed to convert '%s' to ipv4", value); 142 errno = EINVAL; 143 return -1; 144 } 145 return p->set(idx, &tmp); 146 } else { 147 LOGE("Property '%s' has an unknown type (%d)", p->getName(), 148 p->getType()); 149 errno = EINVAL; 150 return -1; 151 } 152 errno = ENOENT; 153 return -1; 154 } 155 156 int PropertyManager::doGet(Property *p, int idx, char *buffer, size_t max) { 157 158 if (p->getType() == Property::Type_STRING) { 159 if (p->get(idx, buffer, max)) { 160 LOGW("String property %s get failed (%s)", p->getName(), 161 strerror(errno)); 162 return -1; 163 } 164 } 165 else if (p->getType() == Property::Type_INTEGER) { 166 int tmp; 167 if (p->get(idx, &tmp)) { 168 LOGW("Integer property %s get failed (%s)", p->getName(), 169 strerror(errno)); 170 return -1; 171 } 172 snprintf(buffer, max, "%d", tmp); 173 } else if (p->getType() == Property::Type_IPV4) { 174 struct in_addr tmp; 175 if (p->get(idx, &tmp)) { 176 LOGW("IPV4 property %s get failed (%s)", p->getName(), 177 strerror(errno)); 178 return -1; 179 } 180 strncpy(buffer, inet_ntoa(tmp), max); 181 } else { 182 LOGE("Property '%s' has an unknown type (%d)", p->getName(), 183 p->getType()); 184 errno = EINVAL; 185 return -1; 186 } 187 return 0; 188 } 189 190 /* 191 * IPropertyManager methods 192 */ 193 194 int PropertyManager::set(const char *name, const char *value) { 195 196 LOGD("set %s = '%s'", name, value); 197 pthread_mutex_lock(&mLock); 198 PropertyNamespaceCollection::iterator ns_it; 199 for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { 200 PropertyCollection::iterator p_it; 201 for (p_it = (*ns_it)->getProperties()->begin(); 202 p_it != (*ns_it)->getProperties()->end(); ++p_it) { 203 for (int i = 0; i < (*p_it)->getNumElements(); i++) { 204 char fqn[255]; 205 char tmp[8]; 206 sprintf(tmp, "_%d", i); 207 snprintf(fqn, sizeof(fqn), "%s.%s%s", 208 (*ns_it)->getName(), (*p_it)->getName(), 209 ((*p_it)->getNumElements() > 1 ? tmp : "")); 210 if (!strcasecmp(name, fqn)) { 211 pthread_mutex_unlock(&mLock); 212 return doSet((*p_it), i, value); 213 } 214 } 215 } 216 } 217 218 LOGE("Property %s not found", name); 219 pthread_mutex_unlock(&mLock); 220 errno = ENOENT; 221 return -1; 222 } 223 224 const char *PropertyManager::get(const char *name, char *buffer, size_t max) { 225 pthread_mutex_lock(&mLock); 226 PropertyNamespaceCollection::iterator ns_it; 227 for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { 228 PropertyCollection::iterator p_it; 229 for (p_it = (*ns_it)->getProperties()->begin(); 230 p_it != (*ns_it)->getProperties()->end(); ++p_it) { 231 232 for (int i = 0; i < (*p_it)->getNumElements(); i++) { 233 char fqn[255]; 234 char tmp[8]; 235 sprintf(tmp, "_%d", i); 236 snprintf(fqn, sizeof(fqn), "%s.%s%s", 237 (*ns_it)->getName(), (*p_it)->getName(), 238 ((*p_it)->getNumElements() > 1 ? tmp : "")); 239 if (!strcasecmp(name, fqn)) { 240 pthread_mutex_unlock(&mLock); 241 if (doGet((*p_it), i, buffer, max)) 242 return NULL; 243 return buffer; 244 } 245 } 246 } 247 } 248 249 LOGE("Property %s not found", name); 250 pthread_mutex_unlock(&mLock); 251 errno = ENOENT; 252 return NULL; 253 } 254 255 android::List<char *> *PropertyManager::createPropertyList(const char *prefix) { 256 android::List<char *> *c = new android::List<char *>(); 257 258 pthread_mutex_lock(&mLock); 259 PropertyNamespaceCollection::iterator ns_it; 260 for (ns_it = mNamespaces->begin(); ns_it != mNamespaces->end(); ++ns_it) { 261 PropertyCollection::iterator p_it; 262 for (p_it = (*ns_it)->getProperties()->begin(); 263 p_it != (*ns_it)->getProperties()->end(); ++p_it) { 264 for (int i = 0; i < (*p_it)->getNumElements(); i++) { 265 char fqn[255]; 266 char tmp[8]; 267 sprintf(tmp, "_%d", i); 268 snprintf(fqn, sizeof(fqn), "%s.%s%s", 269 (*ns_it)->getName(), (*p_it)->getName(), 270 ((*p_it)->getNumElements() > 1 ? tmp : "")); 271 if (!prefix || 272 (prefix && !strncasecmp(fqn, prefix, strlen(prefix)))) { 273 c->push_back(strdup(fqn)); 274 } 275 } 276 } 277 } 278 pthread_mutex_unlock(&mLock); 279 return c; 280 } 281