Skip to content

Commit

Permalink
Update documentation to reflect new features
Browse files Browse the repository at this point in the history
  • Loading branch information
Benjamin Berg authored and martinpitt committed Jun 30, 2021
1 parent 7acc7b7 commit 5e2e428
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 20 deletions.
3 changes: 2 additions & 1 deletion docs/reference/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ version_xml = configure_file(
# HACK: need to find valac'ed umockdev.c for gtk-doc; https://github.com/mesonbuild/meson/issues/3892
# this isn't predictable between meson versions
umockdev_c = run_command('sh', '-ec', 'find -name umockdev.c| xargs dirname').stdout().strip()
umockdev_ioctl_c = run_command('sh', '-ec', 'find -name umockdev-ioctl.c| xargs dirname').stdout().strip()

gnome = import('gnome')
gnome.gtkdoc('umockdev',
main_xml: 'umockdev-docs.xml',
src_dir: [meson.build_root(), umockdev_c],
src_dir: [meson.build_root(), umockdev_c, umockdev_ioctl_c],
content_files: [version_xml],
ignore_headers: ['uevent_sender.h', 'ioctl_tree.h', 'debug.h'],
scan_args: ['--rebuild-types'],
Expand Down
1 change: 1 addition & 0 deletions docs/reference/umockdev-docs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<chapter>
<title>API reference</title>
<xi:include href="xml/umockdev.xml"/>
<xi:include href="xml/umockdev-ioctl.xml"/>
<xi:include href="xml/functions.xml"/>
<xi:include href="xml/umockdeverror.xml"/>

Expand Down
27 changes: 27 additions & 0 deletions docs/reference/umockdev-sections.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ umockdev_testbed_get_property
umockdev_testbed_uevent
umockdev_testbed_add_from_string
umockdev_testbed_add_from_file
umockdev_testbed_attach_ioctl
umockdev_testbed_detach_ioctl
umockdev_testbed_load_ioctl
umockdev_testbed_load_pcap
umockdev_testbed_load_script
umockdev_testbed_load_socket_script
umockdev_testbed_load_evemu_events
Expand All @@ -46,6 +49,30 @@ umockdev_testbed_get_type
umockdev_in_mock_environment
</SECTION>

<SECTION>
<FILE>umockdev-ioctl</FILE>
<TITLE>UMockdev Ioctl emulation</TITLE>
UMockdevIoctlBase
UMockdevIoctlBaseClass
umockdev_ioctl_base_new

UMockdevIoctlData
umockdev_ioctl_data_ref
umockdev_ioctl_data_unref
umockdev_ioctl_data_resolve
umockdev_ioctl_data_set_ptr
umockdev_ioctl_data_reload

UMockdevIoctlClient
umockdev_ioctl_client_complete
umockdev_ioctl_client_abort
umockdev_ioctl_client_execute
umockdev_ioctl_client_get_arg
umockdev_ioctl_client_get_connected
umockdev_ioctl_client_get_devnode
umockdev_ioctl_client_get_request
</SECTION>

<SECTION>
<FILE>umockdeverror</FILE>
UMockdevError
Expand Down
179 changes: 160 additions & 19 deletions src/umockdev-ioctl.vala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

namespace UMockdev {

/**
* SECTION:umockdev-ioctl
* @title: umockdev-ioctl
* @short_description: Emulate ioctl and read/write calls for devices.
*
* These classes permit emulation of ioctl and read/write calls including
* fully customizing the behaviour by creating an #UMockdevIoctlBase instance or
* subclass instance and attaching it using umockdev_testbed_attach_ioctl().
*/

/* The bindings are lacking g_signal_accumulator_true_handled, but easy enough
* to implement here.
*/
Expand All @@ -24,11 +34,14 @@ internal bool signal_accumulator_true_handled(GLib.SignalInvocationHint ihint,
/**
* UMockdevIoctlData:
*
* The #UMockdevIoctlData struct is a container designed to resolve the ioctl
* data parameter. You will be passed an #UMockdevIoctlData container with
* a single pointer initially, which you must immediately resolve using
* umockdev_ioctl_data_resolve() passing 0 as the offset and the expected size
* of the user provided structure.
* The #UMockdevIoctlData struct is a container designed to read and write
* memory from the client process.
*
* After memory has been resolved, the corresponding pointer will point to
* local memory that can be used normally. The memory will automatically be
* synced back by umockdev_ioctl_client_complete().
*
* Since: 0.16
*/
public class IoctlData {
/* Local cache to check if data is dirty before flushing. This is both an
Expand Down Expand Up @@ -149,6 +162,7 @@ public class IoctlData {
* the data.
*
* Returns: #TRUE on success, #FALSE otherwise
* Since: 0.16
*/
public bool reload() throws IOError {
load_data();
Expand Down Expand Up @@ -240,15 +254,53 @@ public class IoctlData {
*
* The #UMockdevIoctlClient struct represents an opened client side FD in order
* to emulate ioctl calls on this device.
*
* Since: 0.16
*/
/**
* UMockdevIoctlClient::handle-ioctl:
* @client: A #UMockdevIoctlClient
*
* Called when an ioctl is requested by the client.
*
* This is the per-client signal. See #UMockdevIoctlBase::handle-ioctl on #UMockdevIoctlBase.
*
* Since: 0.16
*/
/**
* UMockdevIoctlClient::handle-read:
* @client: A #UMockdevIoctlClient
*
* Called when a read is requested by the client.
*
* This is the per-client signal. See #UMockdevIoctlBase::handle-read on #UMockdevIoctlBase.
*
* Since: 0.16
*/
/**
* UMockdevIoctlClient::handle-write:
* @client: A #UMockdevIoctlClient
*
* Called when a write is requested by the client.
*
* This is the per-client signal. See #UMockdevIoctlBase::handle-write on #UMockdevIoctlBase.
*
* Since: 0.16
*/

public class IoctlClient : GLib.Object {
private IoctlBase handler;
private IOStream stream;
private GLib.MainContext _ctx;

[Description(nick = "device node", blurb = "The device node the client opened")]
public string devnode { get; }

[Description(nick = "request", blurb = "The current ioctl request")]
public ulong request { get; }
[Description(nick = "argument", blurb = "The ioctl argument, for read/write the passed buffer")]
public IoctlData arg { get; }
[Description(nick = "connected", blurb = "Whether the client is still connected")]
public bool connected {
get {
return !stream.is_closed();
Expand All @@ -267,19 +319,27 @@ public class IoctlClient : GLib.Object {
}

/**
* umockdev_ioctl_client_execute():
* umockdev_ioctl_client_execute:
* @self: A #UMockdevIoctlClient
* @errno_: Return location for errno
* @error: return location for a GError, or %NULL
*
* This function is not generally useful. It exists for umockdev itself
* in order to implement recording.
*
* Execute the ioctl on the client side. Note that this flushes any
* modifications of the ioctl data. As such, data needs to be re-fetched
* afterwards.
* modifications of the ioctl data. As such, pointers that were already
* resolved (including the initial ioctl argument itself) need to be
* resolved again.
*
* It is only valid to call this while an uncompleted ioctl is being
* It is only valid to call this while an uncompleted command is being
* processed.
*
* This call is thread-safe.
*
* Returns: The client side result of the ioctl call
*
* Since: 0.16
*/
public int execute(out int errno_) throws IOError {
OutputStream output = stream.get_output_stream();
Expand Down Expand Up @@ -309,38 +369,41 @@ public class IoctlClient : GLib.Object {
}

/**
* umockdev_ioctl_invocation_complete():
* @self: A #UmockdevIoctlClient
* @result: Return value of ioctl
* umockdev_ioctl_client_complete:
* @self: A #UMockdevIoctlClient
* @res: Return value of ioctl
* @errno_: errno of ioctl
*
* Asynchronously completes the ioctl invocation of the client. This is
* equivalent to calling umockdev_ioctl_complete() with the invocation.
* equivalent to calling umockdev_ioctl_client_complete() with the
* invocation.
*
* This call is thread-safe.
*
* Since: 0.16
*/
public void complete(long result, int errno_) {
public void complete(long res, int errno_) {
/* Nullify some of the request information */
assert(_cmd != 0);
_cmd = 0;
_request = 0;

this.result = result;
this.result = res;
this.result_errno = errno_;

/* Push us into the correct main context. */
_ctx.invoke(complete_idle);
}

/**
* umockdev_ioctl_invocation_abort():
* @self: A #UmockdevIoctlClient
* @result: Return value of ioctl
* @errno_: errno of ioctl
* umockdev_ioctl_client_abort:
* @self: A #UMockdevIoctlClient
*
* Asynchronously terminates the child by asking it to execute exit(1).
*
* This call is thread-safe.
*
* Since: 0.16
*/
public void abort() {
this._abort = true;
Expand Down Expand Up @@ -521,13 +584,91 @@ public class IoctlClient : GLib.Object {
}
}

/**
* UMockdevIoctlBaseClass:
* @handle_ioctl: Override ioctl emulation
* @handle_read: Override read emulation
* @handle_write: Override write_emulation
* @client_connected: A device was opened
* @client_vanished: A device was closed
*
* The base class for an device ioctl and read/write handling. You can either
* override the corresponding vfuncs or connect to the signals to customize
* the emulation.
*
* Since: 0.16
*/

/**
* UMockdevIoctlBase:
*
* The #UMockdevIoctlBase class is a base class to emulate and record ioctl
* operations of a client. It can be attached to an emulated device in the
* testbed and will then be used.
*
* Since: 0.16
*/
/**
* UMockdevIoctlBase::handle-ioctl:
* @handler: A #UMockdevIoctlBase
* @client: A #UMockdevIoctlClient
*
* Called when an ioctl is requested by the client.
*
* Access the #UMockdevIoctlClient::arg property of @client to retrieve the
* argument of the ioctl. This is a pointer sized buffer initially with the
* original argument passed to the ioctl. If this is pointing to a struct, use
* umockdev_ioctl_data_resolve() to retrieve the underlying memory and update
* the pointer. Resolve any further pointers in the structure in the same way.
*
* After resolving the memory, you can access it as if it was local. The memory
* will be synced back to the client automatically if it has been modified
* locally.
*
* Once processing is done, use umockdev_ioctl_client_complete() to let the
* client continue with the result of the emulation. You can also use
* umockdev_ioctl_client_abort() to kill the client. Note that this handling
* does not need to be immediate. It is valid to immediately return #TRUE from
* this function and call umockdev_ioctl_client_complete() at a later point.
*
* Note that this function will be called from a worker thread with a private
* #GMainContext for the #UMockdevTestbed. Do not block this context for longer
* periods. The complete handler may be called from a different thread.
*
* Returns: #TRUE if the request is being handled, #FALSE otherwise.
* Since: 0.16
*/
/**
* UMockdevIoctlBase::handle-read:
* @handler: A #UMockdevIoctlBase
* @client: A #UMockdevIoctlClient
*
* Called when a read is requested by the client.
*
* The result buffer is represented by #UMockdevIoctlClient::arg of @client.
* Retrieve its length to find out the requested read length. The content of
* the buffer has already been retrieved, and you can freely use and update it.
*
* See #UMockdevIoctlBase::handle-ioctl for some more information.
*
* Returns: #TRUE if the request is being handled, #FALSE otherwise.
* Since: 0.16
*/
/**
* UMockdevIoctlBase::handle-write:
* @handler: A #UMockdevIoctlBase
* @client: A #UMockdevIoctlClient
*
* Called when a write is requested by the client.
*
* The written buffer is represented by #UMockdevIoctlClient::arg of @client.
* Retrieve its length to find out the requested write length. The content of
* the buffer has already been retrieved, and you can freely use it.
*
* See #UMockdevIoctlBase::handle-ioctl for some more information.
*
* Returns: #TRUE if the request is being handled, #FALSE otherwise.
* Since: 0.16
*/

private class StartListenClosure {
Expand Down
3 changes: 3 additions & 0 deletions src/umockdev.vala
Original file line number Diff line number Diff line change
Expand Up @@ -764,6 +764,7 @@ public class Testbed: GLib.Object {
* support.
*
* Returns: %TRUE on success, %FALSE on error.
* Since: 0.16
*/
public bool attach_ioctl (string dev, IoctlBase handler) throws GLib.Error
{
Expand All @@ -788,6 +789,7 @@ public class Testbed: GLib.Object {
* if the path is not currently attached.
*
* Returns: %TRUE on success, %FALSE on error.
* Since: 0.16
*/
public bool detach_ioctl (string dev) throws GLib.Error
{
Expand Down Expand Up @@ -899,6 +901,7 @@ public class Testbed: GLib.Object {
* information.
*
* Returns: %TRUE on success, %FALSE if the recording could not be loaded
* Since: 0.16
*/
public bool load_pcap (string sysfs, string recordfile) throws GLib.Error, FileError, IOError, RegexError
{
Expand Down

0 comments on commit 5e2e428

Please sign in to comment.