// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #include "bin/dartutils.h" #include "bin/io_buffer.h" #include "bin/process.h" #include "bin/socket.h" #include "include/dart_api.h" static const int kProcessIdNativeField = 0; int Process::global_exit_code_ = 0; dart::Mutex Process::global_exit_code_mutex_; // Extract an array of C strings from a list of Dart strings. static char** ExtractCStringList(Dart_Handle strings, Dart_Handle status_handle, const char* error_msg, intptr_t* length) { static const intptr_t kMaxArgumentListLength = 1024 * 1024; ASSERT(Dart_IsList(strings)); intptr_t len = 0; Dart_Handle result = Dart_ListLength(strings, &len); if (Dart_IsError(result)) { Dart_PropagateError(result); } // Protect against user-defined list implementations that can have // arbitrary length. if (len < 0 || len > kMaxArgumentListLength) { DartUtils::SetIntegerField(status_handle, "_errorCode", 0); DartUtils::SetStringField( status_handle, "_errorMessage", "Max argument list length exceeded"); return NULL; } *length = len; char** string_args = new char*[len]; for (int i = 0; i < len; i++) { Dart_Handle arg = Dart_ListGetAt(strings, i); if (Dart_IsError(arg)) { delete[] string_args; Dart_PropagateError(arg); } if (!Dart_IsString(arg)) { DartUtils::SetIntegerField(status_handle, "_errorCode", 0); DartUtils::SetStringField( status_handle, "_errorMessage", error_msg); delete[] string_args; return NULL; } string_args[i] = const_cast(DartUtils::GetStringValue(arg)); } return string_args; } void FUNCTION_NAME(Process_Start)(Dart_NativeArguments args) { Dart_EnterScope(); Dart_Handle process = Dart_GetNativeArgument(args, 0); intptr_t in; intptr_t out; intptr_t err; intptr_t exit_event; Dart_Handle status_handle = Dart_GetNativeArgument(args, 9); Dart_Handle path_handle = Dart_GetNativeArgument(args, 1); // The Dart code verifies that the path implements the String // interface. However, only builtin Strings are handled by // GetStringValue. if (!Dart_IsString(path_handle)) { DartUtils::SetIntegerField(status_handle, "_errorCode", 0); DartUtils::SetStringField( status_handle, "_errorMessage", "Path must be a builtin string"); Dart_SetReturnValue(args, Dart_NewBoolean(false)); Dart_ExitScope(); return; } const char* path = DartUtils::GetStringValue(path_handle); Dart_Handle arguments = Dart_GetNativeArgument(args, 2); intptr_t args_length = 0; char** string_args = ExtractCStringList(arguments, status_handle, "Arguments must be builtin strings", &args_length); if (string_args == NULL) { Dart_SetReturnValue(args, Dart_NewBoolean(false)); Dart_ExitScope(); return; } Dart_Handle working_directory_handle = Dart_GetNativeArgument(args, 3); // Defaults to the current working directoy. const char* working_directory = NULL; if (Dart_IsString(working_directory_handle)) { working_directory = DartUtils::GetStringValue(working_directory_handle); } else if (!Dart_IsNull(working_directory_handle)) { delete[] string_args; DartUtils::SetIntegerField(status_handle, "_errorCode", 0); DartUtils::SetStringField( status_handle, "_errorMessage", "WorkingDirectory must be a builtin string"); Dart_SetReturnValue(args, Dart_NewBoolean(false)); Dart_ExitScope(); return; } Dart_Handle environment = Dart_GetNativeArgument(args, 4); intptr_t environment_length = 0; char** string_environment = NULL; if (!Dart_IsNull(environment)) { string_environment = ExtractCStringList(environment, status_handle, "Environment values must be builtin strings", &environment_length); if (string_environment == NULL) { delete[] string_args; Dart_SetReturnValue(args, Dart_NewBoolean(false)); Dart_ExitScope(); return; } } Dart_Handle in_handle = Dart_GetNativeArgument(args, 5); Dart_Handle out_handle = Dart_GetNativeArgument(args, 6); Dart_Handle err_handle = Dart_GetNativeArgument(args, 7); Dart_Handle exit_handle = Dart_GetNativeArgument(args, 8); intptr_t pid = -1; char* os_error_message = NULL; int error_code = Process::Start(path, string_args, args_length, working_directory, string_environment, environment_length, &in, &out, &err, &pid, &exit_event, &os_error_message); if (error_code == 0) { Socket::SetSocketIdNativeField(in_handle, in); Socket::SetSocketIdNativeField(out_handle, out); Socket::SetSocketIdNativeField(err_handle, err); Socket::SetSocketIdNativeField(exit_handle, exit_event); Process::SetProcessIdNativeField(process, pid); } else { DartUtils::SetIntegerField( status_handle, "_errorCode", error_code); DartUtils::SetStringField( status_handle, "_errorMessage", os_error_message); } delete[] string_args; delete[] string_environment; free(os_error_message); Dart_SetReturnValue(args, Dart_NewBoolean(error_code == 0)); Dart_ExitScope(); } void FUNCTION_NAME(Process_Kill)(Dart_NativeArguments args) { Dart_EnterScope(); Dart_Handle process = Dart_GetNativeArgument(args, 1); intptr_t pid = -1; Process::GetProcessIdNativeField(process, &pid); int signal = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2)); bool success = Process::Kill(pid, signal); Dart_SetReturnValue(args, Dart_NewBoolean(success)); Dart_ExitScope(); } void FUNCTION_NAME(Process_Exit)(Dart_NativeArguments args) { Dart_EnterScope(); int64_t status = 0; // Ignore result if passing invalid argument and just exit 0. DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &status); Dart_ExitScope(); exit(static_cast(status)); } void FUNCTION_NAME(Process_SetExitCode)(Dart_NativeArguments args) { Dart_EnterScope(); int64_t status = 0; // Ignore result if passing invalid argument and just set exit code to 0. DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &status); Process::SetGlobalExitCode(status); Dart_ExitScope(); } Dart_Handle Process::GetProcessIdNativeField(Dart_Handle process, intptr_t* pid) { return Dart_GetNativeInstanceField(process, kProcessIdNativeField, pid); } Dart_Handle Process::SetProcessIdNativeField(Dart_Handle process, intptr_t pid) { return Dart_SetNativeInstanceField(process, kProcessIdNativeField, pid); } void FUNCTION_NAME(SystemEncodingToString)(Dart_NativeArguments args) { Dart_EnterScope(); Dart_Handle bytes = Dart_GetNativeArgument(args, 0); intptr_t bytes_length = 0; Dart_Handle result = Dart_ListLength(bytes, &bytes_length); if (Dart_IsError(result)) Dart_PropagateError(result); uint8_t* buffer = new uint8_t[bytes_length + 1]; result = Dart_ListGetAsBytes(bytes, 0, buffer, bytes_length); buffer[bytes_length] = '\0'; if (Dart_IsError(result)) { delete[] buffer; Dart_PropagateError(result); } char* str = StringUtils::ConsoleStringToUtf8(reinterpret_cast(buffer)); Dart_SetReturnValue(args, DartUtils::NewString(str)); if (str != reinterpret_cast(buffer)) free(str); Dart_ExitScope(); } void FUNCTION_NAME(StringToSystemEncoding)(Dart_NativeArguments args) { Dart_EnterScope(); Dart_Handle str = Dart_GetNativeArgument(args, 0); const char* utf8 = DartUtils::GetStringValue(str); const char* system_string = StringUtils::Utf8ToConsoleString(utf8); int external_length = strlen(system_string); uint8_t* buffer = NULL; Dart_Handle external_array = IOBuffer::Allocate(external_length, &buffer); memmove(buffer, system_string, external_length); if (utf8 != system_string) free(const_cast(system_string)); Dart_SetReturnValue(args, external_array); Dart_ExitScope(); }