blob: 5b62501d7bf9da87b41d17730758b12ae5b8f0df [file] [log] [blame]
The Android Open Source Project00f06fc2009-03-03 19:32:15 -08001/* //device/system/rild/rild.c
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <dlfcn.h>
21#include <string.h>
22#include <stdint.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <errno.h>
26
27#include <telephony/ril.h>
28#define LOG_TAG "RILD"
29#include <utils/Log.h>
30#include <cutils/properties.h>
31#include <cutils/sockets.h>
32#include <linux/capability.h>
33#include <linux/prctl.h>
34
35#include <private/android_filesystem_config.h>
36
37#define LIB_PATH_PROPERTY "rild.libpath"
38#define LIB_ARGS_PROPERTY "rild.libargs"
39#define MAX_LIB_ARGS 16
40
41static void usage(const char *argv0)
42{
43 fprintf(stderr, "Usage: %s -l <ril impl library> [-- <args for impl library>]\n", argv0);
44 exit(-1);
45}
46
47extern void RIL_register (const RIL_RadioFunctions *callbacks);
48
49extern void RIL_onRequestComplete(RIL_Token t, RIL_Errno e,
50 void *response, size_t responselen);
51
52extern void RIL_onUnsolicitedResponse(int unsolResponse, const void *data,
53 size_t datalen);
54
55extern void RIL_requestTimedCallback (RIL_TimedCallback callback,
56 void *param, const struct timeval *relativeTime);
57
58
59static struct RIL_Env s_rilEnv = {
60 RIL_onRequestComplete,
61 RIL_onUnsolicitedResponse,
62 RIL_requestTimedCallback
63};
64
65extern void RIL_startEventLoop();
66
67static int make_argv(char * args, char ** argv)
68{
69 // Note: reserve argv[0]
70 int count = 1;
71 char * tok;
72 char * s = args;
73
74 while ((tok = strtok(s, " \0"))) {
75 argv[count] = tok;
76 s = NULL;
77 count++;
78 }
79 return count;
80}
81
82/*
83 * switchUser - Switches UID to radio, preserving CAP_NET_ADMIN capabilities.
84 * Our group, cache, was set by init.
85 */
86void switchUser() {
87 prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
88 setuid(AID_RADIO);
89
90 struct __user_cap_header_struct header;
91 struct __user_cap_data_struct cap;
92 header.version = _LINUX_CAPABILITY_VERSION;
93 header.pid = 0;
94 cap.effective = cap.permitted = 1 << CAP_NET_ADMIN;
95 cap.inheritable = 0;
96 capset(&header, &cap);
97}
98
99int main(int argc, char **argv)
100{
101 const char * rilLibPath = NULL;
102 char **rilArgv;
103 void *dlHandle;
104 const RIL_RadioFunctions *(*rilInit)(const struct RIL_Env *, int, char **);
105 const RIL_RadioFunctions *funcs;
106 char libPath[PROPERTY_VALUE_MAX];
107 unsigned char hasLibArgs = 0;
108
109 int i;
110
111 for (i = 1; i < argc ;) {
112 if (0 == strcmp(argv[i], "-l") && (argc - i > 1)) {
113 rilLibPath = argv[i + 1];
114 i += 2;
115 } else if (0 == strcmp(argv[i], "--")) {
116 i++;
117 hasLibArgs = 1;
118 break;
119 } else {
120 usage(argv[0]);
121 }
122 }
123
124 if (rilLibPath == NULL) {
125 if ( 0 == property_get(LIB_PATH_PROPERTY, libPath, NULL)) {
126 // No lib sepcified on the command line, and nothing set in props.
127 // Assume "no-ril" case.
128 goto done;
129 } else {
130 rilLibPath = libPath;
131 }
132 }
133
134 /* special override when in the emulator */
135#if 1
136 {
137 static char* arg_overrides[3];
138 static char arg_device[32];
139 int done = 0;
140
141#define REFERENCE_RIL_PATH "/system/lib/libreference-ril.so"
142
143 /* first, read /proc/cmdline into memory */
144 char buffer[1024], *p, *q;
145 int len;
146 int fd = open("/proc/cmdline",O_RDONLY);
147
148 if (fd < 0) {
149 LOGD("could not open /proc/cmdline:%s", strerror(errno));
150 goto OpenLib;
151 }
152
153 do {
154 len = read(fd,buffer,sizeof(buffer)); }
155 while (len == -1 && errno == EINTR);
156
157 if (len < 0) {
158 LOGD("could not read /proc/cmdline:%s", strerror(errno));
159 close(fd);
160 goto OpenLib;
161 }
162 close(fd);
163
164 if (strstr(buffer, "android.qemud=") != NULL)
165 {
166 /* the qemud daemon is launched after rild, so
167 * give it some time to create its GSM socket
168 */
169 int tries = 5;
170#define QEMUD_SOCKET_NAME "qemud_gsm"
171
172 while (1) {
173 int fd;
174
175 sleep(1);
176
177 fd = socket_local_client(
178 QEMUD_SOCKET_NAME,
179 ANDROID_SOCKET_NAMESPACE_RESERVED,
180 SOCK_STREAM );
181
182 if (fd >= 0) {
183 close(fd);
184 snprintf( arg_device, sizeof(arg_device), "%s/%s",
185 ANDROID_SOCKET_DIR, QEMUD_SOCKET_NAME );
186
187 arg_overrides[1] = "-s";
188 arg_overrides[2] = arg_device;
189 done = 1;
190 break;
191 }
192 LOGD("could not connect to %s socket: %s",
193 QEMUD_SOCKET_NAME, strerror(errno));
194 if (--tries == 0)
195 break;
196 }
197 if (!done) {
198 LOGE("could not connect to %s socket (giving up): %s",
199 QEMUD_SOCKET_NAME, strerror(errno));
200 while(1)
201 sleep(0x00ffffff);
202 }
203 }
204
205 /* otherwise, try to see if we passed a device name from the kernel */
206 if (!done) do {
207#define KERNEL_OPTION "android.ril="
208#define DEV_PREFIX "/dev/"
209
210 p = strstr( buffer, KERNEL_OPTION );
211 if (p == NULL)
212 break;
213
214 p += sizeof(KERNEL_OPTION)-1;
215 q = strpbrk( p, " \t\n\r" );
216 if (q != NULL)
217 *q = 0;
218
219 snprintf( arg_device, sizeof(arg_device), DEV_PREFIX "%s", p );
220 arg_device[sizeof(arg_device)-1] = 0;
221 arg_overrides[1] = "-d";
222 arg_overrides[2] = arg_device;
223 done = 1;
224
225 } while (0);
226
227 if (done) {
228 argv = arg_overrides;
229 argc = 3;
230 i = 1;
231 hasLibArgs = 1;
232 rilLibPath = REFERENCE_RIL_PATH;
233
234 LOGD("overriding with %s %s", arg_overrides[1], arg_overrides[2]);
235 }
236 }
237OpenLib:
238#endif
239 switchUser();
240
241 dlHandle = dlopen(rilLibPath, RTLD_NOW);
242
243 if (dlHandle == NULL) {
244 fprintf(stderr, "dlopen failed: %s\n", dlerror());
245 exit(-1);
246 }
247
248 RIL_startEventLoop();
249
250 rilInit = (const RIL_RadioFunctions *(*)(const struct RIL_Env *, int, char **))dlsym(dlHandle, "RIL_Init");
251
252 if (rilInit == NULL) {
253 fprintf(stderr, "RIL_Init not defined or exported in %s\n", rilLibPath);
254 exit(-1);
255 }
256
257 if (hasLibArgs) {
258 rilArgv = argv + i - 1;
259 argc = argc -i + 1;
260 } else {
261 static char * newArgv[MAX_LIB_ARGS];
262 static char args[PROPERTY_VALUE_MAX];
263 rilArgv = newArgv;
264 property_get(LIB_ARGS_PROPERTY, args, "");
265 argc = make_argv(args, rilArgv);
266 }
267
268 // Make sure there's a reasonable argv[0]
269 rilArgv[0] = argv[0];
270
271 funcs = rilInit(&s_rilEnv, argc, rilArgv);
272
273 RIL_register(funcs);
274
275done:
276
277 while(1) {
278 // sleep(UINT32_MAX) seems to return immediately on bionic
279 sleep(0x00ffffff);
280 }
281}
282