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