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