Service.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. #include "Service.h"
  2. #include <AK/HashMap.h>
  3. #include <AK/JsonArray.h>
  4. #include <AK/JsonObject.h>
  5. #include <LibCore/CConfigFile.h>
  6. #include <LibCore/CLocalSocket.h>
  7. #include <fcntl.h>
  8. #include <libgen.h>
  9. #include <pwd.h>
  10. #include <sched.h>
  11. #include <stdio.h>
  12. #include <sys/stat.h>
  13. #include <unistd.h>
  14. struct UidAndGid {
  15. uid_t uid;
  16. gid_t gid;
  17. };
  18. static HashMap<String, UidAndGid>* s_user_map;
  19. static HashMap<pid_t, Service*> s_service_map;
  20. void Service::resolve_user()
  21. {
  22. if (s_user_map == nullptr) {
  23. s_user_map = new HashMap<String, UidAndGid>;
  24. for (struct passwd* passwd = getpwent(); passwd; passwd = getpwent())
  25. s_user_map->set(passwd->pw_name, { passwd->pw_uid, passwd->pw_gid });
  26. endpwent();
  27. }
  28. auto user = s_user_map->get(m_user);
  29. if (!user.has_value()) {
  30. dbg() << "Failed to resolve user name " << m_user;
  31. ASSERT_NOT_REACHED();
  32. }
  33. m_uid = user.value().uid;
  34. m_gid = user.value().gid;
  35. }
  36. Service* Service::find_by_pid(pid_t pid)
  37. {
  38. auto it = s_service_map.find(pid);
  39. if (it == s_service_map.end())
  40. return nullptr;
  41. return (*it).value;
  42. }
  43. static int ensure_parent_directories(const char* path)
  44. {
  45. ASSERT(path[0] == '/');
  46. char* parent_buffer = strdup(path);
  47. const char* parent = dirname(parent_buffer);
  48. int rc = 0;
  49. while (true) {
  50. int rc = mkdir(parent, 0755);
  51. if (rc == 0)
  52. break;
  53. if (errno != ENOENT)
  54. break;
  55. ensure_parent_directories(parent);
  56. };
  57. free(parent_buffer);
  58. return rc;
  59. }
  60. void Service::setup_socket()
  61. {
  62. ASSERT(!m_socket_path.is_null());
  63. ASSERT(m_socket_fd == -1);
  64. ensure_parent_directories(m_socket_path.characters());
  65. // Note: we use SOCK_CLOEXEC here to make sure we don't leak every socket to
  66. // all the clients. We'll make the one we do need to pass down !CLOEXEC later
  67. // after forking off the process.
  68. m_socket_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
  69. if (m_socket_fd < 0) {
  70. perror("socket");
  71. ASSERT_NOT_REACHED();
  72. }
  73. auto socket_address = CSocketAddress::local(m_socket_path);
  74. auto un = socket_address.to_sockaddr_un();
  75. int rc = bind(m_socket_fd, (const sockaddr*)&un, sizeof(un));
  76. if (rc < 0) {
  77. perror("bind");
  78. ASSERT_NOT_REACHED();
  79. }
  80. rc = listen(m_socket_fd, 5);
  81. if (rc < 0) {
  82. perror("listen");
  83. ASSERT_NOT_REACHED();
  84. }
  85. }
  86. void Service::setup_notifier()
  87. {
  88. ASSERT(m_lazy);
  89. ASSERT(m_socket_fd >= 0);
  90. ASSERT(!m_socket_notifier);
  91. m_socket_notifier = CNotifier::construct(m_socket_fd, CNotifier::Event::Read, this);
  92. m_socket_notifier->on_ready_to_read = [this] {
  93. dbg() << "Ready to read on behalf of " << name();
  94. remove_child(*m_socket_notifier);
  95. m_socket_notifier = nullptr;
  96. spawn();
  97. };
  98. }
  99. void Service::activate()
  100. {
  101. ASSERT(m_pid < 0);
  102. if (m_lazy)
  103. setup_notifier();
  104. else
  105. spawn();
  106. }
  107. void Service::spawn()
  108. {
  109. dbg() << "Spawning " << name();
  110. m_pid = fork();
  111. if (m_pid < 0) {
  112. perror("fork");
  113. ASSERT_NOT_REACHED();
  114. } else if (m_pid == 0) {
  115. // We are the child.
  116. struct sched_param p;
  117. p.sched_priority = m_priority;
  118. int rc = sched_setparam(0, &p);
  119. if (rc < 0) {
  120. perror("sched_setparam");
  121. ASSERT_NOT_REACHED();
  122. }
  123. if (!m_stdio_file_path.is_null()) {
  124. close(0);
  125. int fd = open_with_path_length(m_stdio_file_path.characters(), m_stdio_file_path.length(), O_RDWR, 0);
  126. ASSERT(fd <= 0);
  127. if (fd < 0) {
  128. perror("open");
  129. ASSERT_NOT_REACHED();
  130. }
  131. dup2(0, 1);
  132. dup2(0, 2);
  133. }
  134. if (!m_socket_path.is_null()) {
  135. ASSERT(m_socket_fd > 2);
  136. dup2(m_socket_fd, 3);
  137. // The new descriptor is !CLOEXEC here.
  138. // This is true even if m_socket_fd == 3.
  139. setenv("SOCKET_TAKEOVER", "1", true);
  140. }
  141. if (!m_user.is_null()) {
  142. setuid(m_uid);
  143. setgid(m_gid);
  144. }
  145. char* argv[m_extra_arguments.size() + 2];
  146. argv[0] = const_cast<char*>(m_executable_path.characters());
  147. for (int i = 0; i < m_extra_arguments.size(); i++)
  148. argv[i + 1] = const_cast<char*>(m_extra_arguments[i].characters());
  149. argv[m_extra_arguments.size() + 1] = nullptr;
  150. rc = execv(argv[0], argv);
  151. perror("exec");
  152. ASSERT_NOT_REACHED();
  153. } else {
  154. // We are the parent.
  155. s_service_map.set(m_pid, this);
  156. }
  157. }
  158. void Service::did_exit(int exit_code)
  159. {
  160. ASSERT(m_pid > 0);
  161. (void)exit_code;
  162. dbg() << "Service " << name() << " has exited";
  163. s_service_map.remove(m_pid);
  164. m_pid = -1;
  165. if (m_keep_alive)
  166. activate();
  167. }
  168. Service::Service(const CConfigFile& config, const StringView& name)
  169. : CObject(nullptr)
  170. {
  171. ASSERT(config.has_group(name));
  172. set_name(name);
  173. m_executable_path = config.read_entry(name, "Executable", String::format("/bin/%s", this->name().characters()));
  174. m_extra_arguments = config.read_entry(name, "Arguments", "").split(' ');
  175. m_stdio_file_path = config.read_entry(name, "StdIO");
  176. String prio = config.read_entry(name, "Priority");
  177. if (prio == "low")
  178. m_priority = 10;
  179. else if (prio == "normal" || prio.is_null())
  180. m_priority = 30;
  181. else if (prio == "high")
  182. m_priority = 50;
  183. else
  184. ASSERT_NOT_REACHED();
  185. m_keep_alive = config.read_bool_entry(name, "KeepAlive");
  186. m_lazy = config.read_bool_entry(name, "Lazy");
  187. m_socket_path = config.read_entry(name, "Socket");
  188. if (!m_socket_path.is_null()) {
  189. setup_socket();
  190. }
  191. m_user = config.read_entry(name, "User");
  192. if (!m_user.is_null())
  193. resolve_user();
  194. }
  195. void Service::save_to(JsonObject& json)
  196. {
  197. CObject::save_to(json);
  198. json.set("executable_path", m_executable_path);
  199. // FIXME: This crashes Inspector.
  200. /*
  201. JsonArray extra_args;
  202. for (String& arg : m_extra_arguments)
  203. extra_args.append(arg);
  204. json.set("extra_arguments", move(extra_args));
  205. */
  206. json.set("stdio_file_path", m_stdio_file_path);
  207. json.set("priority", m_priority);
  208. json.set("keep_alive", m_keep_alive);
  209. json.set("socket_path", m_socket_path);
  210. json.set("lazy", m_lazy);
  211. json.set("user", m_user);
  212. json.set("uid", m_uid);
  213. json.set("gid", m_gid);
  214. if (m_pid > 0)
  215. json.set("pid", m_pid);
  216. else
  217. json.set("pid", nullptr);
  218. }