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