1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <stddef.h> 32 #include <errno.h> 33 #include <poll.h> 34 #include <fcntl.h> 35 #include <stdbool.h> 36 37 #include <sys/mman.h> 38 39 #include <sys/socket.h> 40 #include <sys/un.h> 41 #include <sys/select.h> 42 #include <sys/stat.h> 43 #include <sys/types.h> 44 #include <netinet/in.h> 45 #include <unistd.h> 46 47 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_ 48 #include <sys/_system_properties.h> 49 50 #include <sys/atomics.h> 51 52 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME; 53 54 static unsigned dummy_props = 0; 55 56 prop_area *__system_property_area__ = (void*) &dummy_props; 57 58 static int get_fd_from_env(void) 59 { 60 char *env = getenv("ANDROID_PROPERTY_WORKSPACE"); 61 62 if (!env) { 63 return -1; 64 } 65 66 return atoi(env); 67 } 68 69 int __system_properties_init(void) 70 { 71 bool fromFile = true; 72 int result = -1; 73 74 if(__system_property_area__ != ((void*) &dummy_props)) { 75 return 0; 76 } 77 78 int fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW); 79 80 if ((fd < 0) && (errno == ENOENT)) { 81 /* 82 * For backwards compatibility, if the file doesn't 83 * exist, we use the environment to get the file descriptor. 84 * For security reasons, we only use this backup if the kernel 85 * returns ENOENT. We don't want to use the backup if the kernel 86 * returns other errors such as ENOMEM or ENFILE, since it 87 * might be possible for an external program to trigger this 88 * condition. 89 */ 90 fd = get_fd_from_env(); 91 fromFile = false; 92 } 93 94 if (fd < 0) { 95 return -1; 96 } 97 98 struct stat fd_stat; 99 if (fstat(fd, &fd_stat) < 0) { 100 goto cleanup; 101 } 102 103 if ((fd_stat.st_uid != 0) 104 || (fd_stat.st_gid != 0) 105 || ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0)) { 106 goto cleanup; 107 } 108 109 prop_area *pa = mmap(NULL, fd_stat.st_size, PROT_READ, MAP_SHARED, fd, 0); 110 111 if (pa == MAP_FAILED) { 112 goto cleanup; 113 } 114 115 if((pa->magic != PROP_AREA_MAGIC) || (pa->version != PROP_AREA_VERSION)) { 116 munmap(pa, fd_stat.st_size); 117 goto cleanup; 118 } 119 120 __system_property_area__ = pa; 121 result = 0; 122 123 cleanup: 124 if (fromFile) { 125 close(fd); 126 } 127 128 return result; 129 } 130 131 const prop_info *__system_property_find_nth(unsigned n) 132 { 133 prop_area *pa = __system_property_area__; 134 135 if(n >= pa->count) { 136 return 0; 137 } else { 138 return TOC_TO_INFO(pa, pa->toc[n]); 139 } 140 } 141 142 const prop_info *__system_property_find(const char *name) 143 { 144 prop_area *pa = __system_property_area__; 145 unsigned count = pa->count; 146 unsigned *toc = pa->toc; 147 unsigned len = strlen(name); 148 prop_info *pi; 149 150 while(count--) { 151 unsigned entry = *toc++; 152 if(TOC_NAME_LEN(entry) != len) continue; 153 154 pi = TOC_TO_INFO(pa, entry); 155 if(memcmp(name, pi->name, len)) continue; 156 157 return pi; 158 } 159 160 return 0; 161 } 162 163 int __system_property_read(const prop_info *pi, char *name, char *value) 164 { 165 unsigned serial, len; 166 167 for(;;) { 168 serial = pi->serial; 169 while(SERIAL_DIRTY(serial)) { 170 __futex_wait((volatile void *)&pi->serial, serial, 0); 171 serial = pi->serial; 172 } 173 len = SERIAL_VALUE_LEN(serial); 174 memcpy(value, pi->value, len + 1); 175 if(serial == pi->serial) { 176 if(name != 0) { 177 strcpy(name, pi->name); 178 } 179 return len; 180 } 181 } 182 } 183 184 int __system_property_get(const char *name, char *value) 185 { 186 const prop_info *pi = __system_property_find(name); 187 188 if(pi != 0) { 189 return __system_property_read(pi, 0, value); 190 } else { 191 value[0] = 0; 192 return 0; 193 } 194 } 195 196 197 static int send_prop_msg(prop_msg *msg) 198 { 199 struct pollfd pollfds[1]; 200 struct sockaddr_un addr; 201 socklen_t alen; 202 size_t namelen; 203 int s; 204 int r; 205 int result = -1; 206 207 s = socket(AF_LOCAL, SOCK_STREAM, 0); 208 if(s < 0) { 209 return result; 210 } 211 212 memset(&addr, 0, sizeof(addr)); 213 namelen = strlen(property_service_socket); 214 strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path); 215 addr.sun_family = AF_LOCAL; 216 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1; 217 218 if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) { 219 close(s); 220 return result; 221 } 222 223 r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0)); 224 225 if(r == sizeof(prop_msg)) { 226 // We successfully wrote to the property server but now we 227 // wait for the property server to finish its work. It 228 // acknowledges its completion by closing the socket so we 229 // poll here (on nothing), waiting for the socket to close. 230 // If you 'adb shell setprop foo bar' you'll see the POLLHUP 231 // once the socket closes. Out of paranoia we cap our poll 232 // at 250 ms. 233 pollfds[0].fd = s; 234 pollfds[0].events = 0; 235 r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */)); 236 if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) { 237 result = 0; 238 } else { 239 // Ignore the timeout and treat it like a success anyway. 240 // The init process is single-threaded and its property 241 // service is sometimes slow to respond (perhaps it's off 242 // starting a child process or something) and thus this 243 // times out and the caller thinks it failed, even though 244 // it's still getting around to it. So we fake it here, 245 // mostly for ctl.* properties, but we do try and wait 250 246 // ms so callers who do read-after-write can reliably see 247 // what they've written. Most of the time. 248 // TODO: fix the system properties design. 249 result = 0; 250 } 251 } 252 253 close(s); 254 return result; 255 } 256 257 int __system_property_set(const char *key, const char *value) 258 { 259 int err; 260 prop_msg msg; 261 262 if(key == 0) return -1; 263 if(value == 0) value = ""; 264 if(strlen(key) >= PROP_NAME_MAX) return -1; 265 if(strlen(value) >= PROP_VALUE_MAX) return -1; 266 267 memset(&msg, 0, sizeof msg); 268 msg.cmd = PROP_MSG_SETPROP; 269 strlcpy(msg.name, key, sizeof msg.name); 270 strlcpy(msg.value, value, sizeof msg.value); 271 272 err = send_prop_msg(&msg); 273 if(err < 0) { 274 return err; 275 } 276 277 return 0; 278 } 279 280 int __system_property_wait(const prop_info *pi) 281 { 282 unsigned n; 283 if(pi == 0) { 284 prop_area *pa = __system_property_area__; 285 n = pa->serial; 286 do { 287 __futex_wait(&pa->serial, n, 0); 288 } while(n == pa->serial); 289 } else { 290 n = pi->serial; 291 do { 292 __futex_wait((volatile void *)&pi->serial, n, 0); 293 } while(n == pi->serial); 294 } 295 return 0; 296 } 297