blob: 490a245245d34909274994747566e9989646ccb4 [file] [log] [blame]
that7e303cf2014-03-06 07:57:43 +01001/*
2 * Copyright (C) 2007 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 <stdio.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <string.h>
21#include <ctype.h>
22#include <fcntl.h>
23#include <stdarg.h>
24#include <dirent.h>
25#include <limits.h>
26#include <errno.h>
27
Ethan Yonkerbcc502c2014-11-10 11:22:10 -060028#include "../../bionic/libc/private/bionic_futex.h"
29
that7e303cf2014-03-06 07:57:43 +010030#include <cutils/properties.h>
31
32#include "legacy_properties.h"
33
34#include <sys/mman.h>
Ethan Yonker6029e932014-11-06 09:31:48 -060035// Not available in 5.0
36//#include <sys/atomics.h>
that7e303cf2014-03-06 07:57:43 +010037#include "legacy_property_service.h"
38
that7e303cf2014-03-06 07:57:43 +010039static int persistent_properties_loaded = 0;
40static int property_area_inited = 0;
41
42static int property_set_fd = -1;
43
that7e303cf2014-03-06 07:57:43 +010044typedef struct {
45 void *data;
46 size_t size;
47 int fd;
48} workspace;
49
50static int init_workspace(workspace *w, size_t size)
51{
52 void *data;
53 int fd;
54
55 /* dev is a tmpfs that we can use to carve a shared workspace
56 * out of, so let's do that...
57 */
58 fd = open("/dev/__legacy_properties__", O_RDWR | O_CREAT, 0600);
59 if (fd < 0)
60 return -1;
61
62 if (ftruncate(fd, size) < 0)
63 goto out;
64
65 data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
66 if(data == MAP_FAILED)
67 goto out;
68
69 close(fd);
70
71 fd = open("/dev/__legacy_properties__", O_RDONLY);
72 if (fd < 0)
73 return -1;
74
75 unlink("/dev/__legacy_properties__");
76
77 w->data = data;
78 w->size = size;
79 w->fd = fd;
80 return 0;
81
82out:
83 close(fd);
84 return -1;
85}
86
87/* (8 header words + 247 toc words) = 1020 bytes */
88/* 1024 bytes header and toc + 247 prop_infos @ 128 bytes = 32640 bytes */
89
90#define PA_COUNT_MAX 247
91#define PA_INFO_START 1024
92#define PA_SIZE 32768
93
94static workspace pa_workspace;
95static prop_info *pa_info_array;
96
97prop_area *__legacy_property_area__;
98
99static int init_property_area(void)
100{
101 prop_area *pa;
102
103 if(pa_info_array)
104 return -1;
105
106 if(init_workspace(&pa_workspace, PA_SIZE))
107 return -1;
108
109 fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
110
111 pa_info_array = (void*) (((char*) pa_workspace.data) + PA_INFO_START);
112
113 pa = pa_workspace.data;
114 memset(pa, 0, PA_SIZE);
115 pa->magic = PROP_AREA_MAGIC;
116 pa->version = PROP_AREA_VERSION;
117
118 /* plug into the lib property services */
119 __legacy_property_area__ = pa;
120 property_area_inited = 1;
121 return 0;
122}
123
124static void update_prop_info(prop_info *pi, const char *value, unsigned len)
125{
126 pi->serial = pi->serial | 1;
127 memcpy(pi->value, value, len + 1);
128 pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
129 __futex_wake(&pi->serial, INT32_MAX);
130}
131
132static const prop_info *__legacy_property_find(const char *name)
133{
134 prop_area *pa = __legacy_property_area__;
135 unsigned count = pa->count;
136 unsigned *toc = pa->toc;
137 unsigned len = strlen(name);
138 prop_info *pi;
139
140 while(count--) {
141 unsigned entry = *toc++;
142 if(TOC_NAME_LEN(entry) != len) continue;
143
144 pi = TOC_TO_INFO(pa, entry);
145 if(memcmp(name, pi->name, len)) continue;
146
147 return pi;
148 }
149
150 return 0;
151}
152
153static int legacy_property_set(const char *name, const char *value)
154{
155 prop_area *pa;
156 prop_info *pi;
157
158 int namelen = strlen(name);
159 int valuelen = strlen(value);
160
161 if(namelen >= PROP_NAME_MAX) return -1;
162 if(valuelen >= PROP_VALUE_MAX) return -1;
163 if(namelen < 1) return -1;
164
165 pi = (prop_info*) __legacy_property_find(name);
166
167
168 if(pi != 0) {
169 /* ro.* properties may NEVER be modified once set */
170 if(!strncmp(name, "ro.", 3)) return -1;
171
172 pa = __legacy_property_area__;
173 update_prop_info(pi, value, valuelen);
174 pa->serial++;
175 __futex_wake(&pa->serial, INT32_MAX);
176 } else {
177 pa = __legacy_property_area__;
178 if(pa->count == PA_COUNT_MAX) return -1;
179
180 pi = pa_info_array + pa->count;
181 pi->serial = (valuelen << 24);
182 memcpy(pi->name, name, namelen + 1);
183 memcpy(pi->value, value, valuelen + 1);
184
185 pa->toc[pa->count] =
Ethan Yonkerbcc502c2014-11-10 11:22:10 -0600186 (namelen << 24) | (((unsigned long) pi) - ((unsigned long) pa));
that7e303cf2014-03-06 07:57:43 +0100187
188 pa->count++;
189 pa->serial++;
190 __futex_wake(&pa->serial, INT32_MAX);
191 }
192
193 return 0;
194}
195
196void legacy_get_property_workspace(int *fd, int *sz)
197{
198 *fd = pa_workspace.fd;
199 *sz = pa_workspace.size;
200}
201
202static void copy_property_to_legacy(const char *key, const char *value, void *cookie)
203{
204 legacy_property_set(key, value);
205}
206
Matt Mowercdd3b332014-03-27 14:38:48 -0500207int legacy_properties_init()
that7e303cf2014-03-06 07:57:43 +0100208{
Matt Mowercdd3b332014-03-27 14:38:48 -0500209 if(init_property_area() != 0)
210 return -1;
that7e303cf2014-03-06 07:57:43 +0100211
Matt Mowercdd3b332014-03-27 14:38:48 -0500212 if(property_list(copy_property_to_legacy, 0) != 0)
213 return -1;
214
215 return 0;
216}