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
PropertyManager()28 PropertyManager::PropertyManager() {
29 mNamespaces = new PropertyNamespaceCollection();
30 pthread_mutex_init(&mLock, NULL);
31 }
32
~PropertyManager()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
lookupNamespace_UNLOCKED(const char * ns)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
lookupProperty_UNLOCKED(PropertyNamespace * ns,const char * name)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
attachProperty(const char * ns_name,Property * p)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
detachProperty(const char * ns_name,Property * p)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
doSet(Property * p,int idx,const char * value)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
doGet(Property * p,int idx,char * buffer,size_t max)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
set(const char * name,const char * value)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
get(const char * name,char * buffer,size_t max)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
createPropertyList(const char * prefix)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