diff --git a/.gitignore b/.gitignore index 9255e08..1b1dd2e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ config.log config.status configure libtool +pre-inst-env TAGS diff --git a/AUTHORS b/AUTHORS index a0ec233..2f438b5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -7,4 +7,6 @@ See also files THANKS and ChangeLog. * Antlers Bug fixes in 'libguile-udev/udev-monitor-func.c' * Mathieu Othacehe - Bug reports in GNU Guix mailing list. \ No newline at end of file + Bug reports in GNU Guix mailing list. +* Maxim Cournoyer + Improvements to the documentation. diff --git a/build-aux/compile b/build-aux/compile index df363c8..5e5dbe6 100755 --- a/build-aux/compile +++ b/build-aux/compile @@ -1,4 +1,4 @@ -#! /bin/sh +#!/bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC diff --git a/configure.ac b/configure.ac index 6b87ae8..c41b8ba 100644 --- a/configure.ac +++ b/configure.ac @@ -109,6 +109,7 @@ AC_SUBST([guilesitedir]) GUILE_EFFECTIVE_VERSION=`$GUILE -c '(display (effective-version))'` AC_SUBST(GUILE_EFFECTIVE_VERSION) +AC_CONFIG_FILES([pre-inst-env], [chmod +x pre-inst-env]) AC_CONFIG_FILES([Makefile libguile-udev/Makefile build-aux/Makefile]) AC_CONFIG_FILES([build-aux/m4/Makefile build-aux/am/Makefile doc/Makefile]) AC_CONFIG_FILES([modules/Makefile modules/udev/Makefile]) diff --git a/doc/guile-udev.texi b/doc/guile-udev.texi index 4549806..c6b3d01 100644 --- a/doc/guile-udev.texi +++ b/doc/guile-udev.texi @@ -11,6 +11,7 @@ This manual documents Guile-Udev version @value{VERSION}. Copyright (C) 2020 Artyom V. Poptsov @email{poptsov.artyom@@gmail.com} +Copyright (C) 2023 Maxim Cournoyer @email{maxim.cournoyer@@gmail.com} Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or @@ -54,11 +55,11 @@ Documentation License.'' @menu * Introduction:: -* Installation:: -* API Reference:: - -Appendices - +* Installing as a system package:: +* Installing from sources:: +* Using this library before it is installed:: +* API Reference:: Appendices +* Examples:: * GNU Free Documentation License:: The license of this manual. @end menu @@ -72,8 +73,19 @@ Guile-Udev is a module that provides bindings to @url{https://www.freedesktop.org/software/systemd/man/libudev.html, libudev} for programs written in @url{https://www.gnu.org/software/guile/, GNU Guile}. -@node Installation -@chapter Installation +@node Installing as a system package +@chapter Installing as a system package + +The @url{https://guix.gnu.org, GNU Guix} package manager, which can run on top +of any GNU(/Linux) distribution, offers a @code{guile-udev} package which can +be installed via: + +@example +guix install guile-udev +@end example + +@node Installing from sources +@chapter Installing from sources Guile-Udev sources are available from GitHub at @url{https://github.com/artyom-poptsov/guile-udev/}. This section describes @@ -86,6 +98,15 @@ Guile-Udev depends on the following packages: @item libudev @end itemize +Alternatively, if you have GNU Guix installed, you can run: + +@example +guix shell +@end example + +After following the instructions displayed by the above command to authorize +automatically loading the @file{guix.scm} file at the root of the repository. + Get the sources of Guile-Udev from GitHub using Git (a good introduction to Git is @url{https://git-scm.com/book/en/v2, Pro Git} book, which is available online): @@ -118,6 +139,17 @@ installed in Guile's default path. But, if you don't know where your Guile site directory is, run @command{configure} without the option, and it will give you a suggestion. +@node Using this library before it is installed +@chapter Using this library before it is installed + +If you would like to test this Guile extension as you work on it, without +having to install it, you can use the @file{pre-inst-env} wrapper after having +configured and built the project, e.g.@: + +@example +./pre-inst-env examples/device-listener.scm +@end example + @node API Reference @chapter API Reference @@ -155,7 +187,9 @@ parameters specified by keywords described below. @table @samp @item callback -Callback to be called when an udev event occurs. +A procedure to be called when an udev event occurs. It gets applied to a +single argument, which is the @code{udev-device} object the event originated +from. Expected type: procedure @@ -163,8 +197,10 @@ Default value: @code{(const #f)} @item filter Udev event filter. -Expected type: a list with two elements: the 1st element is sybsystem name, -the 2nd element is device type +Expected type: a list with two elements: the first element is the subsystem +name, while the second element is the device type. To match @emph{any} device +type, you may use @code{#f} instead of an actual device type. If needed, more +filters can be installed via the @code{udev-monitor-add-filter!} procedure. Default value: @code{#f} @@ -205,9 +241,12 @@ Check if @var{x} is an udev-monitor object. Return @code{#t} if it is, or @code{#f} otherwise. @end deffn -@deffn {Scheme Procedure} udev-monitor-add-filter! udev-monitor sybsystem devtype +@deffn {Scheme Procedure} udev-monitor-add-filter! udev-monitor subsystem [devtype] Add a new filter for the events on @var{udev-monitor} that will trigger the -provided callback. This procedure must be called before starting the scanning. +provided callback, for a device of type @var{devtype} belonging to the +@var{subsystem} subsystem. @var{devtype} is optional; when omitted, devices +of @emph{any} type are matched. This procedure must be called before starting +the scanning. @end deffn @deffn {Scheme Procedure} udev-monitor-remove-filters! udev-monitor @@ -328,6 +367,27 @@ Usage example: @end deffn +@node Examples +@chapter Examples + +Here's an example of a device listener that prints the device path of USB +devices that emit udev events: + +@lisp +@verbatiminclude ../examples/device-listener.scm +@end lisp + +To trigger USB events without actually inserting or removing USB devices into +your computer, you can use the @command{udevadm} command (provided by the +@code{eudev} package from Guix) @emph{as root}: + +@example +# udevadm trigger --verbose --subsystem-match=usb +@end example + +You can find the source of this example in the @file{examples} directory of +the project. + @node GNU Free Documentation License @appendix GNU Free Documentation License diff --git a/examples/device-listener.scm b/examples/device-listener.scm index ee9acb8..6ceaf23 100755 --- a/examples/device-listener.scm +++ b/examples/device-listener.scm @@ -1,5 +1,4 @@ -#!/usr/bin/guile \ --L modules -e main -s +#!/usr/bin/env -S guile -L modules -e main -s !# (use-modules (udev udev) diff --git a/libguile-udev/udev-monitor-func.c b/libguile-udev/udev-monitor-func.c index 4586653..94b3b4c 100644 --- a/libguile-udev/udev-monitor-func.c +++ b/libguile-udev/udev-monitor-func.c @@ -30,9 +30,11 @@ #include "udev-device-type.h" #include "error.h" -SCM_DEFINE_N(gudev_add_filter_x, "udev-monitor-add-filter!", 3, - (SCM udev_monitor, SCM subsystem, SCM devtype), - "Add a filter to the monitor.") +SCM_DEFINE(gudev_add_filter_x, "udev-monitor-add-filter!", 2, 1, 0, + (SCM udev_monitor, SCM subsystem, SCM devtype), + "Add a filter to the monitor. @var{subsystem} is the subsystem\n" + "associated with a device while @var{devtype} is its device type.\n" + "The @var{devtype} argument is optional.") #define FUNC_NAME s_gudev_add_filter_x { char* c_subsystem = NULL; @@ -41,14 +43,17 @@ SCM_DEFINE_N(gudev_add_filter_x, "udev-monitor-add-filter!", 3, int result; SCM_ASSERT(scm_is_string(subsystem), subsystem, SCM_ARG1, FUNC_NAME); - SCM_ASSERT(scm_is_string(devtype), devtype, SCM_ARG2, FUNC_NAME); + SCM_ASSERT(scm_is_string(devtype) || SCM_UNBNDP(devtype), devtype, + SCM_ARG2, FUNC_NAME); scm_dynwind_begin(0); c_subsystem = scm_to_locale_string(subsystem); scm_dynwind_free(c_subsystem); - c_devtype = scm_to_locale_string(devtype); + if (!SCM_UNBNDP(devtype)) + c_devtype = scm_to_locale_string(devtype); + scm_dynwind_free(c_devtype); result = udev_monitor_filter_add_match_subsystem_devtype(umd->udev_monitor, diff --git a/modules/udev/monitor.scm b/modules/udev/monitor.scm index 025cb5e..0fd640d 100644 --- a/modules/udev/monitor.scm +++ b/modules/udev/monitor.scm @@ -24,12 +24,21 @@ (filter #f) (timeout-usec 0) (timeout-sec 0)) + "Create a new 'udev-monitor' object configured with the specified parameters. +CALLBACK is a one argument procedure (receiving a 'udev-device' object) called +when an event matching the specified FILTER. FILTER is a list whose first +element is the device subsystem, and whose second argument is the device type, +or #f to match any type." (let ((monitor (%make-udev-monitor udev))) (udev-monitor-set-timeout! monitor timeout-sec timeout-usec) (udev-monitor-set-callback! monitor callback) (udev-monitor-set-error-callback! monitor callback) (when filter - (udev-monitor-add-filter! monitor (car filter) (cadr filter))) + (let ((subsystem (car filter)) + (devtype (cadr filter))) + (if devtype + (udev-monitor-add-filter! monitor subsystem devtype) + (udev-monitor-add-filter! monitor subsystem)))) monitor)) (load-extension "libguile-udev" "init_udev_monitor") diff --git a/pre-inst-env.in b/pre-inst-env.in new file mode 100644 index 0000000..b4aeb78 --- /dev/null +++ b/pre-inst-env.in @@ -0,0 +1,14 @@ +#!/bin/sh + +abs_top_srcdir="`cd "@abs_top_srcdir@" > /dev/null; pwd`" +abs_top_builddir="`cd "@abs_top_builddir@" > /dev/null; pwd`" + +GUILE_EXTENSIONS_PATH="$abs_top_builddir/libguile-udev/.libs${GUILE_EXTENSIONS_PATH=:+:}$GUILE_EXTENSIONS_PATH" +GUILE_LOAD_COMPILED_PATH="$abs_top_builddir/modules${GUILE_LOAD_COMPILED_PATH:+:}$GUILE_LOAD_COMPILED_PATH" +GUILE_LOAD_PATH="$abs_top_srcdir/modules${GUILE_LOAD_PATH:+:}:$GUILE_LOAD_PATH" +export GUILE_EXTENSIONS_PATH GUILE_LOAD_COMPILED_PATH GUILE_LOAD_PATH + +PATH="$abs_top_builddir/scripts:$PATH" +export PATH + +exec "$@"