SQLClient.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
  3. * Copyright (c) 2022, the SerenityOS developers.
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include <AK/DeprecatedString.h>
  8. #include <AK/String.h>
  9. #include <LibSQL/SQLClient.h>
  10. #if !defined(AK_OS_SERENITY)
  11. # include <LibCore/DeprecatedFile.h>
  12. # include <LibCore/Directory.h>
  13. # include <LibCore/SocketAddress.h>
  14. # include <LibCore/StandardPaths.h>
  15. # include <LibCore/System.h>
  16. #endif
  17. namespace SQL {
  18. #if !defined(AK_OS_SERENITY)
  19. // This is heavily based on how SystemServer's Service creates its socket.
  20. static ErrorOr<int> create_database_socket(DeprecatedString const& socket_path)
  21. {
  22. if (Core::DeprecatedFile::exists(socket_path))
  23. TRY(Core::System::unlink(socket_path));
  24. # ifdef SOCK_NONBLOCK
  25. auto socket_fd = TRY(Core::System::socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
  26. # else
  27. auto socket_fd = TRY(Core::System::socket(AF_LOCAL, SOCK_STREAM, 0));
  28. int option = 1;
  29. TRY(Core::System::ioctl(socket_fd, FIONBIO, &option));
  30. TRY(Core::System::fcntl(socket_fd, F_SETFD, FD_CLOEXEC));
  31. # endif
  32. # if !defined(AK_OS_BSD_GENERIC)
  33. TRY(Core::System::fchmod(socket_fd, 0600));
  34. # endif
  35. auto socket_address = Core::SocketAddress::local(socket_path);
  36. auto socket_address_un = socket_address.to_sockaddr_un().release_value();
  37. TRY(Core::System::bind(socket_fd, reinterpret_cast<sockaddr*>(&socket_address_un), sizeof(socket_address_un)));
  38. TRY(Core::System::listen(socket_fd, 16));
  39. return socket_fd;
  40. }
  41. static ErrorOr<void> launch_server(DeprecatedString const& socket_path, DeprecatedString const& pid_path, Vector<String> candidate_server_paths)
  42. {
  43. auto server_fd_or_error = create_database_socket(socket_path);
  44. if (server_fd_or_error.is_error()) {
  45. warnln("Failed to create a database socket at {}: {}", socket_path, server_fd_or_error.error());
  46. return server_fd_or_error.release_error();
  47. }
  48. auto server_fd = server_fd_or_error.value();
  49. auto server_pid = TRY(Core::System::fork());
  50. if (server_pid == 0) {
  51. TRY(Core::System::setsid());
  52. TRY(Core::System::signal(SIGCHLD, SIG_IGN));
  53. server_pid = TRY(Core::System::fork());
  54. if (server_pid != 0) {
  55. auto server_pid_file = TRY(Core::File::open(pid_path, Core::File::OpenMode::Write));
  56. TRY(server_pid_file->write(DeprecatedString::number(server_pid).bytes()));
  57. TRY(Core::System::kill(getpid(), SIGTERM));
  58. }
  59. server_fd = TRY(Core::System::dup(server_fd));
  60. auto takeover_string = DeprecatedString::formatted("SQLServer:{}", server_fd);
  61. TRY(Core::System::setenv("SOCKET_TAKEOVER"sv, takeover_string, true));
  62. ErrorOr<void> result;
  63. for (auto const& server_path : candidate_server_paths) {
  64. auto arguments = Array {
  65. server_path.bytes_as_string_view(),
  66. "--pid-file"sv,
  67. pid_path,
  68. };
  69. result = Core::System::exec(arguments[0], arguments, Core::System::SearchInPath::Yes);
  70. if (!result.is_error())
  71. break;
  72. }
  73. if (result.is_error()) {
  74. warnln("Could not launch any of {}: {}", candidate_server_paths, result.error());
  75. TRY(Core::System::unlink(pid_path));
  76. }
  77. VERIFY_NOT_REACHED();
  78. }
  79. TRY(Core::System::waitpid(server_pid));
  80. return {};
  81. }
  82. static ErrorOr<bool> should_launch_server(DeprecatedString const& pid_path)
  83. {
  84. if (!Core::DeprecatedFile::exists(pid_path))
  85. return true;
  86. Optional<pid_t> pid;
  87. {
  88. auto server_pid_file = Core::File::open(pid_path, Core::File::OpenMode::Read);
  89. if (server_pid_file.is_error()) {
  90. warnln("Could not open SQLServer PID file '{}': {}", pid_path, server_pid_file.error());
  91. return server_pid_file.release_error();
  92. }
  93. auto contents = server_pid_file.value()->read_until_eof();
  94. if (contents.is_error()) {
  95. warnln("Could not read SQLServer PID file '{}': {}", pid_path, contents.error());
  96. return contents.release_error();
  97. }
  98. pid = StringView { contents.value() }.to_int<pid_t>();
  99. }
  100. if (!pid.has_value()) {
  101. warnln("SQLServer PID file '{}' exists, but with an invalid PID", pid_path);
  102. TRY(Core::System::unlink(pid_path));
  103. return true;
  104. }
  105. if (kill(*pid, 0) < 0) {
  106. warnln("SQLServer PID file '{}' exists with PID {}, but process cannot be found", pid_path, *pid);
  107. TRY(Core::System::unlink(pid_path));
  108. return true;
  109. }
  110. return false;
  111. }
  112. ErrorOr<NonnullRefPtr<SQLClient>> SQLClient::launch_server_and_create_client(Vector<String> candidate_server_paths)
  113. {
  114. auto runtime_directory = TRY(Core::StandardPaths::runtime_directory());
  115. auto socket_path = DeprecatedString::formatted("{}/SQLServer.socket", runtime_directory);
  116. auto pid_path = DeprecatedString::formatted("{}/SQLServer.pid", runtime_directory);
  117. if (TRY(should_launch_server(pid_path)))
  118. TRY(launch_server(socket_path, pid_path, move(candidate_server_paths)));
  119. auto socket = TRY(Core::LocalSocket::connect(move(socket_path)));
  120. TRY(socket->set_blocking(true));
  121. return adopt_nonnull_ref_or_enomem(new (nothrow) SQLClient(move(socket)));
  122. }
  123. #endif
  124. void SQLClient::execution_success(u64 statement_id, u64 execution_id, Vector<DeprecatedString> const& column_names, bool has_results, size_t created, size_t updated, size_t deleted)
  125. {
  126. if (!on_execution_success) {
  127. outln("{} row(s) created, {} updated, {} deleted", created, updated, deleted);
  128. return;
  129. }
  130. ExecutionSuccess success {
  131. .statement_id = statement_id,
  132. .execution_id = execution_id,
  133. .column_names = move(const_cast<Vector<DeprecatedString>&>(column_names)),
  134. .has_results = has_results,
  135. .rows_created = created,
  136. .rows_updated = updated,
  137. .rows_deleted = deleted,
  138. };
  139. on_execution_success(move(success));
  140. }
  141. void SQLClient::execution_error(u64 statement_id, u64 execution_id, SQLErrorCode const& code, DeprecatedString const& message)
  142. {
  143. if (!on_execution_error) {
  144. warnln("Execution error for statement_id {}: {} ({})", statement_id, message, to_underlying(code));
  145. return;
  146. }
  147. ExecutionError error {
  148. .statement_id = statement_id,
  149. .execution_id = execution_id,
  150. .error_code = code,
  151. .error_message = move(const_cast<DeprecatedString&>(message)),
  152. };
  153. on_execution_error(move(error));
  154. }
  155. void SQLClient::next_result(u64 statement_id, u64 execution_id, Vector<Value> const& row)
  156. {
  157. if (!on_next_result) {
  158. StringBuilder builder;
  159. builder.join(", "sv, row, "\"{}\""sv);
  160. outln("{}", builder.string_view());
  161. return;
  162. }
  163. ExecutionResult result {
  164. .statement_id = statement_id,
  165. .execution_id = execution_id,
  166. .values = move(const_cast<Vector<Value>&>(row)),
  167. };
  168. on_next_result(move(result));
  169. }
  170. void SQLClient::results_exhausted(u64 statement_id, u64 execution_id, size_t total_rows)
  171. {
  172. if (!on_results_exhausted) {
  173. outln("{} total row(s)", total_rows);
  174. return;
  175. }
  176. ExecutionComplete success {
  177. .statement_id = statement_id,
  178. .execution_id = execution_id,
  179. .total_rows = total_rows,
  180. };
  181. on_results_exhausted(move(success));
  182. }
  183. }