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 : // Second generation sel_universal implemented in C++ and with optional
8 : // multimedia support via SDL
9 :
10 : #include <stdio.h>
11 :
12 : #include <fstream>
13 : #include <map>
14 : #include <sstream>
15 : #include <string>
16 : #include <vector>
17 : #include "native_client/src/include/nacl_string.h"
18 : #include "native_client/src/include/nacl_macros.h"
19 : #include "native_client/src/include/nacl_scoped_ptr.h"
20 : #include "native_client/src/include/portability.h"
21 : #include "native_client/src/include/portability_io.h"
22 : #include "native_client/src/shared/platform/nacl_log.h"
23 : #include "native_client/src/shared/platform/scoped_ptr_refcount.h"
24 : #include "native_client/src/shared/srpc/nacl_srpc.h"
25 : #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
26 : #include "native_client/src/trusted/desc/nrd_all_modules.h"
27 : #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
28 : #include "native_client/src/trusted/reverse_service/reverse_service.h"
29 : #include "native_client/src/trusted/sel_universal/pepper_emu_handler.h"
30 : #include "native_client/src/trusted/sel_universal/pnacl_emu_handler.h"
31 : #include "native_client/src/trusted/sel_universal/reverse_emulate.h"
32 : #include "native_client/src/trusted/sel_universal/replay_handler.h"
33 : #include "native_client/src/trusted/sel_universal/rpc_universal.h"
34 :
35 : #if defined(NACL_SEL_UNIVERSAL_INCLUDE_SDL)
36 : // NOTE: we need to include this so that it can "hijack" main
37 : #include <SDL/SDL.h>
38 : #endif
39 :
40 : #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
41 :
42 : using std::ifstream;
43 : using std::map;
44 : using std::string;
45 : using std::vector;
46 : using nacl::DescWrapper;
47 :
48 : // TODO(robertm): add explanation for flags
49 : static const char* kUsage =
50 : "Usage:\n"
51 : "\n"
52 : "sel_universal <sel_universal_arg> <sel_ldr_arg>* [-- <nexe> <nexe_arg>*]\n"
53 : "\n"
54 : "Exactly one nexe argument is required.\n"
55 : "After startup the user is prompted for interactive commands.\n"
56 : "For sample commands have a look at: tests/srpc/srpc_basic_test.stdin\n"
57 : "\n"
58 : "sel_universal arguments are:\n"
59 : "\n"
60 : " --help\n"
61 : " --event_record <file>\n"
62 : " --event_replay <file>\n"
63 : " --debug\n"
64 : " --abort_on_error\n"
65 : " --silence_nexe\n"
66 : " --command_prefix <prefix>\n"
67 : " --command_file <file>\n"
68 : " --var <tag> <value>\n"
69 : " --url_alias <url> <filename>\n"
70 : " --uses_reverse_service\n"
71 : "\n"
72 : "The following sel_ldr arguments might be useful:\n"
73 : " -v increase verbosity\n"
74 : " -E NACL_SRPC_DEBUG=1 even more verbosity for srpc debugging\n";
75 :
76 :
77 : // NOTE: this used to be stack allocated inside main which cause
78 : // problems on ARM (probably a tool chain bug).
79 : // NaClSrpcChannel is pretty big (> 256kB)
80 : static NaClSrpcChannel command_channel;
81 : static NaClSrpcChannel channel;
82 :
83 : // variables set via command line
84 22 : static map<string, string> initial_vars;
85 22 : static vector<string> initial_commands;
86 : static bool abort_on_error = false;
87 : static bool silence_nexe = false;
88 33 : static string command_prefix = "";
89 : static bool uses_reverse_service = false;
90 :
91 : // When given argc and argv this function (a) extracts the nexe argument,
92 : // (b) populates sel_ldr_argv with sel_ldr arguments, and (c) populates
93 : // app_argv with nexe module args. Also see kUsage above for details.
94 : // It will call exit with codes 0 (help message) and 1 (incorrect args).
95 : static nacl::string ProcessArguments(int argc,
96 : char* argv[],
97 : vector<nacl::string>* const sel_ldr_argv,
98 11 : vector<nacl::string>* const app_argv) {
99 11 : if (argc == 1) {
100 0 : printf("%s", kUsage);
101 0 : exit(0);
102 : }
103 :
104 11 : int debug_level = 0;
105 : // Extract sel_universal arguments and transfer the rest to sel_ldr_argv
106 11 : nacl::string app_name;
107 34 : for (int i = 1; i < argc; i++) {
108 23 : const string flag(argv[i]);
109 46 : if (flag == "--help") {
110 0 : printf("%s", kUsage);
111 0 : exit(0);
112 23 : } else if (flag == "--event_record") {
113 0 : if (argc <= i + 1) {
114 0 : NaClLog(LOG_FATAL, "not enough args for --event_record option\n");
115 : }
116 0 : RecordPPAPIEvents(argv[i + 1]);
117 23 : } else if (flag == "--event_replay") {
118 0 : if (argc <= i + 1) {
119 0 : NaClLog(LOG_FATAL, "not enough args for --event_replay option\n");
120 : }
121 0 : ReplayPPAPIEvents(argv[i + 1]);
122 23 : } else if (flag == "--debug") {
123 0 : ++debug_level;
124 23 : } else if (flag == "--abort_on_error") {
125 0 : abort_on_error = true;
126 23 : } else if (flag == "--silence_nexe") {
127 0 : silence_nexe = true;
128 23 : } else if (flag == "--command_prefix") {
129 0 : if (argc <= i + 1) {
130 : NaClLog(LOG_FATAL,
131 0 : "not enough args for --command_prefix option\n");
132 : }
133 0 : ++i;
134 0 : command_prefix = argv[i];
135 23 : } else if (flag == "--command_file") {
136 4 : if (argc <= i + 1) {
137 0 : NaClLog(LOG_FATAL, "not enough args for --command_file option\n");
138 : }
139 4 : NaClLog(LOG_INFO, "reading commands from %s\n", argv[i + 1]);
140 4 : ifstream f;
141 4 : f.open(argv[i + 1]);
142 4 : ++i;
143 37 : while (!f.eof()) {
144 33 : string s;
145 33 : getline(f, s);
146 33 : initial_commands.push_back(s);
147 : }
148 4 : f.close();
149 : NaClLog(LOG_INFO, "total commands now: %d\n",
150 4 : static_cast<int>(initial_commands.size()));
151 19 : } else if (flag == "--url_alias") {
152 0 : if (argc <= i + 2) {
153 0 : NaClLog(LOG_FATAL, "not enough args for --url_alias option\n");
154 : }
155 0 : RegisterFileAliasForUrl(argv[i + 1], argv[i + 2]);
156 0 : i += 2;
157 19 : } else if (flag == "--var") {
158 2 : if (argc <= i + 2) {
159 0 : NaClLog(LOG_FATAL, "not enough args for --var option\n");
160 : }
161 :
162 2 : const string tag = string(argv[i + 1]);
163 4 : const string val = string(argv[i + 2]);
164 2 : i += 2;
165 4 : initial_vars[tag] = val;
166 17 : } else if (flag == "--uses_reverse_service") {
167 2 : uses_reverse_service = true;
168 15 : } else if (flag == "--") {
169 : // Done processing sel_ldr args. The first argument after '--' is the
170 : // nexe.
171 11 : i++;
172 11 : if (app_name == "" && i < argc) {
173 11 : app_name = argv[i++];
174 : }
175 : // The remaining arguments are passed to the executable.
176 22 : for (; i < argc; i++) {
177 0 : app_argv->push_back(argv[i]);
178 : }
179 : } else {
180 : // NOTE: most sel_ldr args start with a single hyphen so there is not
181 : // much confusion with sel_universal args. But this remains a hack.
182 4 : sel_ldr_argv->push_back(argv[i]);
183 : }
184 : }
185 :
186 11 : if (debug_level > 0) {
187 0 : NaClLogSetVerbosity(debug_level);
188 : }
189 :
190 11 : if (app_name == "") {
191 0 : NaClLog(LOG_FATAL, "missing app\n");
192 : }
193 :
194 0 : return app_name;
195 : }
196 :
197 :
198 11 : int raii_main(int argc, char* argv[]) {
199 : // Get the arguments to sed_ldr and the nexe module
200 11 : vector<nacl::string> sel_ldr_argv;
201 22 : vector<nacl::string> app_argv;
202 : nacl::string app_name =
203 11 : ProcessArguments(argc, argv, &sel_ldr_argv, &app_argv);
204 :
205 : // Add '-X 5' to sel_ldr arguments to create communication socket
206 11 : sel_ldr_argv.push_back("-X");
207 22 : sel_ldr_argv.push_back("5");
208 11 : if (silence_nexe) {
209 : // redirect stdout/stderr in the nexe to /dev/null
210 0 : std::stringstream ss_stdout;
211 0 : std::stringstream ss_stderr;
212 :
213 0 : int fd = open(PORTABLE_DEV_NULL, O_RDWR);
214 0 : sel_ldr_argv.push_back("-w");
215 0 : ss_stdout << "1:" << fd;
216 0 : sel_ldr_argv.push_back(ss_stdout.str());
217 0 : sel_ldr_argv.push_back("-w");
218 0 : ss_stderr << "2:" << fd;
219 0 : sel_ldr_argv.push_back(ss_stderr.str());
220 : }
221 : // Start sel_ldr with the given application and arguments.
222 11 : nacl::SelLdrLauncher launcher;
223 11 : nacl::DescWrapperFactory factory; // DescWrapper "namespace"
224 :
225 11 : if (command_prefix != "") {
226 0 : launcher.SetCommandPrefix(command_prefix);
227 : }
228 :
229 11 : launcher.InitCommandLine(5, sel_ldr_argv, app_argv);
230 11 : if (!launcher.LaunchFromCommandLine()) {
231 0 : NaClLog(LOG_FATAL, "sel_universal: Failed to launch sel_ldr\n");
232 : }
233 :
234 11 : DescWrapper *host_file = factory.OpenHostFile(app_name.c_str(), O_RDONLY, 0);
235 11 : if (NULL == host_file) {
236 0 : NaClLog(LOG_ERROR, "Could not open %s\n", app_name.c_str());
237 0 : exit(1);
238 : }
239 :
240 11 : if (!launcher.SetupCommandAndLoad(&command_channel, host_file)) {
241 0 : NaClLog(LOG_ERROR, "sel_universal: set up command and load failed\n");
242 0 : exit(1);
243 : }
244 :
245 11 : delete host_file;
246 :
247 11 : if (uses_reverse_service) {
248 2 : ReverseEmulateInit(&command_channel, &launcher);
249 : }
250 :
251 11 : if (!launcher.StartModuleAndSetupAppChannel(&command_channel, &channel)) {
252 : NaClLog(LOG_ERROR,
253 1 : "sel_universal: start module and set up app channel failed\n");
254 1 : exit(1);
255 : }
256 :
257 : NaClCommandLoop loop(channel.client,
258 : &channel,
259 10 : launcher.socket_addr()->desc());
260 :
261 : //
262 : // Pepper sample commands
263 : // initialize_pepper pepper
264 : // sdl_initialize OR (replay*; replay_activate)
265 : // install_upcalls service
266 : // show_variables
267 : // show_descriptors
268 : // rpc PPP_InitializeModule i(0) l(0) h(pepper) s("${service}") * i(0) i(0)
269 :
270 10 : loop.AddHandler("replay_activate", HandlerReplayActivate);
271 20 : loop.AddHandler("replay", HandlerReplay);
272 20 : loop.AddHandler("replay_unused", HandlerUnusedReplays);
273 :
274 : // possible platform specific stuff
275 20 : loop.AddHandler("shmem", HandlerShmem);
276 20 : loop.AddHandler("readonly_file", HandlerReadonlyFile);
277 20 : loop.AddHandler("readwrite_file", HandlerReadwriteFile);
278 20 : loop.AddHandler("readwrite_quota_file", HandlerReadwriteFileQuota);
279 20 : loop.AddHandler("sleep", HandlerSleep);
280 20 : loop.AddHandler("map_shmem", HandlerMap);
281 20 : loop.AddHandler("save_to_file", HandlerSaveToFile);
282 20 : loop.AddHandler("load_from_file", HandlerLoadFromFile);
283 20 : loop.AddHandler("file_size", HandlerFileSize);
284 20 : loop.AddHandler("sync_socket_create", HandlerSyncSocketCreate);
285 20 : loop.AddHandler("sync_socket_write", HandlerSyncSocketWrite);
286 : // obsolete names
287 20 : loop.AddHandler("sdl_initialize", HandlerPepperEmuInitialize);
288 20 : loop.AddHandler("sdl_event_loop", HandlerPepperEmuEventLoop);
289 : // new names
290 20 : loop.AddHandler("pnacl_emu_initialize", HandlerPnaclEmuInitialize);
291 : loop.AddHandler("pnacl_emu_add_varname_mapping",
292 20 : HandlerPnaclEmuAddVarnameMapping);
293 : loop.AddHandler("reverse_service_add_manifest_mapping",
294 20 : HandlerReverseEmuAddManifestMapping);
295 : loop.AddHandler("reverse_service_dump_manifest_mappings",
296 20 : HandlerReverseEmuDumpManifestMappings);
297 20 : loop.AddHandler("stream_file", HandlerPnaclFileStream);
298 :
299 20 : loop.AddHandler("pepper_emu_initialize", HandlerPepperEmuInitialize);
300 20 : loop.AddHandler("pepper_emu_event_loop", HandlerPepperEmuEventLoop);
301 : loop.AddHandler("pepper_emu_set_quit_message",
302 20 : HandlerPepperEmuSetQuitMessage);
303 :
304 10 : NaClLog(1, "populating initial vars\n");
305 12 : for (map<string, string>::iterator it = initial_vars.begin();
306 : it != initial_vars.end();
307 : ++it) {
308 2 : loop.SetVariable(it->first, it->second);
309 : }
310 :
311 : const bool success = initial_commands.size() > 0 ?
312 : loop.ProcessCommands(initial_commands) :
313 10 : loop.StartInteractiveLoop(abort_on_error);
314 :
315 : // Close the connections to sel_ldr.
316 10 : NaClSrpcDtor(&command_channel);
317 10 : NaClSrpcDtor(&channel);
318 :
319 10 : if (uses_reverse_service) {
320 2 : ReverseEmulateFini();
321 : }
322 :
323 10 : return success ? 0 : -1;
324 : }
325 :
326 11 : int main(int argc, char* argv[]) {
327 : // Descriptor transfer requires the following
328 11 : NaClSrpcModuleInit();
329 11 : NaClNrdAllModulesInit();
330 :
331 11 : int exit_status = raii_main(argc, argv);
332 :
333 10 : NaClSrpcModuleFini();
334 10 : NaClNrdAllModulesFini();
335 :
336 10 : return exit_status;
337 22 : }
|