Imported Upstream version 0.1.0+git20131207+e452e83
[deb_libhybris.git] / hybris / properties / properties.c
1 /*
2 * Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
3 * 2008 The Android Open Source Project
4 * 2013 Simon Busch <morphis@gravedo.de>
5 * 2013 Canonical Ltd
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 *
19 */
20
21 #include <stddef.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #define __USE_GNU
29 #include <unistd.h>
30 #include <errno.h>
31 #include <sys/socket.h>
32 #include <sys/un.h>
33 #include <sys/select.h>
34 #include <sys/types.h>
35 #include <netinet/in.h>
36 #include <poll.h>
37
38 #include <hybris/properties/properties.h>
39 #include "properties_p.h"
40
41
42 static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
43 static int send_prop_msg_no_reply = 0;
44
45 /* Get/Set a property from the Android Init property socket */
46 static int send_prop_msg(prop_msg_t *msg,
47 void (*propfn)(const char *, const char *, void *),
48 void *cookie)
49 {
50 struct pollfd pollfds[1];
51 union {
52 struct sockaddr_un addr;
53 struct sockaddr addr_g;
54 } addr;
55 socklen_t alen;
56 size_t namelen;
57 int s;
58 int r;
59 int result = -1;
60 int patched_init = 0;
61
62 /* if we tried to talk to the server in the past and didn't get a reply,
63 * it's fairly safe to say that init is not patched and this is all
64 * hopeless, so we should just quit while we're ahead
65 */
66 if (send_prop_msg_no_reply == 1)
67 return -EIO;
68
69 s = socket(AF_LOCAL, SOCK_STREAM, 0);
70 if (s < 0) {
71 return result;
72 }
73
74 memset(&addr, 0, sizeof(addr));
75 namelen = strlen(property_service_socket);
76 strncpy(addr.addr.sun_path, property_service_socket,
77 sizeof(addr.addr.sun_path));
78 addr.addr.sun_family = AF_LOCAL;
79 alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
80
81 if (TEMP_FAILURE_RETRY(connect(s, &addr.addr_g, alen) < 0)) {
82 close(s);
83 return result;
84 }
85
86 r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg_t), 0));
87
88 if (r == sizeof(prop_msg_t)) {
89 pollfds[0].fd = s;
90 pollfds[0].events = 0;
91 // We successfully wrote to the property server, so use recv
92 // in case we need to get a property. Once the other side is
93 // finished, the socket is closed.
94 while ((r = recv(s, msg, sizeof(prop_msg_t), 0)) > 0) {
95 if (r != sizeof(prop_msg_t)) {
96 close(s);
97 return result;
98 }
99
100 /* If we got a reply, this is a patched init */
101 if (!patched_init)
102 patched_init = 1;
103
104 if (propfn)
105 propfn(msg->name, msg->value, cookie);
106 }
107
108 /* We also just get a close in case of setprop */
109 if ((r >= 0) && (patched_init ||
110 (msg->cmd == PROP_MSG_SETPROP))) {
111 result = 0;
112 } else {
113 send_prop_msg_no_reply = 1;
114 }
115 }
116
117 close(s);
118 return result;
119 }
120
121 int property_list(void (*propfn)(const char *key, const char *value, void *cookie),
122 void *cookie)
123 {
124 int err;
125 prop_msg_t msg;
126
127 memset(&msg, 0, sizeof(msg));
128 msg.cmd = PROP_MSG_LISTPROP;
129
130 err = send_prop_msg(&msg, propfn, cookie);
131 if (err < 0) {
132 return err;
133 }
134
135 return 0;
136 }
137
138 static int property_get_socket(const char *key, char *value, const char *default_value)
139 {
140 int err;
141 prop_msg_t msg;
142
143 memset(&msg, 0, sizeof(msg));
144 msg.cmd = PROP_MSG_GETPROP;
145
146 if (key) {
147 strncpy(msg.name, key, sizeof(msg.name));
148 err = send_prop_msg(&msg, NULL, NULL);
149 if (err < 0)
150 return err;
151 }
152
153 /* In case it's null, just use the default */
154 if ((strlen(msg.value) == 0) && (default_value)) {
155 if (strlen(default_value) >= PROP_VALUE_MAX -1) return -1;
156 strcpy(msg.value, default_value);
157 }
158
159 strcpy(value, msg.value);
160
161 return 0;
162 }
163
164 int property_get(const char *key, char *value, const char *default_value)
165 {
166 char *ret = NULL;
167
168 if ((key) && (strlen(key) >= PROP_NAME_MAX -1)) return -1;
169 if (value == NULL) return -1;
170
171 if (property_get_socket(key, value, default_value) == 0)
172 return strlen(value);
173
174 /* In case the socket is not available, search the property file cache by hand */
175 ret = hybris_propcache_find(key);
176
177 if (ret) {
178 strcpy(value, ret);
179 free(ret);
180 return strlen(value);
181 } else if (default_value != NULL) {
182 strcpy(value, default_value);
183 return strlen(value);
184 } else {
185 value = '\0';
186 }
187
188 return 0;
189 }
190
191 int property_set(const char *key, const char *value)
192 {
193 int err;
194 prop_msg_t msg;
195
196 if (key == 0) return -1;
197 if (value == 0) value = "";
198 if (strlen(key) >= PROP_NAME_MAX -1) return -1;
199 if (strlen(value) >= PROP_VALUE_MAX -1) return -1;
200
201 memset(&msg, 0, sizeof(msg));
202 msg.cmd = PROP_MSG_SETPROP;
203 strncpy(msg.name, key, sizeof(msg.name));
204 strncpy(msg.value, value, sizeof(msg.value));
205
206 err = send_prop_msg(&msg, NULL, NULL);
207 if (err < 0) {
208 return err;
209 }
210
211 return 0;
212 }
213
214 // vim:ts=4:sw=4:noexpandtab