Subject: [bug#75528] [PATCH 2/2] services: Add power.

From: Maxim Cournoyer <[email-masked]>
Date: Tue, 18 Feb 2025 15:51:06 +0900

Hi Tomas,

Tomas Volf <[email-masked]> writes:

[...]

>> Deprecating /var/run to /run is not a Guix thing, but a File Hiearchy
>> Standard (FHS) thing [0].  Since we already use /run, there's no good
>> reason to have /var/run something else than a symlink to /run, and
>> there's an actual change pending merge that would do that, along making
>> /run mounted as a tmpfs (bug#73494).
>>
>> [0]  https://refspecs.linuxfoundation.org/FHS_3.0/fhs/ch05s13.html
>
> I did not know we actually care about FHS (for example our /usr/bin
> definitely does not look like it should in that case :) ).
>
> I did the s|/var/run|/run|.

We typically do not follow FHS much due to each of our packages being
installed under their own prefix, but for the few things where we do,
like here, I think it makes sense to stick to it, as it brings
familiarity and consistency to our users.

>>>> s/Slave/slave/ ?  Could be nicer to use a neutral alternative like
>>>> 'follower machine'.
>>>
>>> The "Slave machine" (including the capitalization) is a term used in the
>>> manual.  I can lower-case it if you would prefer, seems that manual
>>> actually uses both casings now when I looked for it.
>>>
>>> I do not think inventing new terminology is a good idea, since users
>>> will not be able to find it in the manual distributed with the program.
>>
>> The 'slave' word always carry a negative connotation.  I think it's a
>> good idea to be proactive on modernizing the terminology where we can.
>
> In that case I would suggest to contact the upstream and convince them
> regarding this topic.  Once that happens, we will be able to adjust the
> documentation with the next release (which would be free of offensive
> terminology).
>
> In any case, this is not a first occurrence of the word "slave" in the
> Guix repository nor manual.

That there are currently other occurrences is not a good reason to add
more, in my opinion :-).  That said, I've looked at upstream sources and
it's true that the old master/slave terminology is currently deeply
interwined in code and doc... so I did an experiment and came up with
<https://codeberg.org/apteryx/acupsd/pulls/1>.  I also forwarded the
svn diff to upstream via their mailing list.  We'll see what they think.

[...]

>>> WARNING: (guile-user): imported module (gnu services) overrides core binding `delete'
>>>
>>> However, when done "my" way (putting srfi-1 first, since "stdlib"), the
>>> warning goes away.
>>
>> That's an interesting workaround, but I think we should look into that
>> problem and fix it definitely I often used #:hidden (delete) without any
>> issue it seems, so I'm not even sure if its existence still solves a
>> true problem in current Guile.
>
> I have recently (~few months back) tried to remove the `delete' and it a
> wall quickly, so I assume for reasons I do not understand it is still
> required.
>
> Having to use #:hidden (delete) on every single relevant import is in my
> opinion much worse solution than just ordering imports with srfi-1 at
> the top.
>
> But, I concur, it would be best it this just worked in any order.

OK, good to know, but let's keep this out of scope for the context of
this change.

> Anyway, I have sorted the modules as requested.  I am not sure whether
> to sort
>
> #$@(apcupsd-event-handlers-modules
>     (apcupsd-configuration-event-handlers cfg))
>
>
> Under `a' or `m' though.  Opinion?

