DeviceEventLoop.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. /*
  2. * Copyright (c) 2023, Liav A. <liavalb@hotmail.co.il>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "DeviceEventLoop.h"
  7. #include <AK/Debug.h>
  8. #include <LibCore/DirIterator.h>
  9. #include <LibCore/System.h>
  10. #include <LibIPC/MultiServer.h>
  11. #include <fcntl.h>
  12. #include <stdio.h>
  13. #include <unistd.h>
  14. namespace DeviceMapper {
  15. DeviceEventLoop::DeviceEventLoop(NonnullOwnPtr<Core::File> devctl_file)
  16. : m_devctl_file(move(devctl_file))
  17. {
  18. }
  19. using MinorNumberAllocationType = DeviceEventLoop::MinorNumberAllocationType;
  20. static constexpr DeviceEventLoop::DeviceNodeMatch s_matchers[] = {
  21. { "audio"sv, "audio"sv, "audio/%digit"sv, DeviceNodeFamily::Type::CharacterDevice, 116, MinorNumberAllocationType::SequentialUnlimited, 0, 0, 0220 },
  22. { {}, "render"sv, "gpu/render%digit"sv, DeviceNodeFamily::Type::CharacterDevice, 28, MinorNumberAllocationType::SequentialUnlimited, 0, 0, 0666 },
  23. { "window"sv, "gpu-connector"sv, "gpu/connector%digit"sv, DeviceNodeFamily::Type::CharacterDevice, 226, MinorNumberAllocationType::SequentialUnlimited, 0, 0, 0660 },
  24. { {}, "virtio-console"sv, "hvc0p%digit"sv, DeviceNodeFamily::Type::CharacterDevice, 229, MinorNumberAllocationType::SequentialUnlimited, 0, 0, 0666 },
  25. { "phys"sv, "hid-mouse"sv, "input/mouse/%digit"sv, DeviceNodeFamily::Type::CharacterDevice, 10, MinorNumberAllocationType::SequentialUnlimited, 0, 0, 0666 },
  26. { "phys"sv, "hid-keyboard"sv, "input/keyboard/%digit"sv, DeviceNodeFamily::Type::CharacterDevice, 85, MinorNumberAllocationType::SequentialUnlimited, 0, 0, 0666 },
  27. { {}, "storage"sv, "hd%letter"sv, DeviceNodeFamily::Type::BlockDevice, 3, MinorNumberAllocationType::SequentialUnlimited, 0, 0, 0600 },
  28. { "tty"sv, "console"sv, "tty%digit"sv, DeviceNodeFamily::Type::CharacterDevice, 4, MinorNumberAllocationType::SequentialLimited, 0, 63, 0620 },
  29. { "tty"sv, "console"sv, "ttyS%digit"sv, DeviceNodeFamily::Type::CharacterDevice, 4, MinorNumberAllocationType::SequentialLimited, 64, 127, 0620 },
  30. };
  31. static bool is_in_minor_number_range(DeviceEventLoop::DeviceNodeMatch const& matcher, MinorNumber minor_number)
  32. {
  33. if (matcher.minor_number_allocation_type == MinorNumberAllocationType::SequentialUnlimited)
  34. return true;
  35. return matcher.minor_number_start <= minor_number && static_cast<MinorNumber>(matcher.minor_number_start.value() + matcher.minor_number_range_size) >= minor_number;
  36. }
  37. static Optional<DeviceEventLoop::DeviceNodeMatch const&> device_node_family_to_match_type(DeviceNodeFamily::Type unix_device_type, MajorNumber major_number, MinorNumber minor_number)
  38. {
  39. for (auto& matcher : s_matchers) {
  40. if (matcher.major_number == major_number
  41. && unix_device_type == matcher.unix_device_type
  42. && is_in_minor_number_range(matcher, minor_number))
  43. return matcher;
  44. }
  45. return {};
  46. }
  47. static bool is_in_family_minor_number_range(DeviceNodeFamily const& family, MinorNumber minor_number)
  48. {
  49. return family.base_minor_number() <= minor_number && static_cast<MinorNumber>(family.base_minor_number().value() + family.devices_symbol_suffix_allocation_map().size()) >= minor_number;
  50. }
  51. Optional<DeviceNodeFamily&> DeviceEventLoop::find_device_node_family(DeviceNodeFamily::Type unix_device_type, MajorNumber major_number, MinorNumber minor_number) const
  52. {
  53. for (auto const& family : m_device_node_families) {
  54. if (family->major_number() == major_number && family->type() == unix_device_type && is_in_family_minor_number_range(*family, minor_number))
  55. return *family.ptr();
  56. }
  57. return {};
  58. }
  59. ErrorOr<NonnullRefPtr<DeviceNodeFamily>> DeviceEventLoop::find_or_register_new_device_node_family(DeviceNodeMatch const& match, DeviceNodeFamily::Type unix_device_type, MajorNumber major_number, MinorNumber minor_number)
  60. {
  61. if (auto possible_family = find_device_node_family(unix_device_type, major_number, minor_number); possible_family.has_value())
  62. return possible_family.release_value();
  63. unsigned allocation_map_size = 1024;
  64. if (match.minor_number_allocation_type == MinorNumberAllocationType::SequentialLimited)
  65. allocation_map_size = match.minor_number_range_size;
  66. auto bitmap = TRY(Bitmap::create(allocation_map_size, false));
  67. auto node = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) DeviceNodeFamily(move(bitmap),
  68. match.family_type_literal,
  69. unix_device_type,
  70. major_number,
  71. minor_number)));
  72. TRY(m_device_node_families.try_append(node));
  73. return node;
  74. }
  75. static ErrorOr<String> build_suffix_with_letters(size_t allocation_index)
  76. {
  77. String base_string {};
  78. while (true) {
  79. base_string = TRY(String::formatted("{:c}{}", 'a' + (allocation_index % 26), base_string));
  80. allocation_index = (allocation_index / 26);
  81. if (allocation_index == 0)
  82. break;
  83. allocation_index = allocation_index - 1;
  84. }
  85. return base_string;
  86. }
  87. static ErrorOr<String> build_suffix_with_numbers(size_t allocation_index)
  88. {
  89. return String::number(allocation_index);
  90. }
  91. static ErrorOr<void> prepare_permissions_after_populating_devtmpfs(StringView path, DeviceEventLoop::DeviceNodeMatch const& match)
  92. {
  93. if (match.permission_group.is_null())
  94. return {};
  95. auto group = TRY(Core::System::getgrnam(match.permission_group));
  96. VERIFY(group.has_value());
  97. TRY(Core::System::endgrent());
  98. TRY(Core::System::chown(path, 0, group.value().gr_gid));
  99. return {};
  100. }
  101. ErrorOr<void> DeviceEventLoop::register_new_device(DeviceNodeFamily::Type unix_device_type, MajorNumber major_number, MinorNumber minor_number)
  102. {
  103. auto possible_match = device_node_family_to_match_type(unix_device_type, major_number, minor_number);
  104. if (!possible_match.has_value())
  105. return {};
  106. auto const& match = possible_match.release_value();
  107. auto device_node_family = TRY(find_or_register_new_device_node_family(match, unix_device_type, major_number, minor_number));
  108. static constexpr StringView devtmpfs_base_path = "/dev/"sv;
  109. auto path_pattern = TRY(String::from_utf8(match.path_pattern));
  110. auto& allocation_map = device_node_family->devices_symbol_suffix_allocation_map();
  111. auto possible_allocated_suffix_index = allocation_map.find_first_unset();
  112. if (!possible_allocated_suffix_index.has_value()) {
  113. // FIXME: Make the allocation map bigger?
  114. return Error::from_errno(ERANGE);
  115. }
  116. auto allocated_suffix_index = possible_allocated_suffix_index.release_value();
  117. auto path = path_pattern;
  118. if (match.path_pattern.contains("%digit"sv)) {
  119. auto replacement = TRY(build_suffix_with_numbers(allocated_suffix_index));
  120. path = TRY(path.replace("%digit"sv, replacement, ReplaceMode::All));
  121. }
  122. if (match.path_pattern.contains("%letter"sv)) {
  123. auto replacement = TRY(build_suffix_with_letters(allocated_suffix_index));
  124. path = TRY(path.replace("%letter"sv, replacement, ReplaceMode::All));
  125. }
  126. VERIFY(!path.is_empty());
  127. path = TRY(String::formatted("{}{}", devtmpfs_base_path, path));
  128. mode_t old_mask = umask(0);
  129. if (unix_device_type == DeviceNodeFamily::Type::BlockDevice)
  130. TRY(Core::System::create_block_device(path.bytes_as_string_view(), match.create_mode, major_number.value(), minor_number.value()));
  131. else
  132. TRY(Core::System::create_char_device(path.bytes_as_string_view(), match.create_mode, major_number.value(), minor_number.value()));
  133. umask(old_mask);
  134. TRY(prepare_permissions_after_populating_devtmpfs(path.bytes_as_string_view(), match));
  135. auto result = TRY(device_node_family->registered_nodes().try_set(RegisteredDeviceNode { move(path), minor_number }, AK::HashSetExistingEntryBehavior::Keep));
  136. VERIFY(result != HashSetResult::ReplacedExistingEntry);
  137. if (result == HashSetResult::KeptExistingEntry) {
  138. // FIXME: Handle this case properly.
  139. return Error::from_errno(EEXIST);
  140. }
  141. allocation_map.set(allocated_suffix_index, true);
  142. return {};
  143. }
  144. ErrorOr<void> DeviceEventLoop::unregister_device(DeviceNodeFamily::Type unix_device_type, MajorNumber major_number, MinorNumber minor_number)
  145. {
  146. if (!device_node_family_to_match_type(unix_device_type, major_number, minor_number).has_value())
  147. return {};
  148. auto possible_family = find_device_node_family(unix_device_type, major_number, minor_number);
  149. if (!possible_family.has_value()) {
  150. // FIXME: Handle cases where we can't remove a device node.
  151. // This could happen when the DeviceMapper program was restarted
  152. // so the previous state was not preserved and a device was removed.
  153. return Error::from_errno(ENODEV);
  154. }
  155. auto& family = possible_family.release_value();
  156. for (auto& node : family.registered_nodes()) {
  157. if (node.minor_number() == minor_number)
  158. TRY(Core::System::unlink(node.device_path()));
  159. }
  160. auto removed_anything = family.registered_nodes().remove_all_matching([minor_number](auto& device) { return device.minor_number() == minor_number; });
  161. if (!removed_anything) {
  162. // FIXME: Handle cases where we can't remove a device node.
  163. // This could happen when the DeviceMapper program was restarted
  164. // so the previous state was not preserved and a device was removed.
  165. return Error::from_errno(ENODEV);
  166. }
  167. return {};
  168. }
  169. struct PluggableOnceCharacterDeviceNodeMatch {
  170. StringView path;
  171. mode_t mode;
  172. MajorNumber major;
  173. MinorNumber minor;
  174. };
  175. static constexpr PluggableOnceCharacterDeviceNodeMatch s_simple_matchers[] = {
  176. { "/dev/beep"sv, 0666, 1, 10 },
  177. { "/dev/kcov"sv, 0666, 30, 0 },
  178. };
  179. static ErrorOr<void> create_pluggable_once_char_device_node(PluggableOnceCharacterDeviceNodeMatch const& match)
  180. {
  181. mode_t old_mask = umask(0);
  182. ScopeGuard umask_guard([old_mask] { umask(old_mask); });
  183. TRY(Core::System::create_char_device(match.path, match.mode, match.major.value(), match.minor.value()));
  184. return {};
  185. }
  186. ErrorOr<void> DeviceEventLoop::read_one_or_eof(DeviceEvent& event)
  187. {
  188. if (m_devctl_file->read_until_filled({ bit_cast<u8*>(&event), sizeof(DeviceEvent) }).is_error()) {
  189. // Bad! Kernel and SystemServer apparently disagree on the record size,
  190. // which means that previous data is likely to be invalid.
  191. return Error::from_string_view("File ended after incomplete record? /dev/devctl seems broken!"sv);
  192. }
  193. return {};
  194. }
  195. ErrorOr<void> DeviceEventLoop::drain_events_from_devctl()
  196. {
  197. for (;;) {
  198. DeviceEvent event;
  199. TRY(read_one_or_eof(event));
  200. // NOTE: Ignore any event related to /dev/devctl device node - normally
  201. // it should never disappear from the system and we already use it in this
  202. // code.
  203. if (event.major_number == 2 && event.minor_number == 10 && !event.is_block_device)
  204. continue;
  205. if (event.state == DeviceEvent::State::Inserted) {
  206. if (!event.is_block_device) {
  207. // NOTE: We have a special handling for the pluggable-once devices, etc,
  208. // as these device (if they appear) should only "hotplug" (being inserted)
  209. // once during the OS runtime.
  210. // Therefore, we don't want to create a new MinorNumberAllocationType (e.g. SingleInstance).
  211. // Instead, just blindly create such device node and assume we will never
  212. // have to worry about it, so we don't need to register that!
  213. auto possible_pluggable_once_char_device_match = ([](DeviceEvent& event) -> Optional<PluggableOnceCharacterDeviceNodeMatch const&> {
  214. for (auto const& match : s_simple_matchers) {
  215. if (event.major_number == match.major.value() && event.minor_number == match.minor.value())
  216. return match;
  217. }
  218. return Optional<PluggableOnceCharacterDeviceNodeMatch const&> {};
  219. })(event);
  220. if (possible_pluggable_once_char_device_match.has_value()) {
  221. TRY(create_pluggable_once_char_device_node(possible_pluggable_once_char_device_match.value()));
  222. continue;
  223. }
  224. }
  225. VERIFY(event.is_block_device == 1 || event.is_block_device == 0);
  226. TRY(register_new_device(event.is_block_device ? DeviceNodeFamily::Type::BlockDevice : DeviceNodeFamily::Type::CharacterDevice, event.major_number, event.minor_number));
  227. } else if (event.state == DeviceEvent::State::Removed) {
  228. if (event.major_number == 30 && event.minor_number == 0 && !event.is_block_device) {
  229. dbgln("DeviceMapper: unregistering device failed: kcov tried to de-register itself!?");
  230. continue;
  231. }
  232. if (auto error_or_void = unregister_device(event.is_block_device ? DeviceNodeFamily::Type::BlockDevice : DeviceNodeFamily::Type::CharacterDevice, event.major_number, event.minor_number); error_or_void.is_error())
  233. dbgln("DeviceMapper: unregistering device failed: {}", error_or_void.error());
  234. } else {
  235. dbgln("DeviceMapper: Unhandled device event ({:x})!", event.state);
  236. }
  237. }
  238. VERIFY_NOT_REACHED();
  239. }
  240. }