1 /*
2 * Copyright (C) 2008 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 #include <errno.h>
17 #include <string.h>
18 #include <stdlib.h>
19
20 #define LOG_TAG "FrameworkListener"
21
22 #include <cutils/log.h>
23
24 #include <sysutils/FrameworkListener.h>
25 #include <sysutils/FrameworkCommand.h>
26 #include <sysutils/SocketClient.h>
27
FrameworkListener(const char * socketName)28 FrameworkListener::FrameworkListener(const char *socketName) :
29 SocketListener(socketName, true) {
30 mCommands = new FrameworkCommandCollection();
31 }
32
onDataAvailable(SocketClient * c)33 bool FrameworkListener::onDataAvailable(SocketClient *c) {
34 char buffer[255];
35 int len;
36
37 len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
38 if (len < 0) {
39 SLOGE("read() failed (%s)", strerror(errno));
40 return false;
41 } else if (!len)
42 return false;
43
44 int offset = 0;
45 int i;
46
47 for (i = 0; i < len; i++) {
48 if (buffer[i] == '\0') {
49 /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
50 dispatchCommand(c, buffer + offset);
51 offset = i + 1;
52 }
53 }
54 return true;
55 }
56
registerCmd(FrameworkCommand * cmd)57 void FrameworkListener::registerCmd(FrameworkCommand *cmd) {
58 mCommands->push_back(cmd);
59 }
60
dispatchCommand(SocketClient * cli,char * data)61 void FrameworkListener::dispatchCommand(SocketClient *cli, char *data) {
62 FrameworkCommandCollection::iterator i;
63 int argc = 0;
64 char *argv[FrameworkListener::CMD_ARGS_MAX];
65 char tmp[255];
66 char *p = data;
67 char *q = tmp;
68 char *qlimit = tmp + sizeof(tmp) - 1;
69 bool esc = false;
70 bool quote = false;
71 int k;
72
73 memset(argv, 0, sizeof(argv));
74 memset(tmp, 0, sizeof(tmp));
75 while(*p) {
76 if (*p == '\\') {
77 if (esc) {
78 if (q >= qlimit)
79 goto overflow;
80 *q++ = '\\';
81 esc = false;
82 } else
83 esc = true;
84 p++;
85 continue;
86 } else if (esc) {
87 if (*p == '"') {
88 if (q >= qlimit)
89 goto overflow;
90 *q++ = '"';
91 } else if (*p == '\\') {
92 if (q >= qlimit)
93 goto overflow;
94 *q++ = '\\';
95 } else {
96 cli->sendMsg(500, "Unsupported escape sequence", false);
97 goto out;
98 }
99 p++;
100 esc = false;
101 continue;
102 }
103
104 if (*p == '"') {
105 if (quote)
106 quote = false;
107 else
108 quote = true;
109 p++;
110 continue;
111 }
112
113 if (q >= qlimit)
114 goto overflow;
115 *q = *p++;
116 if (!quote && *q == ' ') {
117 *q = '\0';
118 if (argc >= CMD_ARGS_MAX)
119 goto overflow;
120 argv[argc++] = strdup(tmp);
121 memset(tmp, 0, sizeof(tmp));
122 q = tmp;
123 continue;
124 }
125 q++;
126 }
127
128 *q = '\0';
129 if (argc >= CMD_ARGS_MAX)
130 goto overflow;
131 argv[argc++] = strdup(tmp);
132 #if 0
133 for (k = 0; k < argc; k++) {
134 SLOGD("arg[%d] = '%s'", k, argv[k]);
135 }
136 #endif
137
138 if (quote) {
139 cli->sendMsg(500, "Unclosed quotes error", false);
140 goto out;
141 }
142
143 for (i = mCommands->begin(); i != mCommands->end(); ++i) {
144 FrameworkCommand *c = *i;
145
146 if (!strcmp(argv[0], c->getCommand())) {
147 if (c->runCommand(cli, argc, argv)) {
148 SLOGW("Handler '%s' error (%s)", c->getCommand(), strerror(errno));
149 }
150 goto out;
151 }
152 }
153
154 cli->sendMsg(500, "Command not recognized", false);
155 out:
156 int j;
157 for (j = 0; j < argc; j++)
158 free(argv[j]);
159 return;
160
161 overflow:
162 cli->sendMsg(500, "Command too long", false);
163 goto out;
164 }
165