I'm not sure I understood the question, but under `a' makes more sense
to me (which `m' are you referring to?).

>>>>> +(define-configuration/no-serialization apcupsd-event-handlers
>>>>> +  (killpower
>>>>> +   (gexp
>>>>> +    #~((wall "Apccontrol doing: apcupsd --killpower on UPS ~a" name)
>>>>> +       (sleep 10)
>>>>> +       (apcupsd "--killpower")
>>>>> +       (wall "Apccontrol has done: apcupsd --killpower on UPS ~a" name)))
>>>>> +   "Handler for killpower event.")
>>>>
>>
>> By the way, why do we need to sleep 10 seconds here?  It seems
>> unnecessary.
>
> All default handlers are just conversions of the official apccontrol
> script, and it has the sleep in there.  I am not sure why, so I have
> decided it would be better to leave it as it was.

OK, I guess it's safer to keep it.

>> I just thought about it, perhaps it could be more concise to extract the
>> field values using match-record (these are bound to shorter names, since
>> they omit the 'apcupsd-configuration-' prefix).
>
> If I got the idea right, you suggest converting
>
> 	      ("emergency"
> 	       #$@(apcupsd-event-handlers-emergency
> 		   (apcupsd-configuration-event-handlers cfg)))
>
>
> into
>
> 	      ("emergency"
> 	       #$@(match-record cfg <apcupsd-configuration> (handlers)
>                     (match-record handlers <apcupsd-event-handlers> (emergency)
>                       emergency)))
>
>
> I am not sure it is increase in readability, but maybe I misunderstood
> the suggestion.

I think something like this should work:

--8<---------------cut here---------------start------------->8---
modified   gnu/services/power.scm
@@ -494,119 +494,67 @@ (define-configuration apcupsd-configuration
    empty-serializer))
 
 (define (%apccontrol config)
-  (program-file
-   "apccontrol"
-   #~(begin
-       (use-modules (ice-9 format)
-                    (ice-9 match)
-                    (ice-9 popen)
-                    (srfi srfi-9)
-                    #$@(apcupsd-event-handlers-modules
-                        (apcupsd-configuration-event-handlers config)))
-       ;; Script dir depends on these, and the configuration depends on the
-       ;; script dir.  To sever the cyclic dependency, pass the file names via
-       ;; environment variables.
-       (define conf (getenv "GUIX_APCUPSD_CONF"))
-       (define powerfail-file (getenv "GUIX_APCUPSD_POWERFAIL_FILE"))
-
-       (define (err . args)
-         (apply format (current-error-port) args))
-       (define (wall . args)
-         (system* #$(file-append util-linux "/bin/wall") (apply format #f args)))
-       (define (apcupsd . args)
-         (apply system* #$(file-append apcupsd "/sbin/apcupsd") "-f" conf args))
-       (define (mail-to-root subject body)
-         (let ((port (open-pipe* OPEN_WRITE
-                                 "/run/privileged/bin/sendmail"
-                                 "-F" "apcupsd"
-                                 "root")))
-           (format port "Subject: ~a~%~%~a~&" subject body)
-           (close-pipe port)))
-       (match (cdr (command-line))
-         (((? string? cmd) name connected powered)
-          (let ((connected? (match connected
+  (define event-handlers (apcupsd-configuration-event-handlers config))
+  (match-record event-handlers <apcupsd-event-handlers>
+                ( modules killpower commfailure commok powerout
+                  onbattery offbattery ...)
+    (program-file
+     "apccontrol"
+     #~(begin
+         (use-modules (ice-9 format)
+                      (ice-9 match)
+                      (ice-9 popen)
+                      (srfi srfi-9)
+                      #$@modules)
+         ;; Script dir depends on these, and the configuration depends on the
+         ;; script dir.  To sever the cyclic dependency, pass the file names via
+         ;; environment variables.
+         (define conf (getenv "GUIX_APCUPSD_CONF"))
+         (define powerfail-file (getenv "GUIX_APCUPSD_POWERFAIL_FILE"))
+
+         (define (err . args)
+           (apply format (current-error-port) args))
+
+         (define (wall . args)
+           (system* #$(file-append util-linux "/bin/wall") (apply format #f args)))
+
+         (define (apcupsd . args)
+           (apply system* #$(file-append apcupsd "/sbin/apcupsd") "-f" conf args))
+
+         (define (mail-to-root subject body)
+           (let ((port (open-pipe* OPEN_WRITE
+                                   "/run/privileged/bin/sendmail"
+                                   "-F" "apcupsd"
+                                   "root")))
+             (format port "Subject: ~a~%~%~a~&" subject body)
+             (close-pipe port)))
+         
+         (match (cdr (command-line))
+           (((? string? cmd) name connected powered)
+            (let ((connected? (match connected
+                                ("1" #t)
+                                ("0" #f)))
+                  (powered? (match powered
                               ("1" #t)
-                              ("0" #f)))
-                (powered? (match powered
-                            ("1" #t)
-                            ("0" #f))))
-            (match cmd
-              ;; I am sure this could be done by macro, but meh.  Last release
-              ;; of apcupsd was in 2016, so maintaining this will not be much
-              ;; work.
-              ("killpower"
-               #$@(apcupsd-event-handlers-killpower
-                   (apcupsd-configuration-event-handlers config)))
-              ("commfailure"
-               #$@(apcupsd-event-handlers-commfailure
-                   (apcupsd-configuration-event-handlers config)))
-              ("commok"
-               #$@(apcupsd-event-handlers-commok
-                   (apcupsd-configuration-event-handlers config)))
-	      ("powerout"
-	       #$@(apcupsd-event-handlers-powerout
-		   (apcupsd-configuration-event-handlers config)))
-	      ("onbattery"
-	       #$@(apcupsd-event-handlers-onbattery
-		   (apcupsd-configuration-event-handlers config)))
-	      ("offbattery"
-	       #$@(apcupsd-event-handlers-offbattery
-		   (apcupsd-configuration-event-handlers config)))
-	      ("mainsback"
-	       #$@(apcupsd-event-handlers-mainsback
-		   (apcupsd-configuration-event-handlers config)))
-	      ("failing"
-	       #$@(apcupsd-event-handlers-failing
-		   (apcupsd-configuration-event-handlers config)))
-	      ("timeout"
-	       #$@(apcupsd-event-handlers-timeout
-		   (apcupsd-configuration-event-handlers config)))
-	      ("loadlimit"
-	       #$@(apcupsd-event-handlers-loadlimit
-		   (apcupsd-configuration-event-handlers config)))
-	      ("runlimit"
-	       #$@(apcupsd-event-handlers-runlimit
-		   (apcupsd-configuration-event-handlers config)))
-	      ("doreboot"
-	       #$@(apcupsd-event-handlers-doreboot
-		   (apcupsd-configuration-event-handlers config)))
-	      ("doshutdown"
-	       #$@(apcupsd-event-handlers-doshutdown
-		   (apcupsd-configuration-event-handlers config)))
-	      ("annoyme"
-	       #$@(apcupsd-event-handlers-annoyme
-		   (apcupsd-configuration-event-handlers config)))
-	      ("emergency"
-	       #$@(apcupsd-event-handlers-emergency
-		   (apcupsd-configuration-event-handlers config)))
-	      ("changeme"
-	       #$@(apcupsd-event-handlers-changeme
-		   (apcupsd-configuration-event-handlers config)))
-	      ("remotedown"
-	       #$@(apcupsd-event-handlers-remotedown
-		   (apcupsd-configuration-event-handlers config)))
-	      ("startselftest"
-	       #$@(apcupsd-event-handlers-startselftest
-		   (apcupsd-configuration-event-handlers config)))
-	      ("endselftest"
-	       #$@(apcupsd-event-handlers-endselftest
-		   (apcupsd-configuration-event-handlers config)))
-	      ("battdetach"
-	       #$@(apcupsd-event-handlers-battdetach
-		   (apcupsd-configuration-event-handlers config)))
-	      ("battattach"
-	       #$@(apcupsd-event-handlers-battattach
-		   (apcupsd-configuration-event-handlers config)))
-              (_
-               (err "Unknown event: ~a~%" cmd)
-               (err "Iff the event was emitted by apcupsd, this is a bug.~%")
-               (err "Please report to [email-masked].~%")
-               (exit #f)))))
-         (args
-          (err "Unknown arguments: ~a~%" args)
-          (err "Iff the arguments were passed by apcupsd, this is a bug.~%")
-          (err "Please report to [email-masked].~%")
-          (exit #f))))))
+                              ("0" #f))))
+              (match cmd
+                ("killpower" #$killpower)
+                ("commfailure" #$commfailure)
+                ("commok" #$commok)
+	        ("powerout" #$powerout)
+	        ("onbattery" #$onbattery)
+	        ("offbattery" #$offbattery)
+                [...]
+                (_
+                 (err "Unknown event: ~a~%" cmd)
+                 (err "If the event was emitted by apcupsd, this is a bug.~%")
+                 (err "Please report to [email-masked].~%")
+                 (exit #f)))))
+           (args
+            (err "Unknown arguments: ~a~%" args)
+            (err "If the arguments were passed by apcupsd, this is a bug.~%")
+            (err "Please report to [email-masked].~%")
+            (exit #f))))))))
 
 (define (apcupsd-script-dir config)
   (computed-file
--8<---------------cut here---------------end--------------->8---

[...]

>>> This file header is taken from the official configuration file
>>> distributed with the apcupsd (except the GNU Guix part).  So while I do
>>> expect that this configuration file should work with newer version, the
>>> upstream decided to put the version into the configuration file.
>>>
>>> I have no strong opinion either way here, should I just remove the file
>>> header completely?
>>
>> I think so, since we're going the path of producing our own, we don't
>> need to keep things that are not deemed useful.
>
> I have removed the version, but kept the header, so that there is
> reference to apcupsd-service-type left in the file.

Sounds reasonable.

[...]

> Getting bit off topic, but I am not sure how that would work.  Between
> various macros, and Scheme being LISP-1, I have no idea how to write
> robust code that would just magically always indent "right".
>
> But I would be glad to be proven wrong. :)

I guess you could have a procedure that calls the existing indenting
Elisp functions, and then have a post-processing pass on top to fix it
the way wa want.  It's probably a bit over the top :-).  I like
your/Emacs' down to Earth solution.

[...]

> One additional change I have made is to change
>
>         (requirement '())
>
>
> into
>
>         (requirement '(user-processes))
>
> Without the dependency, the daemon got respawned by shepherd on shutdown
> and prevented the machine from going offline, which sucked a bit. ^_^

Oh wow; good catch.  That seems a rather large foot gun to have for
service writers.  I wonder if something could be done about it in the
Shepherd.

> I thought I would mention it so that you can keep it in mind for future
> code reviews.

Indeed, thanks for bringing this to my attention.

> With that I think I am out of things that I want to change or would
> appreciate feedback on, so I am sending a v2.  Thank you for working
> with me through this, the code is much better than in v1.

I'll let you work through my last match-record suggestion above, if you
want and send a v3.

I'm also attaching a fixup with the terminology changes I've submitted
upstream if you'd like to validate it still works (I don't have any
UPS to try it with myself).

>From 63457572d4b84ba17ef34ab479fd0e425f7ca774 Mon Sep 17 00:00:00 2001
Message-ID: <6345757[email-masked]>
From: Maxim Cournoyer <[email-masked]>
Date: Tue, 18 Feb 2025 09:46:45 +0900
Subject: [PATCH] fixup! services: Add power.

---
 doc/guix.texi                                 |    2 +-
 gnu/local.mk                                  |    1 +
 .../patches/apcupsd-leader-follower.patch     | 1847 +++++++++++++++++
 gnu/packages/power.scm                        |    4 +-
 gnu/services/power.scm                        |    4 +-
 5 files changed, 1854 insertions(+), 4 deletions(-)
 create mode 100644 gnu/packages/patches/apcupsd-leader-follower.patch

diff --git a/doc/guix.texi b/doc/guix.texi
index 126e542122..06f51fa3f9 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -36789,7 +36789,7 @@ Power Management Services
 @item connected?
 Is @code{#t} if @command{apcupsd} is connected to the UPS via a serial
 port (or a USB port).  In most configurations, this will be the case.
-In the case of a Slave machine where apcupsd is not directly connected
+In the case of a follower machine where apcupsd is not directly connected
 to the UPS, this value will be @code{#f}.
 
 @item powered?
diff --git a/gnu/local.mk b/gnu/local.mk
index 8042ba0482..d1e7af3743 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -990,6 +990,7 @@ dist_patch_DATA =						\
   %D%/packages/patches/antlr3-3_1-fix-java8-compilation.patch	\
   %D%/packages/patches/antlr3-3_3-fix-java8-compilation.patch	\
   %D%/packages/patches/aoflagger-use-system-provided-pybind11.patch \
+  %D%/packages/patches/apcupsd-leader-follower.patch		\
   %D%/packages/patches/apr-fix-atomics.patch			\
   %D%/packages/patches/apr-skip-getservbyname-test.patch	\
   %D%/packages/patches/aria2-unbundle-wslay.patch		\
diff --git a/gnu/packages/patches/apcupsd-leader-follower.patch b/gnu/packages/patches/apcupsd-leader-follower.patch
new file mode 100644
index 0000000000..632b6ede71
--- /dev/null
+++ b/gnu/packages/patches/apcupsd-leader-follower.patch
@@ -0,0 +1,1847 @@
+This replaces the master/slave termininology with leader/follower, which
+is more inclusive and forward-looking.
+
+Index: ReleaseNotes
+===================================================================
+--- ReleaseNotes	(revision 2381)
++++ ReleaseNotes	(working copy)
+@@ -5,10 +5,15 @@
+ new features over the previous 3.12.x stable series. Users of all previous
+ versions are encouraged to upgrade.
+ 
+-IF YOU USE THE OLD STYLE MASTER/SLAVE NETWORKING MODE, BE SURE TO READ THE
++IF YOU USE THE OLD STYLE LEADER/FOLLOWER NETWORKING MODE, BE SURE TO READ THE
+ 3.14.0 RELEASE NOTES BELOW.
+ 
++3.15.0 -- TBD
+ 
++VARIA
++
++  * Replace master/slave terminology with leader/follower throughout project
++
+ 3.14.14 -- 31 May 2016
+ 
+ BUG FIXES
+Index: autoconf/configure.in
+===================================================================
+--- autoconf/configure.in	(revision 2381)
++++ autoconf/configure.in	(working copy)
+@@ -600,8 +600,8 @@
+     [])
+ 
+ AC_ARG_ENABLE(net, [
+-AC_HELP_STRING([--enable-net], [Compile networking driver for slaves (default)])
+-AC_HELP_STRING([--disable-net], [No network driver for slaves])],
++AC_HELP_STRING([--enable-net], [Compile networking driver for followers (default)])
++AC_HELP_STRING([--disable-net], [No network driver for followers])],
+    [ if test "$enableval" = "yes" ; then
+         AC_DEFINE(HAVE_NET_DRIVER,, [Define if building net driver])
+         NET_DRIVER="net"
+Index: configure
+===================================================================
+--- configure	(revision 2381)
++++ configure	(working copy)
+@@ -1477,8 +1477,8 @@
+   --enable-usb            Compile USB UPS code
+   --disable-usb           No USB UPS code (default)
+ 
+-  --enable-net            Compile networking driver for slaves (default)
+-  --disable-net           No network driver for slaves
++  --enable-net            Compile networking driver for followers (default)
++  --disable-net           No network driver for followers
+ 
+   --enable-snmp           Compile SNMP driver (default)
+   --disable-snmp          No SNMP driver
+Index: doc/apcaccess.8
+===================================================================
+--- doc/apcaccess.8	(revision 2381)
++++ doc/apcaccess.8	(working copy)
+@@ -92,7 +92,7 @@
+ : Date and time apcupsd was started
+ .It STATUS
+ : UPS status.  One or more of the following (space-separated):
+-CAL TRIM BOOST ONLINE ONBATT OVERLOAD LOWBATT REPLACEBATT NOBATT SLAVE SLAVEDOWN
++CAL TRIM BOOST ONLINE ONBATT OVERLOAD LOWBATT REPLACEBATT NOBATT FOLLOWER FOLLOWERDOWN
+ .br
+ or
+ .br
+@@ -101,8 +101,8 @@
+ or
+ .br
+ SHUTTING DOWN
+-.It MASTERUPD
+-: Last time the master sent an update to the slave
++.It LEADERUPD
++: Last time the leader sent an update to the follower
+ .It ENDAPC
+ : Date and time of status information was written
+ .El
+Index: doc/apccontrol.8
+===================================================================
+--- doc/apccontrol.8	(revision 2381)
++++ doc/apccontrol.8	(working copy)
+@@ -34,7 +34,7 @@
+ configuration file - not the name in the EEPROM of a smart UPS. 
+ .It connected
+ This is 1 if apcupsd is connected to the UPS via a serial or USB port. 
+-In the case of a slave machine where apcupsd is not directly connected 
++In the case of a follower machine where apcupsd is not directly connected 
+ to the UPS, this value will be 0.
+ .It powered
+ This is 1 if the computer on which apcupsd is running is powered by the UPS 
+@@ -164,9 +164,9 @@
+ .Pp
+ Default action -- does nothing.
+ .It remotedown
+-apcupsd generates this event on a slave machine when it detects either (1)
+-that the master has shutdown, or (2) that an onbattery event has occurred 
+-and communication with the master has been lost.
++apcupsd generates this event on a follower machine when it detects either (1)
++that the leader has shutdown, or (2) that an onbattery event has occurred 
++and communication with the leader has been lost.
+ .Pp
+ Default action: sends "Remote Shutdown. Beginning Shutdown Sequence." to wall and exits. Immediately after this, apcupsd generates a doshutdown event to 
+ shutdown the system.
+Index: doc/apcupsd.conf.5
+===================================================================
+--- doc/apcupsd.conf.5	(revision 2381)
++++ doc/apcupsd.conf.5	(working copy)
+@@ -286,7 +286,7 @@
+ .Ss SHARE-UPS CONFIGURATION DIRECTIVES
+ .Pp
+ .Bl -hang -width "xxxxxxx"
+-.It UPSCLASS [\& standalone | shareslave | sharemaster \&]
++.It UPSCLASS [\& standalone | sharefollower | shareleader \&]
+ .Pp
+ The default is "standalone" and should be used for 
+ all computers powered by the UPS,  with a direct connection to 
+@@ -293,10 +293,10 @@
+ the UPS and where there are no other computers dependent on power 
+ from the UPS. This is the "normal" case.
+ .Pp
+-Use "shareslave" if you are using a Share-UPS interface expander 
++Use "sharefollower" if you are using a Share-UPS interface expander 
+ and connected to the BASIC port (simple signalling). 
+ .Pp
+-Use "sharemaster", if you are using a Share-UPS interface
++Use "shareleader", if you are using a Share-UPS interface
+ expander and connected to the ADVANCED port (smart signalling). 
+ .Pp
+ .It UPSMODE [\& disable | share \&]
+Index: doc/manual/manual.rst
+===================================================================
+--- doc/manual/manual.rst	(revision 2381)
++++ doc/manual/manual.rst	(working copy)
+@@ -80,7 +80,7 @@
+ serial-line UPS, you'll have to read about serial installation (see
+ `Installation: Serial-Line UPSes`_). If you need more
+ details about administration for unusual situations (such as a
+-master/slave or multi-UPS setup) you'll need to read the sections on
++leader/follower or multi-UPS setup) you'll need to read the sections on
+ those topics as well. Finally,
+ there are a number of technical reference sections which 
+ gives full details on things like configuration file directives and 
+@@ -262,9 +262,9 @@
+ 
+ net
+     This is the keyword to specify if you are using your
+-    UPS in Slave mode (i.e. the machine is not directly connected to
++    UPS in Follower mode (i.e. the machine is not directly connected to
+     the UPS, but to another machine which is), and it is connected to
+-    the Master via an ethernet connection. You must have apcupsd's
++    the Leader via an ethernet connection. You must have apcupsd's
+     Network Information Services NIS turned on for this mode to work.
+ 
+ snmp
+@@ -1229,12 +1229,12 @@
+ your halt script should things go wrong. Please consult the
+ specific system dependent README files for more details.
+ 
+-Please note that if you install from RPMs for a slave machine, you
++Please note that if you install from RPMs for a follower machine, you
+ will need to remove the changes that the RPM install script made
+ (similar to what is noted above) to the halt script. This is
+-because on a slave machine there is no connection to the UPS, so
++because on a follower machine there is no connection to the UPS, so
+ there is no need to attempt to power off the UPS. That will be done
+-by the master.
++by the leader.
+ 
+ 
+ Configure Options
+@@ -1280,9 +1280,9 @@
+ --enable-dumb  Turns on generation of the dumb signalling driver code (default).
+ --enable-usb   Turns on generation of the USB driver code. By default this is disabled.
+ --enable-net  Turns on generation of the NIS
+-    network driver for slaves. For each slave, this is the only driver
++    network driver for followers. For each follower, this is the only driver
+     needed. This driver works by reading the information from the the
+-    configured master using the NIS (Network Information Services)
++    configured leader using the NIS (Network Information Services)
+     interface.
+ --enable-snmp  Turns on generation of the
+     SNMP driver. This driver accesses the UPS over the network using
+@@ -1346,7 +1346,7 @@
+     checking is done on the value entered, so you must ensure that it
+     is a valid IP address.
+ --with-net-port=port  This option allows
+-    you to specify what port apcupsd will use for Master and Slave
++    you to specify what port apcupsd will use for Leader and Follower
+     communications. The default is system dependent but usually 6666.
+     This option simply sets the appropriate port in the apcupsd.conf
+     file, which can be changed at any later time.
+@@ -2046,22 +2046,22 @@
+ change in state of the NIS server before the server has shutdown.
+ Normally, you have at least 30 seconds of grace time between the
+ time the NIS server decides to shutdown and the time it no longer
+-responds. Your slave must poll during this interval.
++responds. Your follower must poll during this interval.
+ 
+ Any client run using the Net driver will shutdown when its own
+ timers expire or when the NIS server shuts down, whichever occurs
+-first. This means that if you want the slave to shutdown before the
++first. This means that if you want the follower to shutdown before the
+ server, you need only set ``BATTERYLEVEL``, ``MINUTES`` or
+ ``TIMEOUT`` on the client for a faster shutdown than the values
+-defined on the NIS server. This can often be useful if the slave is
+-less important than the master and you wish to reduce battery power
+-consumption so that the master can remain up longer during a power
++defined on the NIS server. This can often be useful if the follower is
++less important than the leader and you wish to reduce battery power
++consumption so that the leader can remain up longer during a power
+ outage.
+ 
+ NIS clients work principally by reading the STATFLAG record that is
+ sent by the NIS server (present in the output of apcaccess). The
+ low 16 bits are the standard APC status flag, and the upper 16 bits
+-represent the internal state of apcupsd, so the slave can see when
++represent the internal state of apcupsd, so the follower can see when
+ the power fails and know when to shutdown.
+ 
+ It would be possible to have a client also work as a server, but
+@@ -2069,23 +2069,23 @@
+ to the secondary client.
+ 
+ 
+-Differences between NIS Client/Server and the old (now removed) Master/Slave modes
+-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++Differences between NIS Client/Server and the old (now removed) Leader/Follower modes
++~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ 
+-The difference between the NIS mode and the removed master/slave
++The difference between the NIS mode and the removed leader/follower
+ mode is that the NIS server has no explicit knowledge of the
+-slaves. The NIS server makes its information available via the net
+-(NIS), and the NIS slaves read it. When the NIS server is going to
+-shutdown, it makes the information available to any NIS slave that
++followers. The NIS server makes its information available via the net
++(NIS), and the NIS followers read it. When the NIS server is going to
++shutdown, it makes the information available to any NIS follower that
+ polls it, but the NIS server does not explicitly call each NIS
+-slave as is the case in the Master/Slave networking described
++follower as is the case in the Leader/Follower networking described
+ several sections above.
+ 
+-Think of the difference as push (Master/Slave) vs. pull
+-(NIS-based). In the case of M/S, the master makes all the shutdown
+-decisions and notifies the slaves when they are to shut down or
+-when some other interesting event happens. The slaves just do
+-whatever the master says, whenever the master says to. On the other
++Think of the difference as push (Leader/Follower) vs. pull
++(NIS-based). In the case of M/S, the leader makes all the shutdown
++decisions and notifies the followers when they are to shut down or
++when some other interesting event happens. The followers just do
++whatever the leader says, whenever the leader says to. On the other
+ hand, with the NIS-based network config you basically "publish" the
+ UPS status from one server and then your clients view that status
+ and make their own decisions.
+@@ -3138,7 +3138,7 @@
+ ensure that the clients can reach it by opening up ``NISPORT``
+ (default: TCP 3551) on any firewall running on the server. You may
+ wish to configure your firewall(s) to *only* allow connections from
+-your local network or specifically from the masters, slaves, and
++your local network or specifically from the leaders, followers, and
+ servers as needed.
+ 
+ 
+@@ -3319,12 +3319,12 @@
+     device.
+ 
+ :Question:
+-    How do I ensure that the slaves shutdown before the master?
++    How do I ensure that the followers shutdown before the leader?
+ :Answer:
+-    Slaves make their shutdown decision independently from the master.
++    Followers make their shutdown decision independently from the leader.
+     Therefore you can use the ``TIMEOUT``, ``MINUTES``, and ``BATTERYLEVEL``
+-    settings in the slaves' apcupsd.conf to configure them to shut down 
+-    before the master.
++    settings in the followers' apcupsd.conf to configure them to shut down 
++    before the leader.
+     
+ :Question:
+     How do I ensure that my database server is correctly shutdown?
+@@ -3408,7 +3408,7 @@
+ *connected*
+     is 1 if apcupsd is connected to the UPS
+     via a serial port (or a USB port). In most configurations, this
+-    will be the case. In the case of a Slave machine where apcupsd is
++    will be the case. In the case of a Follower machine where apcupsd is
+     not directly connected to the UPS, this value will be 0.
+ 
+ *powered*
+@@ -3513,8 +3513,8 @@
+     *Default:* nothing
+ 
+ **remotedown**
+-    This event is generated on a slave
+-    machine when it detects either that the master has shutdown, or
++    This event is generated on a follower
++    machine when it detects either that the leader has shutdown, or
+     that a onbattery situation exists and the communications line has
+     been severed.
+ 
+@@ -3991,7 +3991,7 @@
+   attempt to autotedect by trying "private" and "public".
+   (optional, default: autodetect).
+ 
+-A NIS Server/Client (Master/Slave) configuration 
++A NIS Server/Client (Leader/Follower) configuration 
+ with multiple servers is still applicable. However, an alternative 
+ configuration is possible with an SNMP
+ enabled UPS. In this arrangement, all connected servers will be
+@@ -4418,8 +4418,8 @@
+ On some Windows systems, the
+ domain resolution does not seem to work if you have not configured
+ a DNS server in the Network section of the Control Panel. This
+-problem should be apparent only when running a slave configuration.
+-In this case, when you specify the name of the master in your
++problem should be apparent only when running a follower configuration.
++In this case, when you specify the name of the leader in your
+ apcupsd.conf file, apcupsd will be unable to resolve the name to a
+ valid IP address. To circumvent this problem, simply enter the
+ address as an IP address rather than a hostname, or alternatively,
+@@ -5022,7 +5022,7 @@
+     do not provide a battery exhausted signal (only testing can
+     determine this point). For more information, see the 
+     `Testing Apcupsd`_ section of this manual. This
+-    timer can also be useful if you want some slave machines to
++    timer can also be useful if you want some follower machines to
+     shutdown before other machines to conserve battery power. It is
+     also useful for testing apcupsd because you can force a rapid
+     shutdown by setting a small value (e.g. 60) and pulling the plug to
+@@ -5195,17 +5195,17 @@
+ The following directives apply to sharing an UPS using a ShareUPS 
+ hardware module. Most users will not use this mode.
+ 
+-**UPSCLASS** *standalone* | *shareslave* | *sharemaster*
++**UPSCLASS** *standalone* | *sharefollower* | *shareleader*
+ 
+     The default is ``standalone`` and should be used for all machines
+     powered by the UPS and having a serial port or other direct
+     connection to the UPS. This is the normal case.
+ 
+-    Use ``shareslave`` if and only if you are using a ShareUPS and
++    Use ``sharefollower`` if and only if you are using a ShareUPS and
+     connected to a BASIC Port with Simple Signal. This code is not
+     fully tested.
+ 
+-    Use ``sharemaster``, if and only if you are using a ShareUPS and
++    Use ``shareleader``, if and only if you are using a ShareUPS and
+     connected to the ADVANCED Port Smart Signal control. This code is
+     not fully tested.
+ 
+@@ -5782,19 +5782,19 @@
+ automatically reboot. In any case, your machine should have been
+ cleanly shut down.
+ 
+-Master/Slave Shutdown
+----------------------
++Leader/Follower Shutdown
++------------------------
+ 
+-In master/slave configurations, however, the master cannot be 100
+-percent sure that the slaves have all shutdown before it performs
++In leader/follower configurations, however, the leader cannot be 100
++percent sure that the followers have all shutdown before it performs
+ the power off. To avoid this situation, be sure to configure any
+-slaves (clients) to shut down before the master by setting different
++followers (clients) to shut down before the leader by setting different
+ ``TIMEOUT``, ``BATTERYLEVEL``, or ``MINUTES`` parameters in the 
+ config file.
+ 
+-Also, on a slave machine, you do not want to use the modified halt
++Also, on a follower machine, you do not want to use the modified halt
+ script since it will recall apcupsd, which will detect that it is a
+-slave (i.e. no connection to the UPS) and will complain that it
++follower (i.e. no connection to the UPS) and will complain that it
+ cannot do the killpower. This situation is not harmful just
+ annoying and possibly confusing.
+ 
+Index: examples/Makefile
+===================================================================
+--- examples/Makefile	(revision 2381)
++++ examples/Makefile	(working copy)
+@@ -3,12 +3,12 @@
+ SUBDIRS = 
+ include $(topdir)/autoconf/targets.mak
+ 
+-TARGETS = hid-ups hid-set client megaclient newslave upsapm \
++TARGETS = hid-ups hid-set client megaclient newfollower upsapm \
+           smartsim snoopdecode
+ 
+ SRCS = $(foreach target,$(TARGETS),$(target).c)
+ 
+-all-targets: client megaclient newslave upsapm smartsim snoopdecode
++all-targets: client megaclient newfollower upsapm smartsim snoopdecode
+ 
+ $(TARGETS): %: $(call SRC2OBJ,%.c) $(APCLIBS)
+ 	$(LINK)
+Index: examples/nagios_plugin_check_apcupsd.c
+===================================================================
+--- examples/nagios_plugin_check_apcupsd.c	(revision 2381)
++++ examples/nagios_plugin_check_apcupsd.c	(working copy)
+@@ -202,8 +202,8 @@
+       retVal = NAGIOS_OK;
+       strcpy(sStatus, S_NAGIOS_OK);
+    }
+-   if (iStatus & UPS_slave) {
+-      strcat(status, "SLAVE ");
++   if (iStatus & UPS_follower) {
++      strcat(status, "FOLLOWER ");
+       retVal = NAGIOS_OK;
+       strcpy(sStatus, S_NAGIOS_OK);
+    }
+Index: examples/newfollower.c
+===================================================================
+--- examples/newfollower.c	(nonexistent)
++++ examples/newfollower.c	(working copy)
+@@ -0,0 +1,251 @@
++/*
++ * Client test program for apcnisd to be used
++ * as a base for the new leader/follower code.
++ *
++ * Build it with: cc newfollower.c ../lib/libapc.a -o newclient
++ *
++ * Execute: ./newfollower [host[:port]]
++ *
++ * The two commands currently (Apr 2001) accepted by the
++ * server are "status" and "events".
++ *
++ */
++
++#include "apc.h"
++
++#ifdef HAVE_NISLIB
++
++/* Default values, can be changed on command line */
++#define SERV_TCP_PORT 3551
++#define SERV_HOST_ADDR "127.0.0.1"
++
++#define BIGBUF 4096
++char statbuf[BIGBUF];
++int statlen = BIGBUF;
++
++/* List of variables that can be read by getupsvar()
++ * First field is that name given to getupsvar(),
++ * Second field is our internal name as produced by the STATUS
++ *   output from apcupsd.
++ * Third field, if 0 returns everything to the end of the
++ *    line, and if 1 returns only to first space (e.g. integers,
++ *    and floating point values.
++ */
++static struct {
++   const char *request;
++   const char *upskeyword;
++   int nfields;
++} cmdtrans[] = {
++   {"model",      "MODEL",    0},
++   {"upsmodel",   "UPSMODEL", 0},
++   {"date",       "DATE",     0},
++   {"battcap",    "BCHARGE",  1},
++   {"mbattchg",   "MBATTCHG", 1},
++   {"battvolt",   "BATTV",    1},
++   {"nombattv",   "NOMBATTV", 1},
++   {"utility",    "LINEV",    1},
++   {"upsload",    "LOADPCT",  1},
++   {"loadpct",    "LOADPCT",  1},
++   {"outputv",    "OUTPUTV",  1},
++   {"status",     "STATFLAG", 1},
++   {"linemin",    "MINLINEV", 1},
++   {"linemax",    "MAXLINEV", 1},
++   {"upstemp",    "ITEMP",    1},
++   {"outputfreq", "LINEFREQ", 1},
++   {"translo",    "LOTRANS",  1},
++   {"transhi",    "HITRANS",  1},
++   {"runtime",    "TIMELEFT", 1},
++   {"mintimel",   "MINTIMEL", 1},
++   {"retpct",     "RETPCT",   1},          /* min batt to turn on UPS */
++   {"sense",      "SENSE",    1},
++   {"hostname",   "HOSTNAME", 1},
++   {"battdate",   "BATTDATE", 1},
++   {"serialno",   "SERIALNO", 1},
++   {"lastxfer",   "LASTXFER", 0},          /* reason for last xfer to batteries */
++   {"selftest",   "SELFTEST", 1},          /* results of last self test */
++   {"laststest",  "LASTSTEST", 0},
++   {"version",    "VERSION",  1},
++   {"upsname",    "UPSNAME",  1},
++   {"lowbatt",    "DLOWBATT", 1},          /* low battery power off delay */
++   {"battpct",    "BCHARGE",  1},
++   {"highxfer",   "HITRANS",  1},
++   {"lowxfer",    "LOTRANS",  1},
++   {"cable",      "CABLE",    0},
++   {"firmware",   "FIRMWARE", 0},
++   {NULL, NULL}
++};
++
++int fetch_data(char *host, int port);
++int getupsvar(char *host, int port, const char *request, char *answer, int anslen);
++int fill_buffer(int sockfd);
++
++extern int net_errno;
++
++void error_abort(char *msg)
++{
++   fprintf(stderr, msg);
++   exit(1);
++}
++
++int main(int argc, char *argv[])
++{
++   int port;
++   char host[200];
++   char msg[200], *p;
++   char hostname[100];
++   char release[100];
++   char upsname[100];
++   char status[100];
++
++   strcpy(host, SERV_HOST_ADDR);
++   port = SERV_TCP_PORT;
++
++   if (argc > 1) {
++      strcpy(host, argv[1]); /* get host from command line */
++      p = strchr(host, ':');
++      if (p) {
++	 *p++ = 0;
++	 port = atoi(p);
++      }
++   }
++
++   if (getupsvar(host, port, "hostname", msg, sizeof(msg)) <= 0) {
++       printf("Error getting variable\n");
++       exit(1);
++   }
++   strcpy(hostname, msg);
++
++   if (getupsvar(host, port, "version", msg, sizeof(msg)) <= 0) {
++       printf("Error getting variable\n");
++       exit(1);
++   }
++   strcpy(release, msg);
++
++   if (getupsvar(host, port, "upsname", msg, sizeof(msg)) <= 0) {
++       printf("Error getting variable\n");
++       exit(1);
++   }
++   strcpy(upsname, msg);
++
++   if (getupsvar(host, port, "status", msg, sizeof(msg)) <= 0) {
++       printf("Error getting variable\n");
++       exit(1);
++   }
++   strcpy(status, msg);
++
++   printf("For host=%s ups=%s apcupsd version=%s, the Status=%s\n",
++       hostname, upsname, release, status);
++
++   exit(0);
++}
++
++
++/*
++ * Read data into memory buffer to be used by getupsvar()
++ * Returns 0 on error
++ * Returns 1 if data fetched
++ */
++int fetch_data(char *host, int port)
++{
++   int sockfd;
++   int stat;
++
++   if ((sockfd = net_open(host, NULL, port)) < 0) {
++      printf("fetch_data: tcp_open failed for %s port %d", host, port);
++      return 0;
++   }
++
++   stat = fill_buffer(sockfd);		     /* fill statbuf */
++   net_close(sockfd);
++   return stat;
++
++}
++
++/*
++ *
++ * Returns 1 if var found
++ *   answer has var
++ * Returns 0 if variable name not found
++ *   answer has "Not found" is variable name not found
++ *   answer may have "N/A" if the UPS does not support this
++ *	 feature
++ * Returns -1 if network problem
++ *   answer has "N/A" if host is not available or network error
++ */
++int getupsvar(char *host, int port, const char *request, char *answer, int anslen)
++{
++    int i;
++    const char *stat_match = NULL;
++    char *find;
++    int nfields = 0;
++
++    if (!fetch_data(host, port)) {
++        strcpy(answer, "N/A");
++	return -1;
++    }
++
++    for (i=0; cmdtrans[i].request; i++)
++	if (!(strcmp(cmdtrans[i].request, request))) {
++	     stat_match = cmdtrans[i].upskeyword;
++	     nfields = cmdtrans[i].nfields;
++	}
++
++    if (stat_match != NULL) {
++	if ((find=strstr(statbuf, stat_match)) != NULL) {
++	     if (nfields == 1)	/* get one field */
++                 sscanf (find, "%*s %*s %s", answer);
++	     else {		/* get everything to eol */
++		 i = 0;
++		 find += 11;  /* skip label */
++                 while (*find != '\n')
++		     answer[i++] = *find++;
++		 answer[i] = 0;
++	     }
++             if (strcmp(answer, "N/A") == 0)
++		 return 0;
++	     return 1;
++	}
++    }
++
++    strcpy(answer, "Not found");
++    return 0;
++}
++
++#define MAXLINE 512
++
++/* Fill buffer with data from UPS network daemon
++ * Returns 0 on error
++ * Returns 1 if OK
++ */
++int fill_buffer(int sockfd)
++{
++   int n, stat = 1;
++   char buf[1000];
++
++   statbuf[0] = 0;
++   statlen = 0;
++   if (net_send(sockfd, "status", 6) != 6) {
++      printf("fill_buffer: write error on socket\n");
++      return 0;
++   }
++
++   while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) {
++      buf[n] = 0;
++      strcat(statbuf, buf);
++   }
++   if (n < 0)
++      stat = 0;
++
++   statlen = strlen(statbuf);
++   return stat;
++
++}
++
++#else /* HAVE_NISLIB */
++
++int main(int argc, char *argv[]) {
++    printf("Sorry, NIS code is not compiled in apcupsd.\n");
++    return 1;
++}
++
++#endif /* HAVE_NISLIB */
+Index: examples/newslave.c
+===================================================================
+--- examples/newslave.c	(revision 2381)
++++ examples/newslave.c	(nonexistent)
+@@ -1,251 +0,0 @@
+-/*
+- * Client test program for apcnisd to be used
+- * as a base for the new master/slave code.
+- *
+- * Build it with: cc newslave.c ../lib/libapc.a -o newclient
+- *
+- * Execute: ./newslave [host[:port]]
+- *
+- * The two commands currently (Apr 2001) accepted by the
+- * server are "status" and "events".
+- *
+- */
+-
+-#include "apc.h"
+-
+-#ifdef HAVE_NISLIB
+-
+-/* Default values, can be changed on command line */
+-#define SERV_TCP_PORT 3551
+-#define SERV_HOST_ADDR "127.0.0.1"
+-
+-#define BIGBUF 4096
+-char statbuf[BIGBUF];
+-int statlen = BIGBUF;
+-
+-/* List of variables that can be read by getupsvar()
+- * First field is that name given to getupsvar(),
+- * Second field is our internal name as produced by the STATUS
+- *   output from apcupsd.
+- * Third field, if 0 returns everything to the end of the
+- *    line, and if 1 returns only to first space (e.g. integers,
+- *    and floating point values.
+- */
+-static struct {
+-   const char *request;
+-   const char *upskeyword;
+-   int nfields;
+-} cmdtrans[] = {
+-   {"model",      "MODEL",    0},
+-   {"upsmodel",   "UPSMODEL", 0},
+-   {"date",       "DATE",     0},
+-   {"battcap",    "BCHARGE",  1},
+-   {"mbattchg",   "MBATTCHG", 1},
+-   {"battvolt",   "BATTV",    1},
+-   {"nombattv",   "NOMBATTV", 1},
+-   {"utility",    "LINEV",    1},
+-   {"upsload",    "LOADPCT",  1},
+-   {"loadpct",    "LOADPCT",  1},
+-   {"outputv",    "OUTPUTV",  1},
+-   {"status",     "STATFLAG", 1},
+-   {"linemin",    "MINLINEV", 1},
+-   {"linemax",    "MAXLINEV", 1},
+-   {"upstemp",    "ITEMP",    1},
+-   {"outputfreq", "LINEFREQ", 1},
+-   {"translo",    "LOTRANS",  1},
+-   {"transhi",    "HITRANS",  1},
+-   {"runtime",    "TIMELEFT", 1},
+-   {"mintimel",   "MINTIMEL", 1},
+-   {"retpct",     "RETPCT",   1},          /* min batt to turn on UPS */
+-   {"sense",      "SENSE",    1},
+-   {"hostname",   "HOSTNAME", 1},
+-   {"battdate",   "BATTDATE", 1},
+-   {"serialno",   "SERIALNO", 1},
+-   {"lastxfer",   "LASTXFER", 0},          /* reason for last xfer to batteries */
+-   {"selftest",   "SELFTEST", 1},          /* results of last self test */
+-   {"laststest",  "LASTSTEST", 0},
+-   {"version",    "VERSION",  1},
+-   {"upsname",    "UPSNAME",  1},
+-   {"lowbatt",    "DLOWBATT", 1},          /* low battery power off delay */
+-   {"battpct",    "BCHARGE",  1},
+-   {"highxfer",   "HITRANS",  1},
+-   {"lowxfer",    "LOTRANS",  1},
+-   {"cable",      "CABLE",    0},
+-   {"firmware",   "FIRMWARE", 0},
+-   {NULL, NULL}
+-};
+-
+-int fetch_data(char *host, int port);
+-int getupsvar(char *host, int port, const char *request, char *answer, int anslen);
+-int fill_buffer(int sockfd);
+-
+-extern int net_errno;
+-
+-void error_abort(char *msg)
+-{
+-   fprintf(stderr, msg);
+-   exit(1);
+-}
+-
+-int main(int argc, char *argv[])
+-{
+-   int port;
+-   char host[200];
+-   char msg[200], *p;
+-   char hostname[100];
+-   char release[100];
+-   char upsname[100];
+-   char status[100];
+-
+-   strcpy(host, SERV_HOST_ADDR);
+-   port = SERV_TCP_PORT;
+-
+-   if (argc > 1) {
+-      strcpy(host, argv[1]); /* get host from command line */
+-      p = strchr(host, ':');
+-      if (p) {
+-	 *p++ = 0;
+-	 port = atoi(p);
+-      }
+-   }
+-
+-   if (getupsvar(host, port, "hostname", msg, sizeof(msg)) <= 0) {
+-       printf("Error getting variable\n");
+-       exit(1);
+-   }
+-   strcpy(hostname, msg);
+-
+-   if (getupsvar(host, port, "version", msg, sizeof(msg)) <= 0) {
+-       printf("Error getting variable\n");
+-       exit(1);
+-   }
+-   strcpy(release, msg);
+-
+-   if (getupsvar(host, port, "upsname", msg, sizeof(msg)) <= 0) {
+-       printf("Error getting variable\n");
+-       exit(1);
+-   }
+-   strcpy(upsname, msg);
+-
+-   if (getupsvar(host, port, "status", msg, sizeof(msg)) <= 0) {
+-       printf("Error getting variable\n");
+-       exit(1);
+-   }
+-   strcpy(status, msg);
+-
+-   printf("For host=%s ups=%s apcupsd version=%s, the Status=%s\n",
+-       hostname, upsname, release, status);
+-
+-   exit(0);
+-}
+-
+-
+-/*
+- * Read data into memory buffer to be used by getupsvar()
+- * Returns 0 on error
+- * Returns 1 if data fetched
+- */
+-int fetch_data(char *host, int port)
+-{
+-   int sockfd;
+-   int stat;
+-
+-   if ((sockfd = net_open(host, NULL, port)) < 0) {
+-      printf("fetch_data: tcp_open failed for %s port %d", host, port);
+-      return 0;
+-   }
+-
+-   stat = fill_buffer(sockfd);		     /* fill statbuf */
+-   net_close(sockfd);
+-   return stat;
+-
+-}
+-
+-/*
+- *
+- * Returns 1 if var found
+- *   answer has var
+- * Returns 0 if variable name not found
+- *   answer has "Not found" is variable name not found
+- *   answer may have "N/A" if the UPS does not support this
+- *	 feature
+- * Returns -1 if network problem
+- *   answer has "N/A" if host is not available or network error
+- */
+-int getupsvar(char *host, int port, const char *request, char *answer, int anslen)
+-{
+-    int i;
+-    const char *stat_match = NULL;
+-    char *find;
+-    int nfields = 0;
+-
+-    if (!fetch_data(host, port)) {
+-        strcpy(answer, "N/A");
+-	return -1;
+-    }
+-
+-    for (i=0; cmdtrans[i].request; i++)
+-	if (!(strcmp(cmdtrans[i].request, request))) {
+-	     stat_match = cmdtrans[i].upskeyword;
+-	     nfields = cmdtrans[i].nfields;
+-	}
+-
+-    if (stat_match != NULL) {
+-	if ((find=strstr(statbuf, stat_match)) != NULL) {
+-	     if (nfields == 1)	/* get one field */
+-                 sscanf (find, "%*s %*s %s", answer);
+-	     else {		/* get everything to eol */
+-		 i = 0;
+-		 find += 11;  /* skip label */
+-                 while (*find != '\n')
+-		     answer[i++] = *find++;
+-		 answer[i] = 0;
+-	     }
+-             if (strcmp(answer, "N/A") == 0)
+-		 return 0;
+-	     return 1;
+-	}
+-    }
+-
+-    strcpy(answer, "Not found");
+-    return 0;
+-}
+-
+-#define MAXLINE 512
+-
+-/* Fill buffer with data from UPS network daemon
+- * Returns 0 on error
+- * Returns 1 if OK
+- */
+-int fill_buffer(int sockfd)
+-{
+-   int n, stat = 1;
+-   char buf[1000];
+-
+-   statbuf[0] = 0;
+-   statlen = 0;
+-   if (net_send(sockfd, "status", 6) != 6) {
+-      printf("fill_buffer: write error on socket\n");
+-      return 0;
+-   }
+-
+-   while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) {
+-      buf[n] = 0;
+-      strcat(statbuf, buf);
+-   }
+-   if (n < 0)
+-      stat = 0;
+-
+-   statlen = strlen(statbuf);
+-   return stat;
+-
+-}
+-
+-#else /* HAVE_NISLIB */
+-
+-int main(int argc, char *argv[]) {
+-    printf("Sorry, NIS code is not compiled in apcupsd.\n");
+-    return 1;
+-}
+-
+-#endif /* HAVE_NISLIB */
+Index: examples/status/Back-UPS-Pro-1000.status
+===================================================================
+--- examples/status/Back-UPS-Pro-1000.status	(revision 2381)
++++ examples/status/Back-UPS-Pro-1000.status	(working copy)
+@@ -4,7 +4,7 @@
+ RELEASE  : 3.8.1-3
+ CABLE    : Custom Cable Smart
+ MODEL    : BACK-UPS PRO 1000
+-UPSMODE  : Net Master
++UPSMODE  : Net Leader
+ STARTTIME: Thu Mar 08 11:22:12 EST 2001
+ SHARE    : NetworkUPS
+ UPSNAME  : N/A
+Index: examples/status/JapaneseUPS.status
+===================================================================
+--- examples/status/JapaneseUPS.status	(revision 2381)
++++ examples/status/JapaneseUPS.status	(working copy)
+@@ -1,10 +1,10 @@
+ APC      : 001,050,1103
+ DATE     : Mon Sep 11 13:51:14 JST 2000
+-HOSTNAME : master
++HOSTNAME : leader
+ RELEASE  : 3.7.2
+ CABLE    : Custom Cable Smart
+ MODEL    : APC Smart-UPS 1250
+-UPSMODE  : Net Master
++UPSMODE  : Net Leader
+ SHARE    : NetworkUPS
+ UPSNAME  : UPS_IDEN
+ STATUS   : ONLINE 
+Index: examples/status/PowerStack450.status
+===================================================================
+--- examples/status/PowerStack450.status	(revision 2381)
++++ examples/status/PowerStack450.status	(working copy)
+@@ -5,7 +5,7 @@
+ UPSNAME  : UPS_IDEN
+ CABLE    : Custom Cable Smart
+ MODEL    : PowerStack 450  
+-UPSMODE  : Net Master
++UPSMODE  : Net Leader
+ STARTTIME: Sun Mar 31 01:23:34 PST 2002
+ SHARE    : NetworkUPS
+ STATUS   : ONLINE 
+Index: examples/status/SmartUPS5000.status
+===================================================================
+--- examples/status/SmartUPS5000.status	(revision 2381)
++++ examples/status/SmartUPS5000.status	(working copy)
+@@ -1,10 +1,10 @@
+ APC      : 001,050,1145
+ DATE     : Tue Aug 29 13:35:43 CEST 2000
+-HOSTNAME : net-master
++HOSTNAME : net-leader
+ RELEASE  : 3.7.2
+ CABLE    : Custom Cable Smart
+ MODEL    : SMART-UPS 5000 RM
+-UPSMODE  : Net Master
++UPSMODE  : Net Leader
+ SHARE    : NetworkUPS
+ UPSNAME  : UPS_IDEN
+ STATUS   : ONLINE 
+Index: examples/status/newbackupspro2.status
+===================================================================
+--- examples/status/newbackupspro2.status	(revision 2381)
++++ examples/status/newbackupspro2.status	(working copy)
+@@ -3,7 +3,7 @@
+ RELEASE  : 3.7.2
+ CABLE    : APC Cable 940-0095A
+ MODEL    : BACK-UPS PRO 420
+-UPSMODE  : Net Master
++UPSMODE  : Net Leader
+ SHARE    : NetworkUPS
+ UPSNAME  : UPS_IDEN
+ STATUS   : ONLINE 
+Index: examples/upsapm.c
+===================================================================
+--- examples/upsapm.c	(revision 2381)
++++ examples/upsapm.c	(working copy)
+@@ -1,6 +1,6 @@
+ /*
+  * Client test program for apcnisd to be used
+- * as a base for the new master/slave code.
++ * as a base for the new leader/follower code.
+  *
+  * Build it with: cc upsapm.c ../lib/libapc.a -o newclient
+  *
+Index: examples/usb_hid_usages
+===================================================================
+--- examples/usb_hid_usages	(revision 2381)
++++ examples/usb_hid_usages	(working copy)
+@@ -1057,7 +1057,7 @@
+ 	0xD9	CurrentOutOfRange
+ 	0xDA	CurrentNotRegulated
+ 	0xDB	VoltageNotRegulated
+-	0xDC	MasterMode
++	0xDC	LeaderMode
+ 	0xDD	ChargerBattery/HostControlled
+ 	0xF0	ChargerSpecInfo
+ 	0xF1	ChargerSpecRef
+Index: include/defines.h
+===================================================================
+--- include/defines.h	(revision 2381)
++++ include/defines.h	(working copy)
+@@ -82,8 +82,8 @@
+ /* Extended bit values added by apcupsd */
+ #define UPS_commlost      0x00000100    /* Communications with UPS lost */
+ #define UPS_shutdown      0x00000200    /* Shutdown in progress */
+-#define UPS_slave         0x00000400    /* Set if this is a slave */
+-#define UPS_slavedown     0x00000800    /* Slave not responding */
++#define UPS_follower      0x00000400    /* Set if this is a follower */
++#define UPS_followerdown  0x00000800    /* Follower not responding */
+ #define UPS_onbatt_msg    0x00020000    /* Set when UPS_ONBATT message is sent */
+ #define UPS_fastpoll      0x00040000    /* Set on power failure to poll faster */
+ #define UPS_shut_load     0x00080000    /* Set when BatLoad <= percent */
+@@ -94,7 +94,7 @@
+ #define UPS_plugged       0x01000000    /* Set if computer is plugged into UPS */
+ #define UPS_battpresent   0x04000000    /* Indicates if battery is connected */
+ 
+-#define UPS_LOCAL_BITS (UPS_commlost|UPS_shutdown|UPS_slave|UPS_slavedown| \
++#define UPS_LOCAL_BITS (UPS_commlost|UPS_shutdown|UPS_follower|UPS_followerdown| \
+             UPS_onbatt_msg|UPS_fastpoll|UPS_plugged| \
+             UPS_shut_load|UPS_shut_btime|UPS_shut_ltime|UPS_shut_emerg)
+ 
+Index: include/struct.h
+===================================================================
+--- include/struct.h	(revision 2381)
++++ include/struct.h	(working copy)
+@@ -68,8 +68,8 @@
+ typedef enum {
+    NO_CLASS = 0,
+    STANDALONE,
+-   SHARESLAVE,
+-   SHAREMASTER,
++   SHAREFOLLOWER,
++   SHARELEADER,
+ } ClassMode;
+ 
+ typedef enum {
+@@ -158,8 +158,8 @@
+    void clear_shut_load() { Status &= ~UPS_shut_load; };
+    void clear_shut_ltime() { Status &= ~UPS_shut_ltime; };
+    void clear_shut_remote() { Status &= ~UPS_shut_remote; };
+-   void clear_slavedown() { Status &= ~UPS_slavedown; };
+-   void clear_slave() { Status &= ~UPS_slave; };
++   void clear_followerdown() { Status &= ~UPS_followerdown; };
++   void clear_follower() { Status &= ~UPS_follower; };
+    void clear_trim() { Status &= ~UPS_trim; };
+    void clear_battpresent() {Status &= ~UPS_battpresent; };
+ 
+@@ -190,9 +190,9 @@
+    void set_shut_ltime() { Status |= UPS_shut_ltime; };
+    void set_shut_ltime(int val) { if (val) set_shut_ltime(); else clear_shut_ltime(); };
+    void set_shut_remote() { Status |= UPS_shut_remote; };
+-   void set_slavedown() { Status |= UPS_slavedown; };
+-   void set_slavedown(int val) { if (val) set_slavedown(); else clear_slavedown(); };
+-   void set_slave() { Status |= UPS_slave; };
++   void set_followerdown() { Status |= UPS_followerdown; };
++   void set_followerdown(int val) { if (val) set_followerdown(); else clear_followerdown(); };
++   void set_follower() { Status |= UPS_follower; };
+    void set_trim() { Status |= UPS_trim; };
+    void set_trim(int val) { if (val) set_trim(); else clear_trim(); };
+    void set_battpresent() { Status |= UPS_battpresent; };
+@@ -215,8 +215,8 @@
+    bool is_shut_load() const { return (Status & UPS_shut_load) == UPS_shut_load; };
+    bool is_shut_ltime() const { return (Status & UPS_shut_ltime) == UPS_shut_ltime; };
+    bool is_shut_remote() const { return (Status & UPS_shut_remote) == UPS_shut_remote; };
+-   bool is_slave() const { return (Status & UPS_slave) == UPS_slave; };
+-   bool is_slavedown() const { return (Status & UPS_slavedown) == UPS_slavedown; };
++   bool is_follower() const { return (Status & UPS_follower) == UPS_follower; };
++   bool is_followerdown() const { return (Status & UPS_followerdown) == UPS_followerdown; };
+    bool is_trim() const { return (Status & UPS_trim) == UPS_trim; };
+    bool is_battpresent() const { return (Status & UPS_battpresent) == UPS_battpresent; };
+ 
+@@ -252,7 +252,7 @@
+    time_t last_time_annoy;
+    time_t last_time_nologon;
+    time_t last_time_changeme;
+-   time_t last_master_connect_time;     /* last time master connected */
++   time_t last_leader_connect_time;     /* last time leader connected */
+    time_t start_shut_ltime;
+    time_t start_shut_load;
+    time_t start_shut_lbatt;
+@@ -342,7 +342,7 @@
+    int eventfilemax;               /* max size of eventfile in kilobytes */
+    int event_fd;                   /* fd for eventfile */
+ 
+-   char master_name[APC_FILENAME_MAX];
++   char leader_name[APC_FILENAME_MAX];
+    char lockpath[APC_FILENAME_MAX];
+    int lockfile;
+ 
+Index: platforms/debian/packageinfo/examples
+===================================================================
+--- platforms/debian/packageinfo/examples	(revision 2381)
++++ platforms/debian/packageinfo/examples	(working copy)
+@@ -1,3 +1,3 @@
+ examples/apcupsd.conf
+-examples/apcupsd.slave.conf
+-examples/apcupsd.master.conf
++examples/apcupsd.follower.conf
++examples/apcupsd.leader.conf
+Index: platforms/etc/apcupsd.conf.in
+===================================================================
+--- platforms/etc/apcupsd.conf.in	(revision 2381)
++++ platforms/etc/apcupsd.conf.in	(working copy)
+@@ -48,7 +48,7 @@
+ #                            setting enables autodetection, which is
+ #                            the best choice for most installations.
+ #
+-# net       hostname:port    Network link to a master apcupsd through apcupsd's 
++# net       hostname:port    Network link to a leader apcupsd through apcupsd's 
+ #                            Network Information Server. This is used if the
+ #                            UPS powering your computer is connected to a 
+ #                            different computer for monitoring.
+@@ -236,7 +236,7 @@
+ # Remaining items are for ShareUPS (APC expansion card) ONLY
+ #
+ 
+-# UPSCLASS [ standalone | shareslave | sharemaster ]
++# UPSCLASS [ standalone | sharefollower | shareleader ]
+ #   Normally standalone unless you share an UPS using an APC ShareUPS
+ #   card.
+ UPSCLASS standalone
+Index: platforms/mingw/apccontrol.bat
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+Index: platforms/mingw/apcupsd.conf.in
+===================================================================
+--- platforms/mingw/apcupsd.conf.in	(revision 2381)
++++ platforms/mingw/apcupsd.conf.in	(working copy)
+@@ -49,7 +49,7 @@
+ #                            setting enables autodetection, which is
+ #                            the best choice for most installations.
+ #
+-# net       hostname:port    Network link to a master apcupsd through apcupsd's 
++# net       hostname:port    Network link to a leader apcupsd through apcupsd's 
+ #                            Network Information Server. This is used if the
+ #                            UPS powering your computer is connected to a 
+ #                            different computer for monitoring.
+@@ -227,7 +227,7 @@
+ # Remaining items are for ShareUPS (APC expansion card) ONLY
+ #
+ 
+-# UPSCLASS [ standalone | shareslave | sharemaster ]
++# UPSCLASS [ standalone | sharefollower | shareleader ]
+ #   Normally standalone unless you share an UPS using an APC ShareUPS
+ #   card.
+ UPSCLASS standalone
+Index: platforms/openbsd/README
+===================================================================
+--- platforms/openbsd/README	(revision 2381)
++++ platforms/openbsd/README	(working copy)
+@@ -19,7 +19,7 @@
+ 
+ For most operating systems, the following sequence occurs:
+         1. mains power loss
+-        2. warning messages are sent from the master at various intervals
++        2. warning messages are sent from the leader at various intervals
+         3. minimum battery level or max run time is reached
+         4. apcupsd invokes the control script with 'doshutdown' argument,
+            then exits
+@@ -36,7 +36,7 @@
+ modified to the following:
+ 
+         1. mains power loss
+-        2. warning messages are sent from the master at various intervals
++        2. warning messages are sent from the leader at various intervals
+         3. minimum battery level or max run time is reached
+         4. apcupsd sends message to UPS to power off after a configurable
+            number of seconds
+@@ -63,7 +63,7 @@
+ If the OpenBSD server is running in apcupsd networked mode with another
+ machine such as a Linux server, it is possible for the former to complete
+ the shutdown and the latter to cancel it.  Depending on which machine
+-is the master and which is the slave, this could either result in one
++is the leader and which is the follower, this could either result in one
+ machine remaining in a halted state indefinitely, or (worse) the other
+ machine losing power while not in a halted state.
+ 
+@@ -71,7 +71,7 @@
+ mode, that shutdown cancellation be disabled on all machines.
+ 
+ To date, the OpenBSD code has only been tested in standalone mode and
+-as a net master, with a Slackware Linux machine as the net slave.
++as a net leader, with a Slackware Linux machine as the net follower.
+ 
+ Modifying the Power Off Interval
+ --------------------------------
+Index: platforms/slackware/README
+===================================================================
+--- platforms/slackware/README	(revision 2381)
++++ platforms/slackware/README	(working copy)
+@@ -43,7 +43,7 @@
+ action.  If there is reference to rc.local in the rc.M script, then you
+ are probably safe.
+ 
+-If you are using the network feature (master-slave) of apcupsd and are
++If you are using the network feature (leader-follower) of apcupsd and are
+ running a DNS server locally, make sure the name server is up and running
+ before executing rc.apcupsd.  Since named is normally started out of
+ rc.inet2, this should be a non-issue.
+Index: platforms/yellowdog/apcupsd.spec.in
+===================================================================
+--- platforms/yellowdog/apcupsd.spec.in	(revision 2381)
++++ platforms/yellowdog/apcupsd.spec.in	(working copy)
+@@ -120,7 +120,6 @@
+         --enable-cgi \
+         --enable-pthreads \
+         --enable-net \
+-        --enable-master-slave \
+         --enable-apcsmart \
+         --enable-dumb \
+         --enable-usb \
+Index: src/action.c
+===================================================================
+--- src/action.c	(revision 2381)
++++ src/action.c	(working copy)
+@@ -161,10 +161,10 @@
+    }
+ 
+    /*
+-    * For network slaves, apcupsd needs to terminate here for now.
++    * For network followers, apcupsd needs to terminate here for now.
+     * This is sloppy, but it works. If you are networked, then the
+-    * master must fall also. This is required so that the UPS
+-    * can reboot the slaves.
++    * leader must fall also. This is required so that the UPS
++    * can reboot the followers.
+     */
+    if (ok == 3)
+       sendsig_terminate();
+@@ -210,7 +210,7 @@
+    make_file(ups, ups->pwrfailpath);
+    prohibit_logins(ups);
+ 
+-   if (!ups->is_slave()) {
++   if (!ups->is_follower()) {
+       /*
+        * Note, try avoid using this option if at all possible
+        * as it will shutoff the UPS power, and you cannot
+@@ -485,7 +485,7 @@
+       /* shutdown requested but still running */
+       if (ups->is_shutdown()) {
+          if (ups->killdelay && now - ups->ShutDown >= ups->killdelay) {
+-            if (!ups->is_slave())
++            if (!ups->is_follower())
+                initiate_hibernate(ups);
+             ups->ShutDown = now;   /* wait a bit before doing again */
+             ups->set_shutdown();
+Index: src/cgi/multimon.c
+===================================================================
+--- src/cgi/multimon.c	(revision 2381)
++++ src/cgi/multimon.c	(working copy)
+@@ -85,7 +85,7 @@
+         { "CAL",        "CALIBRATION",          1       },
+         { "CL",         "COMM LOST",            2       },
+         { "SD",         "SHUTTING DOWN",        2       },
+-        { "SLAVE",      "SLAVE",                0       },
++        { "FOLLOWER",      "FOLLOWER",                0       },
+         { NULL,         NULL,                   0       }
+ };
+ 
+@@ -185,8 +185,8 @@
+        strcat(status, "CL ");
+     if (ups_status & UPS_shutdown)
+        strcat(status, "SD ");
+-    if (ups_status & UPS_slave)
+-       strcat(status, "SLAVE ");
++    if (ups_status & UPS_follower)
++       strcat(status, "FOLLOWER ");
+ 
+     stat = strtok (status, " ");
+     while (stat != NULL) {  
+Index: src/cgi/upsstats.c
+===================================================================
+--- src/cgi/upsstats.c	(revision 2381)
++++ src/cgi/upsstats.c	(working copy)
+@@ -298,8 +298,8 @@
+              fputs("COMM LOST ", stdout); 
+          if (status & UPS_shutdown)
+              fputs("SHUTDOWN ", stdout);
+-         if (status & UPS_slave)
+-             fputs("SLAVE ", stdout);
++         if (status & UPS_follower)
++             fputs("FOLLOWER ", stdout);
+          if (!(status & UPS_battpresent))
+              fputs("NOBATT ", stdout);
+          fputs ("\n", stdout); 
+Index: src/device.c
+===================================================================
+--- src/device.c	(revision 2381)
++++ src/device.c	(working copy)
+@@ -99,9 +99,9 @@
+            "ignored at %s:%d\n", ups->pwrfailpath, __FILE__, __LINE__);
+    } else {
+       /* We are on batteries, so do the kill_power */
+-      if (ups->upsclass.type == SHAREMASTER) {
++      if (ups->upsclass.type == SHARELEADER) {
+          log_event(ups, LOG_WARNING,
+-            "Waiting 30 seconds for slave(s) to shutdown.");
++            "Waiting 30 seconds for follower(s) to shutdown.");
+          sleep(30);
+       }
+ 
+@@ -111,11 +111,11 @@
+ 
+       log_event(ups, LOG_WARNING, "Attempting to kill the UPS power!");
+ 
+-      if (ups->upsclass.type == SHARESLAVE) {
++      if (ups->upsclass.type == SHAREFOLLOWER) {
+          sleep(10);
+-         log_event(ups, LOG_WARNING, "Waiting For ShareUPS Master to shutdown");
++         log_event(ups, LOG_WARNING, "Waiting For ShareUPS Leader to shutdown");
+          sleep(60);
+-         log_event(ups, LOG_WARNING, "Failed to have power killed by Master!");
++         log_event(ups, LOG_WARNING, "Failed to have power killed by Leader!");
+ 
+          /*
+           * ***FIXME*** this really should not do a reboot here,
+Index: src/drivers/apcsmart/smartsetup.c
+===================================================================
+--- src/drivers/apcsmart/smartsetup.c	(revision 2381)
++++ src/drivers/apcsmart/smartsetup.c	(working copy)
+@@ -123,7 +123,7 @@
+    char a = 'Y';
+ 
+    if (_ups->fd == -1)
+-      return 1;                    /* we must be a slave */
++      return 1;                    /* we must be a follower */
+ 
+    /* Have to clear RTS line to access the serial cable mode PnP on BKPro */
+    /* Shouldn't hurt on other cables, so just do it all the time. */
+Index: src/drivers/dumb/dumbsetup.c
+===================================================================
+--- src/drivers/dumb/dumbsetup.c	(revision 2381)
++++ src/drivers/dumb/dumbsetup.c	(working copy)
+@@ -88,7 +88,7 @@
+    tcsetattr(_ups->fd, TCSANOW, &_newtio);
+    tcflush(_ups->fd, TCIFLUSH);
+ 
+-   _ups->clear_slave();
++   _ups->clear_follower();
+ 
+    return 1;
+ }
+Index: src/drivers/modbus/ModbusComm.cpp
+===================================================================
+--- src/drivers/modbus/ModbusComm.cpp	(revision 2381)
++++ src/drivers/modbus/ModbusComm.cpp	(working copy)
+@@ -128,8 +128,8 @@
+    if (txsz > MODBUS_MAX_PDU_SZ || rxsz > MODBUS_MAX_PDU_SZ)
+       return false;
+ 
+-   // Prepend slave address and function code
+-   txfrm[0] = _slaveaddr;
++   // Prepend follower address and function code
++   txfrm[0] = _followeraddr;
+    txfrm[1] = fc;
+ 
+    // Add PDU
+@@ -173,11 +173,11 @@
+          continue;
+       }
+ 
+-      if (rxfrm[0] != _slaveaddr)
++      if (rxfrm[0] != _followeraddr)
+       {
+-         // Not from expected slave: Retry
++         // Not from expected follower: Retry
+          Dmsg(0, "%s: Bad address (exp=%u, rx=%u)\n", 
+-            __func__, _slaveaddr, rxfrm[0]);
++            __func__, _followeraddr, rxfrm[0]);
+          continue;
+       }
+ 
+Index: src/drivers/modbus/ModbusComm.h
+===================================================================
+--- src/drivers/modbus/ModbusComm.h	(revision 2381)
++++ src/drivers/modbus/ModbusComm.h	(working copy)
+@@ -30,8 +30,8 @@
+ class ModbusComm
+ {
+ public:
+-   ModbusComm(uint8_t slaveaddr = DEFAULT_SLAVE_ADDR) : 
+-      _slaveaddr(slaveaddr), _open(false) {}
++   ModbusComm(uint8_t followeraddr = DEFAULT_FOLLOWER_ADDR) : 
++      _followeraddr(followeraddr), _open(false) {}
+    virtual ~ModbusComm() {}
+ 
+    virtual bool Open(const char *dev) = 0;
+@@ -45,7 +45,7 @@
+    uint16_t ModbusCrc(const uint8_t *data, unsigned int sz);
+ 
+    // MODBUS constants
+-   static const uint8_t DEFAULT_SLAVE_ADDR = 1;
++   static const uint8_t DEFAULT_FOLLOWER_ADDR = 1;
+ 
+    // MODBUS timeouts
+    static const unsigned int MODBUS_INTERCHAR_TIMEOUT_MS = 25; // Spec is 15, increase for compatibility with USB serial dongles
+@@ -69,7 +69,7 @@
+    virtual bool ModbusTx(const ModbusFrame *frm, unsigned int sz) = 0;
+    virtual bool ModbusRx(ModbusFrame *frm, unsigned int *sz) = 0;
+ 
+-   uint8_t _slaveaddr;
++   uint8_t _followeraddr;
+    bool _open;
+ 
+ private:
+Index: src/drivers/modbus/ModbusRs232Comm.cpp
+===================================================================
+--- src/drivers/modbus/ModbusRs232Comm.cpp	(revision 2381)
++++ src/drivers/modbus/ModbusRs232Comm.cpp	(working copy)
+@@ -44,8 +44,8 @@
+ #define O_BINARY 0
+ #endif
+ 
+-ModbusRs232Comm::ModbusRs232Comm(uint8_t slaveaddr) :
+-   ModbusComm(slaveaddr),
++ModbusRs232Comm::ModbusRs232Comm(uint8_t followeraddr) :
++   ModbusComm(followeraddr),
+    _fd(-1)
+ {
+ }
+Index: src/drivers/modbus/ModbusRs232Comm.h
+===================================================================
+--- src/drivers/modbus/ModbusRs232Comm.h	(revision 2381)
++++ src/drivers/modbus/ModbusRs232Comm.h	(working copy)
+@@ -30,7 +30,7 @@
+ class ModbusRs232Comm: public ModbusComm
+ {
+ public:
+-   ModbusRs232Comm(uint8_t slaveaddr = DEFAULT_SLAVE_ADDR);
++   ModbusRs232Comm(uint8_t followeraddr = DEFAULT_FOLLOWER_ADDR);
+    virtual ~ModbusRs232Comm() {}
+ 
+    virtual bool Open(const char *dev);
+Index: src/drivers/modbus/ModbusUsbComm.cpp
+===================================================================
+--- src/drivers/modbus/ModbusUsbComm.cpp	(revision 2381)
++++ src/drivers/modbus/ModbusUsbComm.cpp	(working copy)
+@@ -42,8 +42,8 @@
+ #define ModbusRTURx 0xFF8600FC
+ #define ModbusRTUTx 0xFF8600FD
+ 
+-ModbusUsbComm::ModbusUsbComm(uint8_t slaveaddr) :
+-   ModbusComm(slaveaddr)
++ModbusUsbComm::ModbusUsbComm(uint8_t followeraddr) :
++   ModbusComm(followeraddr)
+ {
+ }
+ 
+@@ -178,13 +178,13 @@
+       {
+          // READ_HOLDING_REGS response includes a size byte.
+          // Add 3 bytes to PDU size to account for size byte itself 
+-         // plus frame header (slaveaddr and op code).
++         // plus frame header (followeraddr and op code).
+          frmsz = rpt[3] + 3;
+       }
+       else if (rpt[2] == MODBUS_FC_WRITE_MULTIPLE_REGS)
+       {
+          // WRITE_MULTIPLE_REGS response is always a fixed length
+-         // 2 byte frame header (slaveaddr and op code)
++         // 2 byte frame header (followeraddr and op code)
+          // 2 byte register starting address
+          // 2 byte register count
+          frmsz = 6;
+Index: src/drivers/modbus/ModbusUsbComm.h
+===================================================================
+--- src/drivers/modbus/ModbusUsbComm.h	(revision 2381)
++++ src/drivers/modbus/ModbusUsbComm.h	(working copy)
+@@ -31,7 +31,7 @@
+ class ModbusUsbComm: public ModbusComm
+ {
+ public:
+-   ModbusUsbComm(uint8_t slaveaddr = DEFAULT_SLAVE_ADDR);
++   ModbusUsbComm(uint8_t followeraddr = DEFAULT_FOLLOWER_ADDR);
+    virtual ~ModbusUsbComm() {}
+ 
+    virtual bool Open(const char *dev);
+Index: src/drivers/net/net.c
+===================================================================
+--- src/drivers/net/net.c	(revision 2381)
++++ src/drivers/net/net.c	(working copy)
+@@ -294,7 +294,7 @@
+    char answer[200];
+    int stat = 1;
+    int32_t newStatus;              /* this really should be uint32_t! */
+-   int32_t masterStatus;           /* status from master */
++   int32_t leaderStatus;           /* status from leader */
+ 
+    if (!_got_caps) {
+       get_capabilities();
+@@ -322,20 +322,20 @@
+    if (!getupsvar("status", answer, sizeof(answer))) {
+       Dmsg(100, "HEY!!! Couldn't get status flag.\n");
+       stat = 0;
+-      masterStatus = 0;
++      leaderStatus = 0;
+    } else {
+       /*
+        * Make sure we don't override local bits, and that
+        * all non-local bits are set/cleared correctly.
+        *
+-       * local bits = UPS_commlost|UPS_shutdown|UPS_slave|UPS_slavedown|
++       * local bits = UPS_commlost|UPS_shutdown|UPS_follower|UPS_followerdown|
+        *              UPS_prev_onbatt|UPS_prev_battlow|UPS_onbatt_msg|
+        *              UPS_fastpoll|UPS_plugged|UPS_dev_setup
+        */
+ 
+       /* First transfer set or not set all non-local bits */
+-      masterStatus = strtol(answer, NULL, 0);
+-      newStatus = masterStatus & ~UPS_LOCAL_BITS;  /* clear local bits */
++      leaderStatus = strtol(answer, NULL, 0);
++      newStatus = leaderStatus & ~UPS_LOCAL_BITS;  /* clear local bits */
+       _ups->Status &= UPS_LOCAL_BITS;               /* clear non-local bits */
+       _ups->Status |= newStatus;                    /* set new non-local bits */
+ 
+@@ -343,20 +343,20 @@
+        * Now set any special bits, note this is set only, we do
+        * not clear these bits, but let our own core code clear them
+        */
+-      newStatus = masterStatus & (UPS_commlost | UPS_fastpoll);
++      newStatus = leaderStatus & (UPS_commlost | UPS_fastpoll);
+       _ups->Status |= newStatus;
+    }
+ 
+    Dmsg(100, "Got Status = %s 0x%x\n", answer, _ups->Status);
+ 
+-   if (masterStatus & UPS_shutdown && !_ups->is_shut_remote()) {
+-      _ups->set_shut_remote();    /* if master is shutting down so do we */
+-      log_event(_ups, LOG_ERR, "Shutdown because NIS master is shutting down.");
+-      Dmsg(100, "Set SHUT_REMOTE because of master status.\n");
++   if (leaderStatus & UPS_shutdown && !_ups->is_shut_remote()) {
++      _ups->set_shut_remote();    /* if leader is shutting down so do we */
++      log_event(_ups, LOG_ERR, "Shutdown because NIS leader is shutting down.");
++      Dmsg(100, "Set SHUT_REMOTE because of leader status.\n");
+    }
+ 
+    /*
+-    * If we lost connection with master and we
++    * If we lost connection with leader and we
+     * are running on batteries, shutdown on the fourth
+     * consequtive pass here. While on batteries, this code
+     * is called once per second.
+@@ -365,7 +365,7 @@
+       if (_comm_loss++ == 4 && !_ups->is_shut_remote()) {
+          _ups->set_shut_remote();
+          log_event(_ups, LOG_ERR,
+-            "Shutdown because loss of comm with NIS master while on batteries.");
++            "Shutdown because loss of comm with NIS leader while on batteries.");
+          Dmsg(100, "Set SHUT_REMOTE because of loss of comm on batteries.\n");
+       }
+    } else {
+@@ -380,8 +380,8 @@
+ bool NetUpsDriver::Open()
+ {
+    strlcpy(_device, _ups->device, sizeof(_device));
+-   strlcpy(_ups->master_name, _ups->device, sizeof(_ups->master_name));
+-   strlcpy(_ups->upsclass.long_name, "Net Slave", sizeof(_ups->upsclass.long_name));
++   strlcpy(_ups->leader_name, _ups->device, sizeof(_ups->leader_name));
++   strlcpy(_ups->upsclass.long_name, "Net Follower", sizeof(_ups->upsclass.long_name));
+ 
+    /* Now split the device. */
+    _hostname = _device;
+@@ -478,11 +478,11 @@
+       return 0;
+ 
+    write_lock(_ups);
+-   _ups->set_slave();
++   _ups->set_follower();
+ 
+    /* ***FIXME**** poll time needs to be scanned */
+    _ups->poll_time = time(NULL);
+-   _ups->last_master_connect_time = _ups->poll_time;
++   _ups->last_leader_connect_time = _ups->poll_time;
+ 
+    if (GETVAR(CI_VLINE, "utility"))
+       _ups->LineVoltage = atof(answer);
+Index: src/drivers/pcnet/pcnet.c
+===================================================================
+--- src/drivers/pcnet/pcnet.c	(revision 2381)
++++ src/drivers/pcnet/pcnet.c	(working copy)
+@@ -674,9 +674,9 @@
+ 
+    /*
+     * Note, we set _ups->fd here so the "core" of apcupsd doesn't
+-    * think we are a slave, which is what happens when it is -1.
++    * think we are a follower, which is what happens when it is -1.
+     * (ADK: Actually this only appears to be true for apctest as
+-    * apcupsd proper uses the UPS_slave flag.)
++    * apcupsd proper uses the UPS_follower flag.)
+     * Internally, we use the fd in our own private space
+     */
+    _ups->fd = 1;
+Index: src/drivers/snmplite/apc-oids.h
+===================================================================
+--- src/drivers/snmplite/apc-oids.h	(revision 2381)
++++ src/drivers/snmplite/apc-oids.h	(working copy)
+@@ -230,7 +230,7 @@
+ __UNUSED__ static int upsDiagIMType[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 2, -1};
+ __UNUSED__ static int upsDiagIMStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 3, -1};
+ __UNUSED__ static int upsDiagIMFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 4, -1};
+-__UNUSED__ static int upsDiagIMSlaveFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 5, -1};
++__UNUSED__ static int upsDiagIMFollowerFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 5, -1};
+ __UNUSED__ static int upsDiagIMHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 6, -1};
+ __UNUSED__ static int upsDiagIMSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 7, -1};
+ __UNUSED__ static int upsDiagIMManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 8, -1};
+Index: src/drivers/test/testdriver.c
+===================================================================
+--- src/drivers/test/testdriver.c	(revision 2381)
++++ src/drivers/test/testdriver.c	(working copy)
+@@ -57,7 +57,7 @@
+    if (!open_test_device())
+       Error_abort("Cannot open UPS device %s\n", _ups->device);
+ 
+-   _ups->clear_slave();
++   _ups->clear_follower();
+    write_unlock(_ups);
+    return true;
+ }
+Index: src/drivers/usb/bsd/bsd-usb.c
+===================================================================
+--- src/drivers/usb/bsd/bsd-usb.c	(revision 2381)
++++ src/drivers/usb/bsd/bsd-usb.c	(working copy)
+@@ -170,9 +170,9 @@
+ 
+    /*
+     * Note, we set _ups->fd here so the "core" of apcupsd doesn't
+-    * think we are a slave, which is what happens when it is -1.
++    * think we are a follower, which is what happens when it is -1.
+     * (ADK: Actually this only appears to be true for apctest as
+-    * apcupsd proper uses the UPS_slave flag.)
++    * apcupsd proper uses the UPS_follower flag.)
+     * Internally, we use the fd in our own private space   
+     */
+    _ups->fd = 1;
+@@ -693,7 +693,7 @@
+ 
+    bool rc = open_usb_device();
+ 
+-   _ups->clear_slave();
++   _ups->clear_follower();
+    write_unlock(_ups);
+    return rc;
+ }
+Index: src/drivers/usb/generic/generic-usb.c
+===================================================================
+--- src/drivers/usb/generic/generic-usb.c	(revision 2381)
++++ src/drivers/usb/generic/generic-usb.c	(working copy)
+@@ -460,14 +460,14 @@
+ 
+    /*
+     * Note, we set _ups->fd here so the "core" of apcupsd doesn't
+-    * think we are a slave, which is what happens when it is -1.
++    * think we are a follower, which is what happens when it is -1.
+     * (ADK: Actually this only appears to be true for apctest as
+-    * apcupsd proper uses the UPS_slave flag.)
++    * apcupsd proper uses the UPS_follower flag.)
+     * Internally, we use the fd in our own private space   
+     */
+    _ups->fd = 1;
+ 
+-   _ups->clear_slave();
++   _ups->clear_follower();
+    write_unlock(_ups);
+    return rc;
+ }
+Index: src/drivers/usb/linux/linux-usb.c
+===================================================================
+--- src/drivers/usb/linux/linux-usb.c	(revision 2381)
++++ src/drivers/usb/linux/linux-usb.c	(working copy)
+@@ -213,9 +213,9 @@
+ 
+    /*
+     * Note, we set _ups->fd here so the "core" of apcupsd doesn't
+-    * think we are a slave, which is what happens when it is -1.
++    * think we are a follower, which is what happens when it is -1.
+     * (ADK: Actually this only appears to be true for apctest as
+-    * apcupsd proper uses the UPS_slave flag.)
++    * apcupsd proper uses the UPS_follower flag.)
+     * Internally, we use the fd in our own private space   
+     */
+    _ups->fd = 1;
+@@ -642,7 +642,7 @@
+ 
+    bool rc = open_usb_device();
+ 
+-   _ups->clear_slave();
++   _ups->clear_follower();
+    write_unlock(_ups);
+    return rc;
+ }
+Index: src/gapcmon/gapcmon.c
+===================================================================
+--- src/gapcmon/gapcmon.c	(revision 2381)
++++ src/gapcmon/gapcmon.c	(working copy)
+@@ -4741,7 +4741,7 @@
+ 
+ /*
+  * GConf2 routine
+- * Handles changes to prefs_model, or the master list of monitors in the preferences page.
++ * Handles changes to prefs_model, or the leader list of monitors in the preferences page.
+  * Triggers for this routine should not be installed until after the 
+  * control panel has been created. 
+ */
+Index: src/lib/apcconfig.c
+===================================================================
+--- src/lib/apcconfig.c	(revision 2381)
++++ src/lib/apcconfig.c	(working copy)
+@@ -80,8 +80,8 @@
+ 
+ static const GENINFO upsclasses[] = {
+    { "standalone",     "Stand Alone",           STANDALONE },
+-   { "shareslave",     "ShareUPS Slave",        SHARESLAVE },
+-   { "sharemaster",    "ShareUPS Master",       SHAREMASTER },
++   { "sharefollower",     "ShareUPS Follower",  SHAREFOLLOWER },
++   { "shareleader",    "ShareUPS Leader",       SHARELEADER },
+    { NULL,             "*invalid-ups-class*",   NO_CLASS },
+ };
+ 
+@@ -190,7 +190,7 @@
+     */
+    {"CONTROL",    obsolete, TRUE,  (GENINFO *)"CONTROL config directive is obsolete"   },
+    {"NETACCESS",  obsolete, TRUE,  (GENINFO *)"NETACCESS config directive is obsolete" },
+-   {"MASTER",     obsolete, TRUE,  (GENINFO *)"MASTER config directive is obsolete"    },
++   {"LEADER",     obsolete, TRUE,  (GENINFO *)"LEADER config directive is obsolete"    },
+    {"USERMAGIC",  obsolete, FALSE, (GENINFO *)"USERMAGIC config directive is obsolete" },
+    {"SLAVE",      obsolete, FALSE, (GENINFO *)"SLAVE config directive is obsolete"     },
+    {"NETPORT",    obsolete, FALSE, (GENINFO *)"NETPORT config directive is obsolete"   },
+@@ -681,7 +681,7 @@
+    if (ups->annoy >= ups->annoydelay)
+       ups->annoydelay = 0;
+ 
+-   if (ups->sharenet.type == SHAREMASTER) {
++   if (ups->sharenet.type == SHARELEADER) {
+       ups->maxtime = 0;
+       ups->percent = 10;
+       ups->runtime = 5;
+Index: src/lib/apcexec.c
+===================================================================
+--- src/lib/apcexec.c	(revision 2381)
++++ src/lib/apcexec.c	(working copy)
+@@ -107,13 +107,13 @@
+       asnprintf(cmdline, sizeof(cmdline), 
+          "\"%s\" /E:4096 /c \"%s%s\" %s \"%s\" %d %d \"%s\"",
+          comspec, ups->scriptdir, APCCONTROL_FILE, cmd.command,
+-         ups->upsname, !ups->is_slave(), ups->is_plugged(), sbindir);
++         ups->upsname, !ups->is_follower(), ups->is_plugged(), sbindir);
+    } else {
+       /* WinNT/2K/Vista need quotes around the entire sub-command */
+       asnprintf(cmdline, sizeof(cmdline), 
+          "\"%s\" /c \"\"%s%s\" %s \"%s\" %d %d \"%s\"\"",
+          comspec, ups->scriptdir, APCCONTROL_FILE, cmd.command,
+-         ups->upsname, !ups->is_slave(), ups->is_plugged(), sbindir);
++         ups->upsname, !ups->is_follower(), ups->is_plugged(), sbindir);
+    }
+ 
+    /* Initialize the STARTUPINFOA struct to hide the console window */
+@@ -165,7 +165,7 @@
+       return SUCCESS;
+    }
+ 
+-   asnprintf(connected, sizeof(connected), "%d", !ups->is_slave());
++   asnprintf(connected, sizeof(connected), "%d", !ups->is_follower());
+    asnprintf(powered, sizeof(powered), "%d", (int)ups->is_plugged());
+    asnprintf(apccontrol, sizeof(apccontrol), "%s%s", ups->scriptdir, APCCONTROL_FILE);
+ 
+Index: src/lib/apcstatus.c
+===================================================================
+--- src/lib/apcstatus.c	(revision 2381)
++++ src/lib/apcstatus.c	(working copy)
+@@ -49,7 +49,7 @@
+     */
+    read_lock(ups);
+ 
+-   if (ups->poll_time == 0)        /* this is always zero on slave */
++   if (ups->poll_time == 0)        /* this is always zero on follower */
+       ups->poll_time = now;
+ 
+    /* put the last UPS poll time on the DATE record */
+@@ -73,16 +73,16 @@
+    if (ups->sharenet.type != DISABLE)
+       s_write(ups, "SHARE    : %s\n", ups->sharenet.long_name);
+ 
+-   /* If slave, send last update time/date from master */
+-   if (ups->is_slave()) {    /* we must be a slave */
+-      if (ups->last_master_connect_time == 0) {
+-         s_write(ups, "MASTERUPD: No connection to Master\n");
++   /* If follower, send last update time/date from leader */
++   if (ups->is_follower()) {    /* we must be a follower */
++      if (ups->last_leader_connect_time == 0) {
++         s_write(ups, "LEADERUPD: No connection to Leader\n");
+       } else {
+-         format_date(ups->last_master_connect_time, datetime, sizeof(datetime));
+-         s_write(ups, "MASTERUPD: %s\n", datetime);
++         format_date(ups->last_leader_connect_time, datetime, sizeof(datetime));
++         s_write(ups, "LEADERUPD: %s\n", datetime);
+       }
+ 
+-      s_write(ups, "MASTER   : %s\n", ups->master_name);
++      s_write(ups, "LEADER   : %s\n", ups->leader_name);
+    }
+ 
+    if (ups->UPS_Cap[CI_UPSMODEL])
+@@ -118,11 +118,11 @@
+    if (!ups->is_battpresent())
+       strlcat(status, "NOBATT ", sizeof(status));
+ 
+-   if (ups->is_slave())
+-      strlcat(status, "SLAVE ", sizeof(status));
++   if (ups->is_follower())
++      strlcat(status, "FOLLOWER ", sizeof(status));
+ 
+-   if (ups->is_slavedown())
+-      strlcat(status, "SLAVEDOWN", sizeof(status));
++   if (ups->is_followerdown())
++      strlcat(status, "FOLLOWERDOWN", sizeof(status));
+ 
+    /* These override the above */
+    if (ups->is_commlost())
diff --git a/gnu/packages/power.scm b/gnu/packages/power.scm
index 843a907aa5..cfa3edcab8 100644
--- a/gnu/packages/power.scm
+++ b/gnu/packages/power.scm
@@ -32,7 +32,9 @@ (define-public apcupsd
                 "/" name "-" version ".tar.gz"))
               (sha256
                (base32
-                "0rwqiyzlg9p0szf3x6q1ppvrw6f6dbpn2rc5z623fk3bkdalhxyv"))))
+                "0rwqiyzlg9p0szf3x6q1ppvrw6f6dbpn2rc5z623fk3bkdalhxyv"))
+              (patch-flags '("-p0"))
+              (patches (search-patches "apcupsd-leader-follower.patch"))))
     (outputs '("out" "doc"))
     (build-system gnu-build-system)
     (arguments
diff --git a/gnu/services/power.scm b/gnu/services/power.scm
index 72b2a40fef..3eeb5318f6 100644
--- a/gnu/services/power.scm
+++ b/gnu/services/power.scm
@@ -253,7 +253,7 @@ (define-enum cable '( simple smart ether usb
                       940-0095A 940-0095B 940-0095C 940-0625A MAM-04-02-2000))
 (define-enum type '(apcsmart usb net snmp netsnmp dumb pcnet modbus test))
 (define-enum no-logon '(disable timeout percent minutes always))
-(define-enum class '(standalone shareslave sharemaster))
+(define-enum class '(standalone sharefollower shareleader))
 (define-enum mode '(disable share))
 
 (define-configuration apcupsd-configuration
@@ -315,7 +315,7 @@ (define-configuration apcupsd-configuration
 Most new UPSes are an USB.
 
 @item net
-Network link to a master apcupsd through apcupsd's Network Information Server.
+Network link to a leader apcupsd through apcupsd's Network Information Server.
 This is used if the UPS powering your computer is connected to a different
 computer for monitoring.

base-commit: 8c483c12e94bcf43e4c44170f1d5fea5fbba4970
prerequisite-patch-id: 42f60b7b8949c7d41d47f400576627b868cfdacb
prerequisite-patch-id: 9c6033a9adb2f18f01259f4e0152d8b442e64edd
-- 
2.48.1

Thank you for your patience!

-- 
Thanks,
Maxim