OLD | NEW |
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
4 | 4 |
5 library fletch_agent.agent; | 5 library dartino_agent.agent; |
6 | 6 |
7 import 'dart:convert' show UTF8; | 7 import 'dart:convert' show UTF8; |
8 import 'dart:fletch'; | 8 import 'dart:dartino'; |
9 import 'dart:fletch.ffi'; | 9 import 'dart:dartino.ffi'; |
10 import 'dart:fletch.os' as os; | 10 import 'dart:dartino.os' as os; |
11 import 'dart:typed_data'; | 11 import 'dart:typed_data'; |
12 | 12 |
13 import 'package:ffi/ffi.dart'; | 13 import 'package:ffi/ffi.dart'; |
14 import 'package:file/file.dart'; | 14 import 'package:file/file.dart'; |
15 import 'package:fletch/fletch.dart' as fletch; | 15 import 'package:dartino/dartino.dart' as dartino; |
16 import 'package:os/os.dart' show sys; | 16 import 'package:os/os.dart' show sys; |
17 import 'package:socket/socket.dart'; | 17 import 'package:socket/socket.dart'; |
18 | 18 |
19 import '../lib/messages.dart'; | 19 import '../lib/messages.dart'; |
20 | 20 |
21 class Logger { | 21 class Logger { |
22 final String _prefix; | 22 final String _prefix; |
23 final String _path; | 23 final String _path; |
24 final bool _logToStdout; | 24 final bool _logToStdout; |
25 | 25 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 return cStringToString(ptr); | 66 return cStringToString(ptr); |
67 } | 67 } |
68 | 68 |
69 // Agent specific info. | 69 // Agent specific info. |
70 final String ip; | 70 final String ip; |
71 final int port; | 71 final int port; |
72 final String pidFile; | 72 final String pidFile; |
73 final Logger logger; | 73 final Logger logger; |
74 final bool applyUpgrade; | 74 final bool applyUpgrade; |
75 | 75 |
76 // Fletch-vm path and args. | 76 // Dartino-vm path and args. |
77 final String vmBinPath; | 77 final String vmBinPath; |
78 final String vmLogDir; | 78 final String vmLogDir; |
79 final String tmpDir; | 79 final String tmpDir; |
80 | 80 |
81 factory AgentContext() { | 81 factory AgentContext() { |
82 String ip = _getEnv('AGENT_IP'); | 82 String ip = _getEnv('AGENT_IP'); |
83 if (ip == null) { | 83 if (ip == null) { |
84 ip = '0.0.0.0'; | 84 ip = '0.0.0.0'; |
85 } | 85 } |
86 int port; | 86 int port; |
87 try { | 87 try { |
88 String portStr = _getEnv('AGENT_PORT'); | 88 String portStr = _getEnv('AGENT_PORT'); |
89 port = int.parse(portStr); | 89 port = int.parse(portStr); |
90 } catch (_) { | 90 } catch (_) { |
91 port = AGENT_DEFAULT_PORT; // default | 91 port = AGENT_DEFAULT_PORT; // default |
92 } | 92 } |
93 String logFile = _getEnv('AGENT_LOG_FILE'); | 93 String logFile = _getEnv('AGENT_LOG_FILE'); |
94 if (logFile == null) { | 94 if (logFile == null) { |
95 print('Agent requires a valid log file. Please specify file path in ' | 95 print('Agent requires a valid log file. Please specify file path in ' |
96 'the AGENT_LOG_FILE environment variable.'); | 96 'the AGENT_LOG_FILE environment variable.'); |
97 Process.exit(); | 97 Process.exit(); |
98 } | 98 } |
99 var logger = new Logger('Agent', logFile); | 99 var logger = new Logger('Agent', logFile); |
100 String pidFile = _getEnv('AGENT_PID_FILE'); | 100 String pidFile = _getEnv('AGENT_PID_FILE'); |
101 if (pidFile == null) { | 101 if (pidFile == null) { |
102 logger.error('Agent requires a valid pid file. Please specify file path ' | 102 logger.error('Agent requires a valid pid file. Please specify file path ' |
103 'in the AGENT_PID_FILE environment variable.'); | 103 'in the AGENT_PID_FILE environment variable.'); |
104 Process.exit(); | 104 Process.exit(); |
105 } | 105 } |
106 String vmBinPath = _getEnv('FLETCH_VM'); | 106 String vmBinPath = _getEnv('DARTINO_VM'); |
107 String vmLogDir = _getEnv('VM_LOG_DIR'); | 107 String vmLogDir = _getEnv('VM_LOG_DIR'); |
108 String tmpDir = _getEnv('TMPDIR'); | 108 String tmpDir = _getEnv('TMPDIR'); |
109 if (tmpDir == null) tmpDir = '/tmp'; | 109 if (tmpDir == null) tmpDir = '/tmp'; |
110 | 110 |
111 // If the below ENV variable is set the agent will just store the agent | 111 // If the below ENV variable is set the agent will just store the agent |
112 // debian package but not apply it. | 112 // debian package but not apply it. |
113 bool applyUpgrade = _getEnv('AGENT_UPGRADE_DRY_RUN') == null; | 113 bool applyUpgrade = _getEnv('AGENT_UPGRADE_DRY_RUN') == null; |
114 | 114 |
115 logger.info('Agent log file: $logFile'); | 115 logger.info('Agent log file: $logFile'); |
116 logger.info('Agent pid file: $pidFile'); | 116 logger.info('Agent pid file: $pidFile'); |
117 logger.info('Vm path: $vmBinPath'); | 117 logger.info('Vm path: $vmBinPath'); |
118 logger.info('Log path: $vmLogDir'); | 118 logger.info('Log path: $vmLogDir'); |
119 | 119 |
120 // Make sure we have a fletch-vm binary we can use for launching a vm. | 120 // Make sure we have a dartino-vm binary we can use for launching a vm. |
121 if (!File.existsAsFile(vmBinPath)) { | 121 if (!File.existsAsFile(vmBinPath)) { |
122 logger.error('Cannot find fletch vm at path: $vmBinPath'); | 122 logger.error('Cannot find dartino vm at path: $vmBinPath'); |
123 Process.exit(); | 123 Process.exit(); |
124 } | 124 } |
125 // Make sure we have a valid log directory. | 125 // Make sure we have a valid log directory. |
126 if (!File.existsAsFile(vmLogDir)) { | 126 if (!File.existsAsFile(vmLogDir)) { |
127 logger.error('Cannot find log directory: $vmLogDir'); | 127 logger.error('Cannot find log directory: $vmLogDir'); |
128 Process.exit(); | 128 Process.exit(); |
129 } | 129 } |
130 return new AgentContext._( | 130 return new AgentContext._( |
131 ip, port, pidFile, logger, vmBinPath, vmLogDir, tmpDir, applyUpgrade); | 131 ip, port, pidFile, logger, vmBinPath, vmLogDir, tmpDir, applyUpgrade); |
132 } | 132 } |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 break; | 205 break; |
206 case RequestHeader.STOP_VM: | 206 case RequestHeader.STOP_VM: |
207 _stopVm(); | 207 _stopVm(); |
208 break; | 208 break; |
209 case RequestHeader.LIST_VMS: | 209 case RequestHeader.LIST_VMS: |
210 _listVms(); | 210 _listVms(); |
211 break; | 211 break; |
212 case RequestHeader.UPGRADE_AGENT: | 212 case RequestHeader.UPGRADE_AGENT: |
213 _upgradeAgent(); | 213 _upgradeAgent(); |
214 break; | 214 break; |
215 case RequestHeader.FLETCH_VERSION: | 215 case RequestHeader.DARTINO_VERSION: |
216 _fletchVersion(); | 216 _dartinoVersion(); |
217 break; | 217 break; |
218 case RequestHeader.SIGNAL_VM: | 218 case RequestHeader.SIGNAL_VM: |
219 _signalVm(); | 219 _signalVm(); |
220 break; | 220 break; |
221 default: | 221 default: |
222 _context.logger.warn('Unknown command: ${_requestHeader.command}.'); | 222 _context.logger.warn('Unknown command: ${_requestHeader.command}.'); |
223 _sendReply( | 223 _sendReply( |
224 new ReplyHeader(_requestHeader.id, ReplyHeader.UNKNOWN_COMMAND)); | 224 new ReplyHeader(_requestHeader.id, ReplyHeader.UNKNOWN_COMMAND)); |
225 break; | 225 break; |
226 } | 226 } |
(...skipping 11 matching lines...) Expand all Loading... |
238 File portFile = new File.temporary("${_context.tmpDir}/vm-port-"); | 238 File portFile = new File.temporary("${_context.tmpDir}/vm-port-"); |
239 try { | 239 try { |
240 List<String> args = ['--log-dir=${_context.vmLogDir}', | 240 List<String> args = ['--log-dir=${_context.vmLogDir}', |
241 '--port-file=${portFile.path}', '--host=0.0.0.0']; | 241 '--port-file=${portFile.path}', '--host=0.0.0.0']; |
242 vmPid = os.NativeProcess.startDetached(_context.vmBinPath, args); | 242 vmPid = os.NativeProcess.startDetached(_context.vmBinPath, args); |
243 // Find out what port the vm is listening on. | 243 // Find out what port the vm is listening on. |
244 _context.logger.info('Reading port from ${portFile.path} for vm $vmPid'); | 244 _context.logger.info('Reading port from ${portFile.path} for vm $vmPid'); |
245 int port = _retrieveVmPort(portFile.path); | 245 int port = _retrieveVmPort(portFile.path); |
246 reply = new StartVmReply( | 246 reply = new StartVmReply( |
247 _requestHeader.id, ReplyHeader.SUCCESS, vmId: vmPid, vmPort: port); | 247 _requestHeader.id, ReplyHeader.SUCCESS, vmId: vmPid, vmPort: port); |
248 _context.logger.info('Started fletch vm with pid $vmPid on port $port'); | 248 _context.logger.info('Started dartino vm with pid $vmPid on port $port'); |
249 } catch (e) { | 249 } catch (e) { |
250 reply = new StartVmReply(_requestHeader.id, ReplyHeader.START_VM_FAILED); | 250 reply = new StartVmReply(_requestHeader.id, ReplyHeader.START_VM_FAILED); |
251 // TODO(wibling): could extend the result with caught error string. | 251 // TODO(wibling): could extend the result with caught error string. |
252 _context.logger.warn('Failed to start vm with error: $e'); | 252 _context.logger.warn('Failed to start vm with error: $e'); |
253 if (vmPid > 0) { | 253 if (vmPid > 0) { |
254 // Kill the vm. | 254 // Kill the vm. |
255 _kill.icall$2(vmPid, SIGTERM); | 255 _kill.icall$2(vmPid, SIGTERM); |
256 } | 256 } |
257 } finally { | 257 } finally { |
258 File.delete(portFile.path); | 258 File.delete(portFile.path); |
259 } | 259 } |
260 _sendReply(reply); | 260 _sendReply(reply); |
261 } | 261 } |
262 | 262 |
263 int _retrieveVmPort(String portPath) { | 263 int _retrieveVmPort(String portPath) { |
264 // The fletch-vm will write the port it is listening on into the file | 264 // The dartino-vm will write the port it is listening on into the file |
265 // specified by 'portPath' above. The agent waits for the file to be | 265 // specified by 'portPath' above. The agent waits for the file to be |
266 // created (retries the File.open until it succeeds) and then reads the | 266 // created (retries the File.open until it succeeds) and then reads the |
267 // port from the file. | 267 // port from the file. |
268 // To make sure we are reading a consistent value from the file, ie. the | 268 // To make sure we are reading a consistent value from the file, ie. the |
269 // vm could have written a partial value at the time we read it, we continue | 269 // vm could have written a partial value at the time we read it, we continue |
270 // reading the value from the file until we have read the same value from | 270 // reading the value from the file until we have read the same value from |
271 // file in two consecutive reads. | 271 // file in two consecutive reads. |
272 // An alternative to the consecutive reading would be to use cooperative | 272 // An alternative to the consecutive reading would be to use cooperative |
273 // locking, but consecutive reading is not relying on the fletch-vm to | 273 // locking, but consecutive reading is not relying on the dartino-vm to |
274 // behave. | 274 // behave. |
275 // TODO(wibling): Look into passing a socket port to the fletch-vm and | 275 // TODO(wibling): Look into passing a socket port to the dartino-vm and |
276 // have it write the port to the socket. This allows the agent to just | 276 // have it write the port to the socket. This allows the agent to just |
277 // wait on the socket and wake up when it is ready. | 277 // wait on the socket and wake up when it is ready. |
278 int previousPort = -1; | 278 int previousPort = -1; |
279 for (int retries = 500; retries >= 0; --retries) { | 279 for (int retries = 500; retries >= 0; --retries) { |
280 int port = _tryReadPort(portPath, retries == 0); | 280 int port = _tryReadPort(portPath, retries == 0); |
281 // Check if we read the same port value twice in a row. | 281 // Check if we read the same port value twice in a row. |
282 if (previousPort != -1 && previousPort == port) return port; | 282 if (previousPort != -1 && previousPort == port) return port; |
283 previousPort = port; | 283 previousPort = port; |
284 os.sleep(10); | 284 os.sleep(10); |
285 } | 285 } |
(...skipping 28 matching lines...) Expand all Loading... |
314 if (_requestHeader.payloadLength != 4) { | 314 if (_requestHeader.payloadLength != 4) { |
315 _sendReply( | 315 _sendReply( |
316 new StopVmReply(_requestHeader.id, ReplyHeader.INVALID_PAYLOAD)); | 316 new StopVmReply(_requestHeader.id, ReplyHeader.INVALID_PAYLOAD)); |
317 return; | 317 return; |
318 } | 318 } |
319 var reply; | 319 var reply; |
320 // Read in the vm id. | 320 // Read in the vm id. |
321 var pidBytes = _socket.read(4); | 321 var pidBytes = _socket.read(4); |
322 if (pidBytes == null) { | 322 if (pidBytes == null) { |
323 reply = new StopVmReply(_requestHeader.id, ReplyHeader.INVALID_PAYLOAD); | 323 reply = new StopVmReply(_requestHeader.id, ReplyHeader.INVALID_PAYLOAD); |
324 _context.logger.warn('Missing pid of the fletch vm to stop.'); | 324 _context.logger.warn('Missing pid of the dartino vm to stop.'); |
325 } else { | 325 } else { |
326 int pid = readUint32(pidBytes, 0); | 326 int pid = readUint32(pidBytes, 0); |
327 int err = _kill.icall$2(pid, SIGTERM); | 327 int err = _kill.icall$2(pid, SIGTERM); |
328 if (err != 0) { | 328 if (err != 0) { |
329 reply = new StopVmReply(_requestHeader.id, ReplyHeader.UNKNOWN_VM_ID); | 329 reply = new StopVmReply(_requestHeader.id, ReplyHeader.UNKNOWN_VM_ID); |
330 _context.logger.warn( | 330 _context.logger.warn( |
331 'Failed to stop pid $pid with error: ${Foreign.errno}'); | 331 'Failed to stop pid $pid with error: ${Foreign.errno}'); |
332 } else { | 332 } else { |
333 reply = new StopVmReply(_requestHeader.id, ReplyHeader.SUCCESS); | 333 reply = new StopVmReply(_requestHeader.id, ReplyHeader.SUCCESS); |
334 _context.logger.info('Stopped pid: $pid'); | 334 _context.logger.info('Stopped pid: $pid'); |
335 } | 335 } |
336 } | 336 } |
337 _sendReply(reply); | 337 _sendReply(reply); |
338 } | 338 } |
339 | 339 |
340 void _signalVm() { | 340 void _signalVm() { |
341 if (_requestHeader.payloadLength != 8) { | 341 if (_requestHeader.payloadLength != 8) { |
342 _sendReply( | 342 _sendReply( |
343 new SignalVmReply(_requestHeader.id, ReplyHeader.INVALID_PAYLOAD)); | 343 new SignalVmReply(_requestHeader.id, ReplyHeader.INVALID_PAYLOAD)); |
344 return; | 344 return; |
345 } | 345 } |
346 var reply; | 346 var reply; |
347 // Read in the vm id and the signal to send. | 347 // Read in the vm id and the signal to send. |
348 var pidBytes = _socket.read(8); | 348 var pidBytes = _socket.read(8); |
349 if (pidBytes == null) { | 349 if (pidBytes == null) { |
350 reply = new SignalVmReply(_requestHeader.id, ReplyHeader.INVALID_PAYLOAD); | 350 reply = new SignalVmReply(_requestHeader.id, ReplyHeader.INVALID_PAYLOAD); |
351 _context.logger.warn('Missing pid of the fletch vm to signal.'); | 351 _context.logger.warn('Missing pid of the dartino vm to signal.'); |
352 } else { | 352 } else { |
353 int pid = readUint32(pidBytes, 0); | 353 int pid = readUint32(pidBytes, 0); |
354 int signal = readUint32(pidBytes, 4); | 354 int signal = readUint32(pidBytes, 4); |
355 // Hack to make ctrl-c work for stopping spawned vms work on Raspbian | 355 // Hack to make ctrl-c work for stopping spawned vms work on Raspbian |
356 // wheezy. For some reason SIGINT doesn't work so we map it to SIGTERM as | 356 // wheezy. For some reason SIGINT doesn't work so we map it to SIGTERM as |
357 // a workaround. | 357 // a workaround. |
358 if (signal == SIGINT && sys.info().release.startsWith('3.18')) { | 358 if (signal == SIGINT && sys.info().release.startsWith('3.18')) { |
359 _context.logger.info('Remapping SIGINT to SIGTERM on Raspbian wheezy'); | 359 _context.logger.info('Remapping SIGINT to SIGTERM on Raspbian wheezy'); |
360 signal = SIGTERM; | 360 signal = SIGTERM; |
361 } | 361 } |
(...skipping 13 matching lines...) Expand all Loading... |
375 void _listVms() { | 375 void _listVms() { |
376 // TODO(wibling): implement this method. For now just hardcode some values. | 376 // TODO(wibling): implement this method. For now just hardcode some values. |
377 _sendReply( | 377 _sendReply( |
378 new ListVmsReply(_requestHeader.id, ReplyHeader.UNKNOWN_COMMAND)); | 378 new ListVmsReply(_requestHeader.id, ReplyHeader.UNKNOWN_COMMAND)); |
379 } | 379 } |
380 | 380 |
381 void _upgradeAgent() { | 381 void _upgradeAgent() { |
382 int result; | 382 int result; |
383 ByteBuffer binary = _socket.read(_requestHeader.payloadLength); | 383 ByteBuffer binary = _socket.read(_requestHeader.payloadLength); |
384 if (binary == null) { | 384 if (binary == null) { |
385 _context.logger.warn('Could not read fletch-agent package binary' | 385 _context.logger.warn('Could not read dartino-agent package binary' |
386 ' of length ${_requestHeader.payloadLength} bytes'); | 386 ' of length ${_requestHeader.payloadLength} bytes'); |
387 result = ReplyHeader.INVALID_PAYLOAD; | 387 result = ReplyHeader.INVALID_PAYLOAD; |
388 } else { | 388 } else { |
389 _context.logger.info('Read fletch-agent package binary' | 389 _context.logger.info('Read dartino-agent package binary' |
390 ' of length ${binary.lengthInBytes} bytes.'); | 390 ' of length ${binary.lengthInBytes} bytes.'); |
391 File file = new File.open(PACKAGE_FILE_NAME, mode: File.WRITE); | 391 File file = new File.open(PACKAGE_FILE_NAME, mode: File.WRITE); |
392 try { | 392 try { |
393 file.write(binary); | 393 file.write(binary); |
394 } catch (e) { | 394 } catch (e) { |
395 _context.logger.warn('UpgradeAgent failed: $e'); | 395 _context.logger.warn('UpgradeAgent failed: $e'); |
396 _sendReply(new UpgradeAgentReply(_requestHeader.id, | 396 _sendReply(new UpgradeAgentReply(_requestHeader.id, |
397 ReplyHeader.UPGRADE_FAILED)); | 397 ReplyHeader.UPGRADE_FAILED)); |
398 } finally { | 398 } finally { |
399 file.close(); | 399 file.close(); |
400 } | 400 } |
401 _context.logger.info('Package file written successfully.'); | 401 _context.logger.info('Package file written successfully.'); |
402 if (_context.applyUpgrade) { | 402 if (_context.applyUpgrade) { |
403 int pid = os.NativeProcess.startDetached('/usr/bin/dpkg', | 403 int pid = os.NativeProcess.startDetached('/usr/bin/dpkg', |
404 [// Force dpkg to overwrite configuration files installed by | 404 [// Force dpkg to overwrite configuration files installed by |
405 // the agent. | 405 // the agent. |
406 '--force-confnew', | 406 '--force-confnew', |
407 '--install', | 407 '--install', |
408 PACKAGE_FILE_NAME]); | 408 PACKAGE_FILE_NAME]); |
409 _context.logger.info('started package update (PID $pid)'); | 409 _context.logger.info('started package update (PID $pid)'); |
410 } | 410 } |
411 result = ReplyHeader.SUCCESS; | 411 result = ReplyHeader.SUCCESS; |
412 } | 412 } |
413 _context.logger.info('sending reply'); | 413 _context.logger.info('sending reply'); |
414 _sendReply(new UpgradeAgentReply(_requestHeader.id, result)); | 414 _sendReply(new UpgradeAgentReply(_requestHeader.id, result)); |
415 } | 415 } |
416 | 416 |
417 void _fletchVersion() { | 417 void _dartinoVersion() { |
418 String version = fletch.version(); | 418 String version = dartino.version(); |
419 _context.logger.info('Returning fletch version $version'); | 419 _context.logger.info('Returning dartino version $version'); |
420 _sendReply(new FletchVersionReply( | 420 _sendReply(new DartinoVersionReply( |
421 _requestHeader.id, ReplyHeader.SUCCESS, version: version)); | 421 _requestHeader.id, ReplyHeader.SUCCESS, version: version)); |
422 } | 422 } |
423 } | 423 } |
424 | 424 |
425 void main(List<String> arguments) { | 425 void main(List<String> arguments) { |
426 // The agent context will initialize itself from the runtime environment. | 426 // The agent context will initialize itself from the runtime environment. |
427 var context = new AgentContext(); | 427 var context = new AgentContext(); |
428 | 428 |
429 // Write the program's pid to the pid file if set. | 429 // Write the program's pid to the pid file if set. |
430 _writePid(context.pidFile); | 430 _writePid(context.pidFile); |
431 | 431 |
432 // Run fletch agent on given ip address and port. | 432 // Run dartino agent on given ip address and port. |
433 var agent = new Agent(context); | 433 var agent = new Agent(context); |
434 agent.start(); | 434 agent.start(); |
435 } | 435 } |
436 | 436 |
437 void _writePid(String pidFilePath) { | 437 void _writePid(String pidFilePath) { |
438 final ForeignFunction _getpid = ForeignLibrary.main.lookup('getpid'); | 438 final ForeignFunction _getpid = ForeignLibrary.main.lookup('getpid'); |
439 | 439 |
440 int pid = _getpid.icall$0(); | 440 int pid = _getpid.icall$0(); |
441 List<int> encodedPid = UTF8.encode('$pid'); | 441 List<int> encodedPid = UTF8.encode('$pid'); |
442 ByteBuffer buffer = new Uint8List.fromList(encodedPid).buffer; | 442 ByteBuffer buffer = new Uint8List.fromList(encodedPid).buffer; |
443 var pidFile = new File.open(pidFilePath, mode: File.WRITE); | 443 var pidFile = new File.open(pidFilePath, mode: File.WRITE); |
444 try { | 444 try { |
445 pidFile.write(buffer); | 445 pidFile.write(buffer); |
446 } finally { | 446 } finally { |
447 pidFile.close(); | 447 pidFile.close(); |
448 } | 448 } |
449 } | 449 } |
450 | 450 |
451 void printUsage() { | 451 void printUsage() { |
452 print('Usage:'); | 452 print('Usage:'); |
453 print('The Fletch agent supports the following flags'); | 453 print('The Dartino agent supports the following flags'); |
454 print(''); | 454 print(''); |
455 print(' --port: specify the port on which to listen, default: ' | 455 print(' --port: specify the port on which to listen, default: ' |
456 '$AGENT_DEFAULT_PORT'); | 456 '$AGENT_DEFAULT_PORT'); |
457 print(' --ip: specify the ip address on which to listen, default: 0.0.0.0'); | 457 print(' --ip: specify the ip address on which to listen, default: 0.0.0.0'); |
458 print(' --vm: specify the path to the vm binary, default: ' | 458 print(' --vm: specify the path to the vm binary, default: ' |
459 '/opt/fletch/bin/fletch-vm.'); | 459 '/opt/dartino/bin/dartino-vm.'); |
460 print(''); | 460 print(''); |
461 Process.exit(); | 461 Process.exit(); |
462 } | 462 } |
OLD | NEW |