2 * Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
3 * Copyright (c) 2008 The Android Open Source Project
4 * Copyright (c) 2013 Simon Busch <morphis@gravedo.de>
5 * Copyright (c) 2013 Canonical Ltd
6 * Copyright (c) 2013 Jolla Ltd. <robin.burchell@jollamobile.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
28 #include <hybris/properties/properties.h>
29 #include "properties_p.h"
31 struct hybris_prop_value
37 /* surely enough for anyone */
38 #define MAX_PROPS 1000
40 /* the sorted prop array */
41 static struct hybris_prop_value prop_array
[MAX_PROPS
];
43 /* the current highest index in prop_array */
47 static int prop_qcmp(const void *a
, const void *b
);
48 static struct hybris_prop_value
*cache_find_internal(const char *key
);
49 static void cache_add_internal(const char *key
, const char *value
);
50 static void cache_repopulate_internal(FILE *f
);
51 static void cache_empty_internal();
52 static void cache_repopulate_cmdline_internal();
54 /* the inode/mtime of the prop cache, used for invalidation */
55 static ino_t static_prop_inode
;
56 static time_t static_prop_mtime
;
60 * find a prop value from the file cache.
62 * the return value is the value of the given property key, or NULL if the
63 * property key is not found. the returned value is owned by the caller,
66 char *hybris_propcache_find(const char *key
)
69 FILE *f
= fopen("/system/build.prop", "r");
75 /* before searching, we must first determine whether our cache is valid. if
76 * it isn't, we must discard our results and re-create the cache.
78 * we use fstat here to avoid a race between stat and something else
81 if (fstat(fileno(f
), &st
) != 0) {
82 perror("cache_find can't stat build.prop");
86 /* TODO: is there any better way to detect changes? */
87 if (static_prop_inode
!= st
.st_ino
||
88 static_prop_mtime
!= st
.st_mtime
) {
89 static_prop_inode
= st
.st_ino
;
90 static_prop_mtime
= st
.st_mtime
;
92 /* cache is stale. fill it back up with fresh data first. */
93 cache_empty_internal();
94 cache_repopulate_internal(f
);
95 cache_repopulate_cmdline_internal();
98 qsort(prop_array
, max_prop
, sizeof(struct hybris_prop_value
), prop_qcmp
);
101 /* then look up the key and do a copy if we get a result */
102 struct hybris_prop_value
*prop
= cache_find_internal(key
);
104 ret
= strdup(prop
->value
);
112 * empties the prop cache, ready for repopulation
114 static void cache_empty_internal()
117 for (i
= 0; i
< max_prop
; ++i
) {
118 free(prop_array
[i
].key
);
119 free(prop_array
[i
].value
);
126 * compares two hybris_prop_value by key, so as to maintain a qsorted array of
127 * props, and search the array.
129 static int prop_qcmp(const void *a
, const void *b
)
131 struct hybris_prop_value
*aa
= (struct hybris_prop_value
*)a
;
132 struct hybris_prop_value
*bb
= (struct hybris_prop_value
*)b
;
134 return strcmp(aa
->key
, bb
->key
);
138 * find a given key in the in-memory prop cache.
140 * returns the value of the given property key, or NULL if the property is not
141 * found. Note that this does not pass ownership of the hybris_prop_value or the
144 static struct hybris_prop_value
*cache_find_internal(const char *key
)
146 struct hybris_prop_value prop_key
;
147 prop_key
.key
= (char*)key
;
149 return bsearch(&prop_key
, prop_array
, max_prop
, sizeof(struct hybris_prop_value
), prop_qcmp
);
153 * add a given property to the in-memory prop cache for later retrieval.
155 * both `key' and `value' are copied from the caller.
157 static void cache_add_internal(const char *key
, const char *value
)
159 /* Skip values that can be bigger than value max */
160 if (strlen(value
) >= PROP_VALUE_MAX
-1)
163 /* preserve current behavior of first prop key => match */
164 if (cache_find_internal(key
))
167 prop_array
[max_prop
].key
= strdup(key
);
168 prop_array
[max_prop
++].value
= strdup(value
);
170 if (max_prop
>= MAX_PROPS
) {
171 fprintf(stderr
, "libhybris: ran out of props, increase MAX_PROPS");
177 * repopulates the prop cache from a given file `f'.
179 static void cache_repopulate_internal(FILE *f
)
184 while (fgets(buf
, 1024, f
) != NULL
) {
185 if (strchr(buf
, '\r'))
186 *(strchr(buf
, '\r')) = '\0';
187 if (strchr(buf
, '\n'))
188 *(strchr(buf
, '\n')) = '\0';
190 mkey
= strtok(buf
, "=");
195 value
= strtok(NULL
, "=");
199 cache_add_internal(mkey
, value
);
204 * repopulate the prop cache from /proc/cmdline
206 static void cache_repopulate_cmdline_internal()
208 /* Find a key value from the kernel command line, which is parsed
209 * by Android at init (on an Android working system) */
214 fd
= open("/proc/cmdline", O_RDONLY
);
216 int n
= read(fd
, cmdline
, 1023);
219 /* get rid of trailing newline, it happens */
220 if (n
> 0 && cmdline
[n
-1] == '\n') n
--;
230 while (ptr
&& *ptr
) {
231 char *x
= strchr(ptr
, ' ');
232 if (x
!= 0) *x
++ = 0;
237 char *value
= strchr(name
, '=');
238 int name_len
= strlen(name
);
240 if (value
== 0) continue;
242 if (name_len
== 0) continue;
244 if (!strncmp(name
, "androidboot.", 12) && name_len
> 12) {
245 const char *boot_prop_name
= name
+ 12;
246 char prop
[PROP_NAME_MAX
];
247 snprintf(prop
, sizeof(prop
) -1, "ro.%s", boot_prop_name
);
249 cache_add_internal(prop
, value
);