1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl testing shell
9 : */
10 :
11 : #include <assert.h>
12 : #include <string.h>
13 : #include <sstream>
14 :
15 : #include "native_client/src/include/portability.h"
16 : #include "native_client/src/include/portability_io.h"
17 :
18 : #include "native_client/src/include/nacl_base.h"
19 :
20 : #include "native_client/src/shared/platform/nacl_log.h"
21 : #include "native_client/src/shared/platform/nacl_threads.h"
22 : #include "native_client/src/shared/srpc/nacl_srpc.h"
23 :
24 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
25 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
26 : #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
27 : #include "native_client/src/trusted/desc/nacl_desc_invalid.h"
28 : #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
29 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
30 : #include "native_client/src/trusted/sel_universal/parsing.h"
31 : #include "native_client/src/trusted/sel_universal/rpc_universal.h"
32 :
33 : #define kMaxCommandLineLength 4096
34 :
35 : using std::stringstream;
36 :
37 : using nacl::DescWrapperFactory;
38 : using nacl::DescWrapper;
39 :
40 39 : static NaClSrpcImcDescType DescFromPlatformDesc(int fd, int mode) {
41 : return
42 39 : (NaClSrpcImcDescType) NaClDescIoDescMake(NaClHostDescPosixMake(fd, mode));
43 : }
44 :
45 :
46 66 : void NaClCommandLoop::AddDesc(NaClSrpcImcDescType desc, string name) {
47 132 : NaClLog(1, "adding descriptor %p -> %s\n",
48 66 : static_cast<void*>(desc), name.c_str());
49 66 : descs_[name] = desc;
50 66 : }
51 :
52 :
53 2 : NaClSrpcImcDescType NaClCommandLoop::FindDescByName(string name) const {
54 2 : if (descs_.find(name) == descs_.end()) {
55 0 : NaClLog(LOG_ERROR, "could not find desc: %s\n", name.c_str());
56 0 : return kNaClSrpcInvalidImcDesc;
57 : } else {
58 : // NOTE: descs_[name] is not const
59 2 : return descs_.find(name)->second;
60 : }
61 2 : }
62 :
63 :
64 6 : string NaClCommandLoop::AddDescUniquify(NaClSrpcImcDescType desc,
65 6 : string prefix) {
66 : // check whether we have given this descriptor a name already
67 6 : for (map<string, NaClSrpcImcDescType>::iterator it = descs_.begin();
68 16 : it != descs_.end();
69 10 : ++it) {
70 20 : if (it->second == desc) return it->first;
71 10 : }
72 :
73 1 : while (1) {
74 1 : stringstream sstr;
75 3 : sstr << prefix << "_" << desc_count_;
76 1 : ++desc_count_;
77 1 : string unique = sstr.str();
78 4 : if (descs_.find(unique) == descs_.end()) {
79 3 : AddDesc(desc, unique);
80 1 : return unique;
81 : }
82 6 : }
83 6 : }
84 :
85 :
86 429 : void NaClCommandLoop::AddHandler(string name, CommandHandler handler) {
87 429 : if (handlers_.find(name) != handlers_.end()) {
88 0 : NaClLog(LOG_ERROR, "handler %s already exists\n", name.c_str());
89 0 : }
90 429 : handlers_[name] = handler;
91 429 : }
92 :
93 :
94 0 : void NaClCommandLoop::RegisterNonDeterministicOutput(string content,
95 0 : string name) {
96 0 : NaClSrpcArg arg;
97 : // we parse and then unparse to canonicalize the string representation
98 : // of content
99 0 : if (!ParseArg(&arg, content, true, this)) {
100 0 : NaClLog(LOG_ERROR, "malformed argument to RegisterNonDeterministicOutput");
101 0 : }
102 0 : string data = DumpArg(&arg, this);
103 0 : nondeterministic_[data] = name;
104 0 : FreeArrayArg(&arg);
105 0 : }
106 :
107 :
108 65 : void NaClCommandLoop::SetVariable(string name, string value) {
109 65 : vars_[name] = value;
110 65 : }
111 :
112 :
113 2 : string NaClCommandLoop::GetVariable(string name) const {
114 2 : if (vars_.find(name) == vars_.end()) {
115 0 : NaClLog(LOG_ERROR, "unknown variable %s\n", name.c_str());
116 0 : return "";
117 : }
118 : // NOTE: vars_[name] is not const
119 2 : return vars_.find(name)->second;
120 2 : }
121 :
122 :
123 0 : void NaClCommandLoop::AddUpcallRpc(string name, NaClSrpcMethod rpc) {
124 0 : if (upcall_installed_) {
125 0 : NaClLog(LOG_ERROR, "upcall service is already install - ignoring\n");
126 0 : return;
127 : }
128 :
129 0 : if (upcall_rpcs_.find(name) != upcall_rpcs_.end()) {
130 0 : NaClLog(LOG_ERROR, "rpc %s already exists\n", name.c_str());
131 0 : }
132 0 : upcall_rpcs_[name] = rpc;
133 0 : }
134 :
135 :
136 0 : void NaClCommandLoop::AddUpcallRpcSecondary(string name, NaClSrpcMethod rpc) {
137 0 : if (upcall_installed_) {
138 0 : NaClLog(LOG_ERROR, "upcall service is already install - ignoring\n");
139 0 : return;
140 : }
141 :
142 0 : if (upcall_rpcs_secondary_.find(name) != upcall_rpcs_secondary_.end()) {
143 0 : NaClLog(LOG_ERROR, "rpc (secondary) %s already exists\n", name.c_str());
144 0 : }
145 0 : upcall_rpcs_secondary_[name] = rpc;
146 0 : }
147 :
148 :
149 90 : void NaClCommandLoop::DumpArgsAndResults(NaClSrpcArg* inv[],
150 90 : NaClSrpcArg* outv[]) {
151 344 : for (size_t j = 0; inv[j] != NULL; ++j) {
152 82 : string value = DumpArg(inv[j], this);
153 328 : if (nondeterministic_.find(value) != nondeterministic_.end()) {
154 0 : value = nondeterministic_.find(value)->second;
155 0 : }
156 164 : printf("input %d: %s\n", (int) j, value.c_str());
157 82 : }
158 :
159 306 : for (size_t j = 0; outv[j] != NULL; ++j) {
160 63 : string value = DumpArg(outv[j], this);
161 252 : if (nondeterministic_.find(value) != nondeterministic_.end()) {
162 0 : value = nondeterministic_.find(value)->second;
163 0 : }
164 126 : printf("output %d: %s\n", (int) j, value.c_str());
165 63 : }
166 90 : }
167 :
168 :
169 90 : static string BuildSignature(string name, NaClSrpcArg** in, NaClSrpcArg** out) {
170 45 : string result = name;
171 :
172 45 : result.push_back(':');
173 254 : for (int i = 0; i < NACL_SRPC_MAX_ARGS; ++i) {
174 127 : if (NULL == in[i]) {
175 45 : break;
176 : }
177 82 : result.push_back(in[i]->tag);
178 82 : }
179 :
180 45 : result.push_back(':');
181 216 : for (int i = 0; i < NACL_SRPC_MAX_ARGS; ++i) {
182 108 : if (NULL == out[i]) {
183 45 : break;
184 : }
185 63 : result.push_back(out[i]->tag);
186 63 : }
187 45 : return result;
188 90 : }
189 :
190 :
191 0 : bool NaClCommandLoop::HandleShowDescriptors(NaClCommandLoop* ncl,
192 0 : const vector<string>& args) {
193 0 : if (args.size() != 1) {
194 0 : NaClLog(LOG_ERROR, "not the right number of args for this command\n");
195 0 : return false;
196 : }
197 0 : printf("Descriptors:\n");
198 : typedef map<string, NaClSrpcImcDescType>::const_iterator Ci;
199 0 : for (Ci it = ncl->descs_.begin(); it != ncl->descs_.end(); ++it) {
200 0 : printf(" %p: %s\n", static_cast<void*>(it->second), it->first.c_str());
201 0 : }
202 0 : return true;
203 0 : }
204 :
205 :
206 0 : bool NaClCommandLoop::HandleShowVariables(NaClCommandLoop* ncl,
207 0 : const vector<string>& args) {
208 0 : if (args.size() != 1) {
209 0 : NaClLog(LOG_ERROR, "not the right number of args for this command\n");
210 0 : return false;
211 : }
212 0 : printf("Variables:\n");
213 : typedef map<string, string>::const_iterator Ci;
214 0 : for (Ci it = ncl->vars_.begin(); it != ncl->vars_.end(); ++it) {
215 0 : printf(" %s: [%s]\n", it->first.c_str(), it->second.c_str());
216 0 : }
217 0 : return true;
218 0 : }
219 :
220 :
221 0 : bool NaClCommandLoop::HandleSetVariable(NaClCommandLoop* ncl,
222 0 : const vector<string>& args) {
223 0 : if (args.size() != 3) {
224 0 : NaClLog(LOG_ERROR, "not the right number of args for this command\n");
225 0 : return false;
226 : }
227 0 : ncl->SetVariable(args[1], args[2]);
228 0 : return true;
229 0 : }
230 :
231 :
232 0 : bool NaClCommandLoop::HandleNondeterministic(NaClCommandLoop* ncl,
233 0 : const vector<string>& args) {
234 0 : if (args.size() != 3) {
235 0 : NaClLog(LOG_ERROR, "not the right number of args for this command\n");
236 0 : return false;
237 : }
238 0 : ncl->RegisterNonDeterministicOutput(args[1], args[2]);
239 0 : return true;
240 0 : }
241 :
242 :
243 0 : bool NaClCommandLoop::HandleEcho(NaClCommandLoop* ncl,
244 0 : const vector<string>& args) {
245 0 : UNREFERENCED_PARAMETER(ncl);
246 0 : const char* delim = "";
247 0 : for (size_t i = 1; i < args.size(); ++i) {
248 0 : printf("%s%s", delim, args[i].c_str());
249 0 : delim = " ";
250 0 : }
251 0 : printf("\n");
252 0 : return true;
253 : }
254 :
255 : static NaClSrpcHandlerDesc* MakeDescriptorArray(
256 0 : const map<string, NaClSrpcMethod>& method_map) {
257 0 : NaClSrpcHandlerDesc* handlers =
258 0 : new NaClSrpcHandlerDesc[method_map.size() + 1];
259 :
260 0 : NaClSrpcHandlerDesc* curr = handlers;
261 : typedef map<string, NaClSrpcMethod>::const_iterator Ci;
262 0 : for (Ci it = method_map.begin(); it != method_map.end(); ++it) {
263 0 : curr->entry_fmt = it->first.c_str();
264 0 : curr->handler = it->second;
265 0 : ++curr;
266 0 : NaClLog(1, "adding upcall handler: %s\n", it->first.c_str());
267 0 : }
268 : // terminate the handlers with a zero sentinel
269 0 : curr->entry_fmt = 0;
270 0 : curr->handler = 0;
271 0 : return handlers;
272 : }
273 :
274 :
275 0 : static void Unimplemented(NaClSrpcRpc* rpc,
276 0 : NaClSrpcArg** inputs,
277 0 : NaClSrpcArg** outputs,
278 0 : NaClSrpcClosure* done) {
279 0 : UNREFERENCED_PARAMETER(inputs);
280 0 : UNREFERENCED_PARAMETER(outputs);
281 0 : UNREFERENCED_PARAMETER(done);
282 :
283 0 : const char* rpc_name;
284 0 : const char* arg_types;
285 0 : const char* ret_types;
286 :
287 0 : if (NaClSrpcServiceMethodNameAndTypes(rpc->channel->server,
288 : rpc->rpc_number,
289 : &rpc_name,
290 : &arg_types,
291 : &ret_types)) {
292 0 : NaClLog(LOG_ERROR, "cannot find signature for rpc %d\n", rpc->rpc_number);
293 0 : }
294 :
295 : // TODO(robertm): add full argument printing
296 0 : printf("invoking: %s (%s) -> %s\n", rpc_name, arg_types, ret_types);
297 0 : }
298 :
299 :
300 : // Makes data available to SecondaryHandlerThread.
301 : static NaClSrpcHandlerDesc* SecondaryHandlers = 0;
302 :
303 0 : void WINAPI SecondaryHandlerThread(void* desc_void) {
304 0 : DescWrapper* desc = reinterpret_cast<DescWrapper*>(desc_void);
305 :
306 0 : NaClLog(1, "secondary service thread started %p\n", desc_void);
307 0 : NaClSrpcServerLoop(desc->desc(), SecondaryHandlers, NULL);
308 0 : NaClLog(1, "secondary service thread stopped\n");
309 0 : NaClThreadExit();
310 0 : }
311 :
312 0 : bool NaClCommandLoop::HandleInstallUpcalls(NaClCommandLoop* ncl,
313 0 : const vector<string>& args) {
314 0 : if (args.size() != 3) {
315 0 : NaClLog(LOG_ERROR, "not the right number of args for this command\n");
316 0 : return false;
317 : }
318 :
319 0 : NaClLog(1, "installing %d primary upcall rpcs",
320 0 : (int)ncl->upcall_rpcs_.size());
321 : // Note, we do not care about this leak
322 0 : NaClSrpcHandlerDesc* handlers = MakeDescriptorArray(ncl->upcall_rpcs_);
323 :
324 : // Note, we do not care about this leak
325 0 : NaClSrpcService* service =
326 0 : reinterpret_cast<NaClSrpcService*>(malloc(sizeof *service));
327 0 : if (service == NULL || !NaClSrpcServiceHandlerCtor(service, handlers)) {
328 0 : NaClLog(LOG_ERROR, "could not create upcall service");
329 0 : }
330 0 : ncl->channel_->server = service;
331 0 : ncl->SetVariable(args[1], service->service_string);
332 :
333 : // NOTE: Make sure there is at least one entry.
334 : // weird things happen otherwise
335 0 : ncl->AddUpcallRpcSecondary("Dummy::", &Unimplemented);
336 0 : NaClLog(1, "installing %d secondary upcall rpcs",
337 0 : (int)ncl->upcall_rpcs_secondary_.size());
338 :
339 0 : SecondaryHandlers = MakeDescriptorArray(ncl->upcall_rpcs_secondary_);
340 0 : DescWrapperFactory* factory = new DescWrapperFactory();
341 : // NOTE: these are really NaClDescXferableDataDesc. Code was mimicked after
342 : // the exisiting plugin code
343 0 : NaClLog(1, "create socket pair so that client can make pepper upcalls\n");
344 :
345 0 : DescWrapper* descs[2] = { NULL, NULL };
346 0 : if (0 != factory->MakeSocketPair(descs)) {
347 0 : NaClLog(LOG_FATAL, "cannot create socket pair\n");
348 0 : }
349 :
350 0 : NaClLog(1, "spawning secondary service thread\n");
351 :
352 0 : NaClThread thread;
353 0 : if (!NaClThreadCtor(
354 : &thread,
355 : SecondaryHandlerThread,
356 : descs[0],
357 : 128 << 10)) {
358 0 : NaClLog(LOG_FATAL, "cannot create service handler thread\n");
359 0 : }
360 :
361 0 : ncl->AddDesc(descs[1]->desc(), args[2]);
362 :
363 0 : ncl->upcall_installed_ = true;
364 0 : return true;
365 0 : }
366 :
367 :
368 0 : static bool HandleStrcpy(NaClCommandLoop* ncl, const vector<string>& args) {
369 0 : UNREFERENCED_PARAMETER(ncl);
370 0 : if (args.size() < 4) {
371 0 : NaClLog(LOG_ERROR, "Insufficient arguments to 'rpc' command.\n");
372 0 : return false;
373 : }
374 :
375 0 : const uintptr_t start = (uintptr_t) ExtractInt64(args[1]);
376 0 : const uintptr_t offset = (uintptr_t) ExtractInt64(args[2]);
377 : // skip leading and trailing double quote
378 0 : string payload = args[3].substr(1, args[3].size() - 2);
379 0 : char* dst = reinterpret_cast<char*>(start + offset);
380 0 : NaClLog(1, "copy [%s] to %p\n", args[3].c_str(), dst);
381 : // prevent sanity warning
382 0 : strncpy(dst, payload.c_str(), payload.size() + 1);
383 0 : return true;
384 0 : }
385 :
386 :
387 0 : static bool HandleMemset(NaClCommandLoop* ncl, const vector<string>& args) {
388 0 : UNREFERENCED_PARAMETER(ncl);
389 0 : if (args.size() < 5) {
390 0 : NaClLog(LOG_ERROR, "Insufficient arguments to 'rpc' command.\n");
391 0 : return false;
392 : }
393 :
394 0 : const uintptr_t start = (uintptr_t) ExtractInt64(args[1]);
395 0 : const uintptr_t offset = (uintptr_t) ExtractInt64(args[2]);
396 0 : const uintptr_t length = (uintptr_t) ExtractInt64(args[3]);
397 0 : const int pattern = (int) ExtractInt32(args[4]);
398 :
399 0 : char* dst = reinterpret_cast<char*>(start + offset);
400 0 : NaClLog(1, "setting [%p, %p] to 0x%02x\n", dst, dst + length, pattern);
401 0 : memset(dst, pattern, length);
402 0 : return true;
403 0 : }
404 :
405 :
406 0 : static bool HandleChecksum(NaClCommandLoop* ncl, const vector<string>& args) {
407 0 : UNREFERENCED_PARAMETER(ncl);
408 0 : if (args.size() < 4) {
409 0 : NaClLog(LOG_ERROR, "Insufficient arguments to 'rpc' command.\n");
410 0 : return false;
411 : }
412 :
413 0 : const uintptr_t start = (uintptr_t) ExtractInt64(args[1]);
414 0 : const uintptr_t offset = (uintptr_t) ExtractInt64(args[2]);
415 0 : const size_t length = (size_t) ExtractInt64(args[3]);
416 0 : unsigned int sum = 0;
417 0 : unsigned char* src = reinterpret_cast<unsigned char*>(start + offset);
418 0 : for (size_t i = 0; i < length; ++i) {
419 0 : sum += sum << 1;
420 0 : sum ^= src[i];
421 0 : }
422 :
423 0 : printf("CHECKSUM: 0x%08x\n", sum);
424 0 : return true;
425 0 : }
426 :
427 :
428 0 : static bool HandleHelp(NaClCommandLoop* ncl, const vector<string>& args) {
429 0 : UNREFERENCED_PARAMETER(ncl);
430 0 : UNREFERENCED_PARAMETER(args);
431 : // TODO(sehr,robertm): we should have a syntax description arg
432 : // in the handler install call.
433 0 : printf("Commands:\n");
434 0 : printf(" # <anything>\n");
435 0 : printf(" comment\n");
436 0 : printf(" show_descriptors\n");
437 0 : printf(" print the table of known descriptors (handles)\n");
438 0 : printf(" show_variables\n");
439 0 : printf(" print the table of variables and their values\n");
440 0 : printf(" set_variable <name> <value>\n");
441 0 : printf(" set variable to the given value\n");
442 0 : printf(" rpc method_name <in_args> * <out_args>\n");
443 0 : printf(" Invoke method_name.\n");
444 0 : printf(" Each in_arg is of form 'type(value)', e.g. i(42), s(\"foo\").\n");
445 0 : printf(" Each out_arg is of form 'type', e.g. i, s.\n");
446 0 : printf(" service\n");
447 0 : printf(" print the methods found by service_discovery\n");
448 0 : printf(" install_upcalls <name>\n");
449 0 : printf(" install upcalls and set variable name to the service_string\n");
450 0 : printf(" echo <args>*\n");
451 0 : printf(" print rest of line - performs variable substitution\n");
452 0 : printf(" quit\n");
453 0 : printf(" quit the program\n");
454 0 : printf(" help\n");
455 0 : printf(" print this menu\n");
456 0 : printf(" ?\n");
457 0 : printf(" print this menu\n");
458 0 : return true;
459 : }
460 :
461 45 : bool NaClCommandLoop::InvokeNexeRpc(string signature,
462 45 : NaClSrpcArg** in,
463 45 : NaClSrpcArg** out) {
464 90 : const uint32_t rpc_num = NaClSrpcServiceMethodIndex(getService(),
465 45 : signature.c_str());
466 :
467 45 : if (kNaClSrpcInvalidMethodIndex == rpc_num) {
468 0 : NaClLog(LOG_ERROR, "No RPC found of signature: [%s]\n", signature.c_str());
469 0 : return false;
470 : }
471 :
472 45 : NaClLog(1, "Calling RPC %s (%u)\n", signature.c_str(), (unsigned) rpc_num);
473 :
474 90 : const NaClSrpcError result = NaClSrpcInvokeV(
475 45 : getChannel(), rpc_num, in, out);
476 45 : NaClLog(1, "Result %d\n", result);
477 :
478 45 : if (NACL_SRPC_RESULT_OK != result) {
479 0 : NaClLog(LOG_ERROR, "RPC call failed: %s.\n", NaClSrpcErrorString(result));
480 0 : }
481 45 : return NACL_SRPC_RESULT_OK == result;
482 45 : }
483 :
484 45 : static bool HandleRpc(NaClCommandLoop* ncl, const vector<string>& args) {
485 : // we need two args at start and the "*" in out separator
486 45 : if (args.size() < 3) {
487 0 : NaClLog(LOG_ERROR, "Insufficient arguments to 'rpc' command.\n");
488 0 : return false;
489 : }
490 :
491 : // TODO(robertm): use stl find
492 45 : size_t in_out_sep;
493 254 : for (in_out_sep = 2; in_out_sep < args.size(); ++in_out_sep) {
494 127 : if (args[in_out_sep] == "*")
495 45 : break;
496 82 : }
497 :
498 45 : if (in_out_sep == args.size()) {
499 0 : NaClLog(LOG_ERROR, "Missing input/output argument separator\n");
500 0 : return false;
501 : }
502 :
503 45 : bool show_results = true;
504 45 : size_t arg_start = 2;
505 45 : if (args[2] == "hide-results") {
506 0 : show_results = false;
507 0 : arg_start = 3;
508 0 : }
509 : // Build the input parameter values.
510 45 : const size_t n_in = in_out_sep - arg_start;
511 45 : NaClSrpcArg in[NACL_SRPC_MAX_ARGS];
512 45 : NaClSrpcArg* inv[NACL_SRPC_MAX_ARGS + 1];
513 45 : NaClLog(2, "SRPC: Parsing %d input args.\n", (int)n_in);
514 45 : BuildArgVec(inv, in, n_in);
515 45 : if (!ParseArgs(inv, args, arg_start, true, ncl)) {
516 : // TODO(sehr): reclaim memory here on failure.
517 0 : NaClLog(LOG_ERROR, "Bad input args for RPC.\n");
518 0 : return false;
519 : }
520 :
521 : // Build the output (rpc return) values.
522 45 : const size_t n_out = args.size() - in_out_sep - 1;
523 45 : NaClSrpcArg out[NACL_SRPC_MAX_ARGS];
524 45 : NaClSrpcArg* outv[NACL_SRPC_MAX_ARGS + 1];
525 45 : NaClLog(2, "SRPC: Parsing %d output args.\n", (int)n_out);
526 45 : BuildArgVec(outv, out, n_out);
527 45 : if (!ParseArgs(outv, args, in_out_sep + 1, false, ncl)) {
528 : // TODO(sehr): reclaim memory here on failure.
529 0 : NaClLog(LOG_ERROR, "Bad output args for RPC.\n");
530 0 : return false;
531 : }
532 :
533 90 : const string signature = BuildSignature(args[1], inv, outv);
534 :
535 45 : NaClSrpcArg* empty[] = {NULL};
536 90 : printf("rpc call initiated %s\n", signature.c_str());
537 45 : ncl->DumpArgsAndResults(inv, empty);
538 45 : fflush(stdout);
539 45 : fflush(stderr);
540 :
541 180 : const bool rpc_result = ncl->InvokeNexeRpc(signature, inv, outv);
542 :
543 90 : printf("rpc call complete %s\n", signature.c_str());
544 45 : if (show_results) {
545 45 : ncl->DumpArgsAndResults(empty, outv);
546 45 : }
547 :
548 45 : if (!rpc_result)
549 0 : return false;
550 :
551 : // save output into variables
552 216 : for (size_t i = 0; outv[i] != 0; ++i) {
553 63 : string value = DumpArg(outv[i], ncl);
554 126 : stringstream tag;
555 126 : tag << "result" << i;
556 315 : ncl->SetVariable(tag.str(), value);
557 189 : }
558 45 : printf("\n");
559 :
560 : /* Free the storage allocated for array valued parameters and returns. */
561 45 : FreeArrayArgs(inv);
562 45 : FreeArrayArgs(outv);
563 45 : return true;
564 90 : }
565 :
566 :
567 0 : static bool HandleService(NaClCommandLoop* ncl, const vector<string>& args) {
568 0 : UNREFERENCED_PARAMETER(args);
569 : // TODO(robertm): move this library call into sel_universal
570 0 : NaClSrpcServicePrint(ncl->getService());
571 0 : return true;
572 : }
573 :
574 :
575 26 : NaClCommandLoop::NaClCommandLoop(NaClSrpcService* service,
576 26 : NaClSrpcChannel* channel,
577 78 : NaClSrpcImcDescType default_socket_address) {
578 13 : upcall_installed_ = false;
579 13 : desc_count_ = 0;
580 13 : channel_ = channel;
581 13 : service_ = service;
582 : // populate descriptors
583 65 : AddDesc((NaClDesc*) NaClDescInvalidMake(), "invalid");
584 78 : AddDesc(DescFromPlatformDesc(DUP(0), NACL_ABI_O_RDONLY), "stdin");
585 78 : AddDesc(DescFromPlatformDesc(DUP(1), NACL_ABI_O_WRONLY), "stdout");
586 78 : AddDesc(DescFromPlatformDesc(DUP(2), NACL_ABI_O_WRONLY), "stderr");
587 13 : if (kNaClSrpcInvalidImcDesc != default_socket_address) {
588 52 : AddDesc(default_socket_address, "module_socket_address");
589 13 : }
590 :
591 : // populate command handlers
592 : // TODO(robertm): for backward compatibility
593 52 : AddHandler("show_descriptors", HandleShowDescriptors);
594 52 : AddHandler("show_variables", HandleShowVariables);
595 52 : AddHandler("set_variable", HandleSetVariable);
596 52 : AddHandler("nondeterministic", HandleNondeterministic);
597 52 : AddHandler("install_upcalls", HandleInstallUpcalls);
598 52 : AddHandler("strcpy", HandleStrcpy);
599 52 : AddHandler("memset", HandleMemset);
600 52 : AddHandler("checksum", HandleChecksum);
601 52 : AddHandler("rpc", HandleRpc);
602 52 : AddHandler("echo", HandleEcho);
603 52 : AddHandler("help", HandleHelp);
604 52 : AddHandler("?", HandleHelp);
605 52 : AddHandler("service", HandleService);
606 26 : }
607 :
608 13 : NaClCommandLoop::~NaClCommandLoop() {
609 65 : NaClDescUnref(descs_["stdin"]);
610 65 : NaClDescUnref(descs_["stdout"]);
611 65 : NaClDescUnref(descs_["stderr"]);
612 91 : }
613 :
614 : // return codes:
615 : // 0 - ok
616 : // -1 - failure
617 : // 1 - stop processing
618 58 : int NaClCommandLoop::ProcessOneCommand(const string command) {
619 116 : vector<string> tokens;
620 174 : Tokenize(command, &tokens);
621 :
622 116 : if (tokens.size() == 0) {
623 6 : return 0;
624 : }
625 :
626 156 : if (tokens[0][0] == '#') {
627 0 : return 0;
628 : }
629 :
630 156 : if (tokens[0] == "quit") {
631 0 : return 1;
632 : }
633 :
634 1029 : for (size_t i = 0; i < tokens.size(); ++i) {
635 2037 : tokens[i] = SubstituteVars(tokens[i], this);
636 291 : }
637 :
638 260 : if (handlers_.find(tokens[0]) == handlers_.end()) {
639 0 : NaClLog(LOG_ERROR, "Unknown command [%s].\n", tokens[0].c_str());
640 0 : return -1;
641 : }
642 :
643 208 : if (!handlers_[tokens[0]](this, tokens)) {
644 0 : NaClLog(LOG_ERROR, "Command [%s] failed.\n", tokens[0].c_str());
645 0 : return -1;
646 : }
647 :
648 110 : return 0;
649 58 : }
650 :
651 6 : bool NaClCommandLoop::ProcessCommands(const vector<string>& commands) {
652 6 : NaClLog(1, "entering processing commands\n");
653 82 : for (size_t i = 0; i < commands.size(); ++i) {
654 35 : fflush(stdout);
655 35 : fflush(stderr);
656 :
657 70 : int result = ProcessOneCommand(commands[i]);
658 35 : if (result == 1) return true;
659 35 : if (result == -1) return false;
660 35 : }
661 :
662 6 : return true;
663 6 : }
664 :
665 :
666 7 : bool NaClCommandLoop::StartInteractiveLoop(bool abort_on_error) {
667 7 : int command_count = 0;
668 :
669 7 : NaClLog(1, "entering print eval loop\n");
670 7 : for (;;) {
671 30 : fflush(stdout);
672 30 : fflush(stderr);
673 :
674 30 : char buffer[kMaxCommandLineLength];
675 :
676 30 : fprintf(stderr, "%d> ", command_count);
677 30 : ++command_count;
678 :
679 30 : if (!fgets(buffer, sizeof(buffer), stdin))
680 7 : break;
681 :
682 92 : int result = ProcessOneCommand(buffer);
683 23 : if (result == 1) break;
684 23 : if (result == -1 && abort_on_error) return false;
685 23 : }
686 7 : NaClLog(1, "exiting print eval loop\n");
687 7 : return true;
688 7 : }
|