• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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