81 using Device_factory_type = FACTORY;
82 using Client_type =
typename Device_factory_type::Client_type;
83 using Device_type =
typename Device_factory_type::Device_type;
84 using Scheduler_type = SCHEDULER;
86 using Ds_vector = std::vector<L4::Cap<L4Re::Dataspace>>;
88 using Pairing_callback = std::function<void(Device_type *)>;
96 std::string device_id;
104 bool enable_trusted_ds_validation;
106 std::shared_ptr<Ds_vector const> trusted_dataspaces;
109 Pairing_callback pairing_cb;
111 Pending_client() =
default;
114 bool ro,
bool enable_trusted_ds_validation,
115 std::shared_ptr<Ds_vector const> trusted_dataspaces,
117 : device_id(dev), gate(g), num_ds(ds), readonly(ro),
118 enable_trusted_ds_validation(enable_trusted_ds_validation),
119 trusted_dataspaces(trusted_dataspaces), pairing_cb(cb)
127 : _shutdown_state(Shutdown_type::Running),
128 _device(cxx::move(dev)),
133 {
return _interface ? _interface->obj_cap() :
L4::Cap<void>(); }
135 void start_disk_scan(Errand::Callback
const &callback)
137 _device->start_device_scan(
140 scan_disk_partitions(callback, 0);
149 for (
auto *sub : _subs)
150 sub->unregister_interfaces(registry);
155 if (_shutdown_state != Shutdown_type::Running)
164 for (
auto *sub : _subs)
169 int ret = sub->create_interface_for(c, registry);
175 if (!match_hid(c->device_id))
181 auto clt = Device_factory_type::create_client(_device, c->num_ds,
184 clt->add_trusted_dataspaces(c->trusted_dataspaces);
185 if (c->enable_trusted_ds_validation)
186 clt->enable_trusted_ds_validation();
188 if (c->gate.is_valid())
190 if (!clt->register_obj(registry, c->gate).is_valid())
195 c->gate = L4::cap_reinterpret_cast<L4::Rcv_endpoint>(
196 clt->register_obj(registry));
197 if (!c->gate.is_valid())
201 _mgr->_scheduler->add_client(clt.get());
202 _interface.reset(clt.release());
206 c->pairing_cb(_device.get());
214 if (_interface->obj_cap() && !_interface->obj_cap().validate().label())
215 remove_client(registry);
221 for (
auto *sub : _subs)
222 sub->check_clients(registry);
226 void shutdown_event(Shutdown_type type)
229 _shutdown_state = type;
230 for (
auto const &sub: _subs)
231 sub->shutdown_event(type);
233 _interface->shutdown_event(type);
248 template <
typename T = Device_factory_type>
249 auto scan_disk_partitions(Errand::Callback
const &callback,
int)
252 auto reader = cxx::make_ref_obj<Partition_reader<Device_type>>(_device.get());
264 if (reader->get_partition(i, &info) < 0)
267 auto conn = cxx::make_ref_obj<Connection>(
269 Device_factory_type::create_partition(_device, i, info));
270 _subs.push_front(std::move(conn));
278 Errand::schedule([reader](){}, 0);
289 template <
typename T = Device_factory_type>
290 void scan_disk_partitions(Errand::Callback
const &callback,
long)
301 _interface->shutdown_event(Shutdown_type::Client_gone);
303 if (_interface->busy())
305 Dbg::trace().printf(
"Deferring dead client removal.\n");
312 Errand::schedule([
this, registry]() { remove_client(registry); },
317 _interface->unregister_obj(registry);
318 _mgr->_scheduler->remove_client(_interface.get());
322 bool contains_device(std::string
const &name)
const
327 for (
auto *sub : _subs)
328 if (sub->contains_device(name))
334 bool match_hid(std::string
const &name)
const
335 {
return _device->match_hid(
cxx::String(name.c_str(), name.length())); }
339 Shutdown_type _shutdown_state;
343 cxx::unique_ptr<Client_type> _interface;
352 : _registry(registry)
354 _scheduler = cxx::make_unique<Scheduler_type>(registry);
359 for (
auto *c : _connpts)
360 c->unregister_interfaces(_registry);
385 std::string
const partlabel(
"partlabel:");
386 std::string
const partuuid(
"partuuid:");
388 if (param.size() > partlabel.size()
389 && param.compare(0, partlabel.size(), partlabel) == 0)
391 device = param.substr(partlabel.size());
394 else if (param.size() > partuuid.size()
395 && param.compare(0, partuuid.size(), partuuid) == 0)
397 auto device_partuuid = param.substr(partuuid.size());
398 if (!is_uuid(device_partuuid.c_str()))
400 Dbg::trace().printf(
"The 'partuuid:' parameter expects a UUID.\n");
404 device = device_partuuid;
405 std::transform(device.begin(), device.end(), device.begin(),
406 [](
unsigned char c){ return std::toupper(c); });
412 if (is_uuid(param.c_str()))
413 std::transform(device.begin(), device.end(), device.begin(),
414 [](
unsigned char c) { return std::toupper(c); });
420 int partno,
int num_ds,
bool readonly =
false,
421 Pairing_callback cb =
nullptr,
422 bool enable_trusted_ds_validation =
false,
423 std::shared_ptr<Ds_vector const> trusted_dataspaces
431 Err().printf(
"Invalid partition number 0.\n");
439 snprintf(_buf,
sizeof(_buf),
"%s:%d", device, partno);
445 _pending_clients.emplace_back(client, buf, num_ds, readonly,
446 enable_trusted_ds_validation,
447 trusted_dataspaces, cb);
452 int create_dynamic_client(std::string
const &device,
int partno,
int num_ds,
454 Pairing_callback cb =
nullptr,
455 bool enable_trusted_ds_validation =
false,
456 std::shared_ptr<Ds_vector const> trusted_dataspaces
464 clt.readonly = readonly;
466 clt.device_id = device;
470 clt.trusted_dataspaces = trusted_dataspaces;
472 clt.enable_trusted_ds_validation = enable_trusted_ds_validation;
476 clt.device_id +=
':';
477 clt.device_id += std::to_string(partno);
480 for (
auto *c : _connpts)
482 int ret = c->create_interface_for(&clt, _registry);
503 for (
auto *c : _connpts)
504 c->check_clients(_registry);
509 auto conn = cxx::make_ref_obj<Connection>(
this, std::move(device));
511 conn->start_disk_scan(
514 _connpts.push_front(conn);
515 connect_static_clients(conn.get());
526 for (
auto const &con : _connpts)
527 con->shutdown_event(type);
531 void connect_static_clients(Connection *con)
533 for (
auto &c : _pending_clients)
535 Dbg::trace().printf(
"Checking existing client %s\n", c.device_id.c_str());
536 if (!c.gate.is_valid())
539 int ret = con->create_interface_for(&c, _registry);
554 static constexpr bool is_uuid(
char const *s)
556 for (
unsigned i = 0; i < 36; ++i)
557 if (i == 8 || i == 13 || i == 18 || i == 23)
567 return s[36] ==
'\0';
575 std::vector<Pending_client> _pending_clients;
577 cxx::unique_ptr<Scheduler_type> _scheduler;