11. NUT core development and maintenance

This section is intended to people who want to develop new core features, or to do some maintenance.

11.1. NUT-specific autoconf macros

The following NUT-specific autoconf macros are defined in the m4/ directory.

  • NUT_TYPE_SOCKLEN_T
  • NUT_TYPE_UINT8_T
  • NUT_TYPE_UINT16_T

    Check for the corresponding type in the system header files, and
    #define a replacement if necessary.
  • NUT_CHECK_LIBGD
  • NUT_CHECK_LIBNEON
  • NUT_CHECK_LIBNETSNMP
  • NUT_CHECK_LIBPOWERMAN
  • NUT_CHECK_LIBOPENSSL
  • NUT_CHECK_LIBNSS
  • NUT_CHECK_LIBUSB
  • NUT_CHECK_LIBWRAP

    Determine the compiler flags for the corresponding library. On
    success, set nut_have_libxxx="yes" and set LIBXXX_CFLAGS and
    LIBXXX_LDFLAGS. On failure, set nut_have_libxxx="no". This macro
    can be run multiple times, but will do the checking only once.
    Here "xxx" should of course be replaced by the respective library name.
    The checks for each library grow organically to compensate for
    various bugs in the libraries, pkg-config, etc. This is why we have
    a separate macro for each library.
  • NUT_CHECK_IPV6

    Check for various features required to compile the IPv6 support.
    dnl Check for various features required for IPv6 support. Define a
    preprocessor symbol for each individual feature (HAVE_GETADDRINFO,
    HAVE_FREEADDRINFO, HAVE_STRUCT_ADDRINFO, HAVE_SOCKADDR_STORAGE,
    SOCKADDR_IN6, IN6_ADDR, HAVE_IN6_IS_ADDR_V4MAPPED,
    HAVE_AI_ADDRCONFIG). Also set the shell variable nut_have_ipv6=yes
    if all the required features are present. Set nut_have_ipv6=no
    otherwise.
  • NUT_CHECK_OS

    Check for the exact system name and type.
    This was only used in the past to determine the packaging rule to be used
    through the OS_NAME variable, but may be useful for other purposes in the
    future.
  • NUT_REPORT_FEATURE(FEATURE, VALUE, VARIABLE, DESCRIPTION)

    Schedule a line for the end-of-configuration feature summary.  The
    FEATURE is a descriptive string such that the sentence "Checking
    whether to FEATURE" makes sense, and VALUE describes the decision
    taken (typically yes or no). The feature is also reported to the
    terminal.
    Also use VARIABLE and DESCRIPTION for defining AM_CONDITIONAL and
    AC_DEFINE (only if VALUE = "yes"). VARIABLE is of the form 'WITH_<NAME>'.
  • NUT_REPORT(FEATURE, VALUE)

    Schedule a line for the end-of-configuration feature summary, without
    printing anything to the terminal immediately.
  • NUT_PRINT_FEATURE_REPORT

    Print out a list of the features that have been reported by
    previous NUT_REPORT_FEATURE macro calls.
  • NUT_ARG_WITH(FEATURE, DESCRIPTION, DEFAULT)

    Declare a simple --with-FEATURE option with the given DESCRIPTION
    and DEFAULT. Sets the variable nut_with_FEATURE.

11.2. NUT roadmap and ideas for future expansion

Here are some ideas that have come up over the years but haven’t been implemented yet. This may be a good place to start if you’re looking for a rainy day hacking project.

Roadmap

2.6

This release is focused on the website and documentation rewrite, using the excellent AsciiDoc.

2.8

This branch will focus on configuration and user interface improvements.

3.0

This major transition will mark the final switch to a complete power device broker.

Non-network "upsmon"

Some systems don’t want a daemon listening to the network. This can be for security reasons, or perhaps because the system has been squashed down and doesn’t have TCP/IP available. For these situations you could run a driver and program that sits on top of the driver socket to do local monitoring.

This also makes monitoring extremely easy to automate - you don’t need to worry about usernames, passwords or firewalling. Just start a driver and drop this program on top of it.

  • Parse ups.conf and open the state socket for a driver
  • Send DUMPALL and enter a select loop
  • Parse SETINFOs that change ups.status
  • When you get OB LB, shut down

Completely unprivileged upsmon

upsmon currently retains root in a forked process so it can call the shutdown command. The only reason it needs root on most systems is that only privileged users can signal init or send a message on /dev/initctl.

In the case of systems running sysvinit (Slackware, others?), upsmon could just open /dev/initctl while it has root and then drop it completely. When it’s time to shut down, fire a control structure at init across the lingering socket and tell it to enter runlevel 0.

This has been shown to work in local tests, but it’s not portable. It could only be offered as an option for those systems which run that flavor of init. It also needs to be tested to see what happens to the lingering fd over time, such as when init restarts after an upgrade.

For other systems, there is always the possibility of having a suid program which does nothing but prod init into starting a shutdown. Lock down the group access so only upsmon’s unprivileged user can access it, and make that your SHUTDOWNCMD. Then it could drop root completely.

Chrooted upsmon

upsmon could run the network monitoring part in a chroot jail if it had a pipe to another process running outside for NOTIFY dispatches. Such a pipe would have to be constructed extremely carefully so an attacker could not compromise it from the jailed process.

A state machine with a tightly defined sequence could do this safely. All it has to do is dispatch the UPS name and event type.

[start] [type] [length] <name> [stop]

Monitor program with interpreted language

Once in awhile, I get requests for a way to shut down based on the UPS temperature, or ambient humidity, or at a certain battery charge level, or any number of things other than an "OB LB" status. It should be obvious that adding a way to monitor all of that in upsmon would bloat upsmon for all those people who really don’t need anything like that.

A separate program that interprets a list of rules and uses it to monitor the UPS equipment is the way to solve this. If you have a condition that needs to be tested, add a rule.

Some of the tools that such a language would need include simple greater-than/less-than testing (if battery.charge < 20), equivalence testing (if ups.model = "SMART-UPS 700"), and some way to set and clear timers.

Due to the expected size and limited audience for such a program, it might have to be distributed separately.

Note

Python may be a good candidate.

Sandbox