Desc: Network protocol info
File: protocol.txt
Date: 9 May 2003
Auth: Russell Kroll <rkroll@exploits.org>

This protocol primarily runs over TCP, but there is some lingering
support for UDP.  UDP support may be removed completely if there is no
interest.  All clients shipped with the package use upsclient and
therefore TCP exclusively.

As of May 2002, this protocol now has an official port number from IANA,
which is 3493.  The old number (3305) was a relic of the original code's
ancestry, and conflicted with other services.  Version 0.50.0 and up
use 3493 by default.

============================================================================
New commands (April 2003)
============================================================================

These commands were added to support the new long variable names.  They
do not recognize the older names, and will not perform any sort of
"mapping".  If you need to do something with an old variable name, use
the older commands below.

The big difference to note here is that the notion of "@upsname" is
gone.  The upsname is now a required part of many commands, and there is
no "default" UPS for any of these new commands.  This was done to remove
ambiguity and to clean up a lot of ugly code in the server.

Multi-word elements are contained within "quotes" for easier parsing.  
Embedded quotes are escaped with backslashes.  Embedded backslashes are
also escaped by representing them as \\.  This protocol is intended to
be interpreted with parseconf or something similar.

GET
===

Retrieve a single response from the server.  This is the only new
command which will work over UDP.

Possible sub-commands:

NUMLOGINS
---------

    Form: GET NUMLOGINS <upsname>
          GET NUMLOGINS su700

Response: NUMLOGINS <upsname> <value>
          NUMLOGINS su700 1

<value> is the number of clients which have done LOGIN for this UPS.
This is used by the master upsmon to determine how many clients are
still connected when starting the shutdown process.

This replaces the old "REQ NUMLOGINS" command.

UPSDESC
-------

    Form: GET UPSDESC <upsname>
          GET UPSDESC su700

Response: UPSDESC <upsname> "<description>"
          UPSDESC su700 "Development box"

<description> is the value of "desc=" from ups.conf for this UPS.  If it
is not set, upsd will return "Unavailable".

This can be used to provide human-readable descriptions instead of a
cryptic "upsname@hostname" string.

VAR
---

    Form: GET VAR <upsname> <varname>
          GET VAR su700 ups.status

Response: VAR <upsname> <varname> "<value>"
          VAR su700 ups.status "OL"

This replaces the old "REQ" command.

TYPE
----

    Form: GET TYPE <upsname> <varname>
          GET TYPE su700 input.transfer.low

Response: TYPE <upsname> <varname> <type>...
          TYPE su700 input.transfer.low ENUM

<type> can be several values, and multiple words may be returned:

      RW - this variable may be set to another value with SET
    ENUM - an enumerated type, which supports a few specific values
STRING:n - this is a string of maximum length n

ENUM and STRING are usually associated with RW, but not always.

This replaces the old "VARTYPE" command.

DESC
----

    Form: GET DESC <upsname> <varname>
          GET DESC su700 ups.status

Response: DESC <upsname> <varname> "<description>"
          DESC su700 ups.status "UPS status"

<description> is a string that gives a brief explanation of the named
variable.  upsd may return "Unavailable" if the file which provides this
description is not installed.

Different versions of this file may be used in some situations to
provide for localization and internationalization.

This replaces the old "VARDESC" command.

CMDDESC
-------

    Form: GET CMDDESC <upsname> <cmdname>
          GET CMDDESC su700 load.on

Response: CMDDESC <upsname> <cmdname> "<description>"
          CMDDESC su700 load.on "Turn on the load immediately"

This is like DESC above, but it applies to the instant commands.

This replaces the old "INSTCMDDESC" command.

LIST
====

The LIST functions all share a common container format.  They will
return "BEGIN LIST" and then repeat the initial query.  The list then
follows, with as many lines are necessary to convey it.  "END LIST" with
the initial query attached then follows.

The formatting may seem a bit redundant, but it makes a different form
of client possible.  You can send a LIST query and then go off and wait
for it to get back to you.  When it arrives, you don't need complicated
state machines to remember which list is which.

UPS
---

    Form: LIST UPS

Response: BEGIN LIST UPS
          UPS <upsname> "<description>"
          ...
          END LIST UPS

	  BEGIN LIST UPS
	  UPS su700 "Development box"
	  END LIST UPS

<upsname> is a name from ups.conf, and <description> is the value of
desc= from ups.conf, if available.  It will be set to "Unavailable"
otherwise.

This can be used to determine what values of <upsname> are valid before
calling other functions on the server.  This is also a good way to
handle situations where a single upsd supports multiple drivers.

Clients performing a "UPS discovery" process may find this useful.

VAR
---

    Form: LIST VAR <upsname>
          LIST VAR su700

Response: BEGIN LIST VAR <upsname>
 	  VAR <upsname> <varname> "<value>"
	  ...
	  END LIST VAR <upsname>

	  BEGIN LIST VAR su700
	  VAR su700 ups.mfr "APC"
	  VAR su700 ups.mfr.date "10/17/96"
	  ...
	  END LIST VAR su700

This replaces the old "LISTVARS" command.

RW
--

    Form: LIST RW <upsname>
          LIST RW su700

Response: BEGIN LIST RW <upsname>
          RW <upsname> <varname> "<value>"
	  ...
	  END LIST RW <upsname>

	  BEGIN LIST RW su700
	  RW su700 output.voltage.target.battery "115"
	  RW su700 ups.delay.shutdown "020"
	  ...
	  END LIST RW su700

This replaces the old "LISTRW" command.

CMD
---

    Form: LIST CMD <upsname>
          LIST CMD su700

Response: BEGIN LIST CMD <upsname>
	  CMD <upsname> <cmdname>
	  ...
	  END LIST CMD <cmdname>

	  BEGIN LIST CMD su700
	  CMD su700 load.on
	  CMD su700 test.panel.start
	  ...
	  END LIST CMD su700

This replaces the old "LISTINSTCMD" command.

ENUM
----

    Form: LIST ENUM <upsname> <varname>
          LIST ENUM su700 input.transfer.low

Response: BEGIN LIST ENUM <upsname> <varname>
	  ENUM <upsname> <varname> "<value>"
	  ...
	  END LIST ENUM <upsname> <varname>

	  BEGIN LIST ENUM su700 input.transfer.low
	  ENUM su700 input.transfer.low "103"
	  ENUM su700 input.transfer.low "100"
	  ...
	  END LIST ENUM su700 input.transfer.low

This replaces the old "ENUM" command.

Note: this does not support the old "SELECTED" notation.  You must
request the current value separately.

============================================================================
Reworked commands
============================================================================

These commands have new argument sets that work with the new variable
names.  Their older counterparts still exist, and will be used when
necessary for compatability.

SET
---

   Form: SET VAR <upsname> <varname> "<value>"
         SET VAR su700 ups.id "My UPS"

INSTCMD
-------

   Form: INSTCMD <upsname> <cmdname>
         INSTCMD su700 test.panel.start

============================================================================
Older commands
============================================================================

These commands continue to be supported for backwards compatibility.
While the drivers are actually using the newer variable names
("ups.status" instead of STATUS), upsd will internally convert when
necessary.

The commands which use the old variable names will be going away after
the 1.x series, so you should upgrade any clients that are using them.

LISTVARS
========

Form: LISTVARS [<upsname>]

upsname is an identifier given to a UPS on a host.  These are specified
in the ups.conf.  If it is not specified, the server will refer to the
first entry from that file.

Returns: VARS <varlist>
Returns: VARS @<upsname> <varlist>	(when upsname specified)

<varlist> is a space delimited list of all possible variables that
the server process knows about for this UPS.

Requires: MONITOR access

* Obsolete: switch to "LIST VAR".

REQ
===

Form: REQ <varname>[@<upsname>]

<varname> is a variable name returned by LISTVARS or a reserved word:

 - Reserved words:

   NUMLOGINS - Number of systems currently monitoring this UPS
               (incremented by LOGIN commands from authorized clients)

<upsname> is an identifier as seen above with LISTVARS.

Returns: ANS <varname> <value>
Returns: ANS <varname>@<upsname> <value>	(when upsname specified)

<varname> is the variable you requested, repeated just to be sure

<value> is the current value as the server knows it

*** Old versions of upsd also have a few special responses for <value>:

 UNKNOWN
  - upsd doesn't recognize this variable.  
    Replaced with "ERR VAR-UNKNOWN".

 NOT-SUPPORTED
  - this UPS driver doesn't gather data for this variable
    Replaced with "ERR VAR-NOT-SUPPORTED".
   
 DATA-STALE
  - the server hasn't gotten an update for this data recently
    Replaced with "ERR DATA-STALE".

Requires: MONITOR access

* Obsolete: switch to "GET VAR".

LISTRW
======

Form: LISTRW [<upsname>]

Returns: RW <read-write variable list>
         RW @<upsname> <read-write variable list> (when upsname specified)

Requires: MONITOR access

Lists all variables that allow modification of their values within the
driver.

* Obsolete - switch to "LIST RW".

VARTYPE
=======

Form: VARTYPE <varname>[@<upsname>]

Returns: TYPE <vartype> <extravalue>

Requires: MONITOR access

<vartype> is one of ENUM or STRING.

ENUM: Enumerated type, <extravalue> is how many possibilities exist
STRING: Character string, <extravalue> is how long it may be

Lists the type of a read-write variable.

* Obsolete - switch to "GET TYPE".

VARDESC
=======

Form: VARDESC <varname>

Returns: DESC "<variable description>"

Requires: MONITOR access

<variable description> is a short explanation of what a variable means.

* Obsolete - switch to "GET DESC".

ENUM
====

Form: ENUM <varname>[@<upsname>]

Returns: multi-line return:

ENUM <varname>
OPTION "<optval>" [SELECTED]		may repeat multiple times
END

Requires: MONITOR access

<optval> is a valid option for <varname>.  SELECTED will be included if
<varname> is currently set to <optval> in the hardware.

Shows the possible values for an enumerated type R/W variable.

* Obsolete - switch to "LIST ENUM".

INSTCMD
=======

Form: INSTCMD <command>[@<upsname>]

Requires: "INSTCMD" action granted in upsd.users
          "<command>" instcmd granted in upsd.users

<command> is an instant command name.  See LISTINSTCMD and shared.h.

* Obsolete - switch to new form: "INSTCMD <upsname> <cmdname>"

LISTINSTCMD
===========

Form: LISTINSTCMD [<upsname>]

Returns: INSTCMDS [@<upsname>] <cmd1> <cmd2> ... <cmdn>

Requires: MONITOR access

Shows all the instant commands available on a given UPS.

* Obsolete - switch to "LIST CMD"

INSTCMDDESC
===========

Form: INSTCMDDESC <cmdname>

Requires: MONITOR access

Returns: DESC "<description>"

Shows the description for a given instant command suitable for showing
to users.

* Obsolete - switch to "LIST CMDDESC"

SET
===

Form: SET <varname>[@upsname] <value>

<value> is an acceptable sequence for the variable <varname>.

Requires: "SET" action granted in upsd.users

Sets the R/W variable <varname> to <value>, assuming it is allowed.

* Obsolete - switch to new form: "SET VAR <upsname> <varname> <value>".

============================================================================
Unchanged commands
============================================================================

These commands are not affected by the variable name change.

LOGOUT
======

Form: LOGOUT

Returns: OK Goodbye	(recent versions)

TCP mode only.  Used to disconnect gracefully from the server.

Older versions just said "Goodbye...".

LOGIN
=====

Form: LOGIN <upsname>

Returns: OK	(upon success)
	 or various errors

Requires: "upsmon slave" or "upsmon master" in upsd.users

Use this to log the fact that a system is drawing power from this UPS.
The upsmon master will wait until the count of attached systems reaches
1 - itself.  This allows the slaves to shut down first.

NOTE: You probably shouldn't send this command unless you are upsmon,
      or a upsmon replacement.

MASTER
======

Form: MASTER <upsname>

Returns: OK	(upon success)
	 or various errors

Requires: "upsmon master" in upsd.users

This function doesn't do much by itself.  It is used by upsmon to make
sure that master-level functions like FSD are available if necessary.

FSD
===

Form: FSD <upsname>

Returns: OK FSD-SET	(success)
	 or various errors

Requires: "upsmon master" in upsd.users
          or "FSD" action granted in upsd.users

upsmon in master mode is the primary user of this function.  It sets this
"forced shutdown" flag on any UPS when it plans to power it off.  This is
done so that slave systems will know about it and shut down before the
power disappears.

Setting this flag makes "FSD" appear in a STATUS request for this UPS.
Finding "FSD" in a status request should be treated just like a "OB LB".

It should be noted that FSD is currently a latch - once set, there is  
no way to clear it short of restarting upsd or dropping then re-adding
it in the ups.conf.  This may cause issues when upsd is running on a
system that is not shut down due to the UPS event.

PASSWORD
========

Form: PASSWORD <password>

Returns: OK	(upon success)
	 or various errors

Requires: BASE or higher access

Sets the password associated with a connection.  Used for later
authentication for commands that require it.

USERNAME
========

Form: USERNAME <username>

Returns: OK	(upon success)
	 or various errors

Requires: BASE or higher access

Sets the username associated with a connection.  This is also used for
authentication, specifically in conjunction with the upsd.users file.

STARTTLS
========

Form: STARTTLS

Requires: TCP connection (impossible over UDP)

Returns: OK STARTTLS
	 or various errors

This tells upsd to switch to TLS mode internally, so all future
communications will be encrypted.  You must also change to TLS mode in
the client after receiving the OK, or the connection will be useless.	

Other commands
==============

HELP - lists the commands supported by this server
VER  - shows the version of the server currently in use

These two are not intended to be used directly by programs.  Humans can
make use of this program by using telnet for TCP or netcat for UDP.  Try
either "telnet localhost 3493" for TCP or "nc -u localhost 3493" for UDP
and it should talk to you.

Error responses
===============

NOTE: these messages will be growing somewhat.  Responses to the new
commands (see above) will include the original query.  This will allow
proper error detection even with pipelining.

This is not yet completed.

Old notes
---------

ERR <message>

 VAR-NOT-SUPPORTED
  - this UPS doesn't support the requested variable

 VAR-UNKNOWN
  - upsd doesn't recognize the requested variable

 ACCESS-DENIED
  - This client has been denied access to this function.

 PASSWORD-REQUIRED
  - The client must set a password before attempting this action.

 PASSWORD-INCORRECT
  - The password supplied previously is not the correct one associated 
    with this action on the server.

 UNKNOWN-UPS
  - The client tried to associate a command with a UPS that is 
    not recognized by the server.

 ALREADY-LOGGED-IN
  - The client has already done LOGIN.

 ALREADY-SET-PASSWORD
  - The client has already done PASSWORD.

 UNKNOWN-COMMAND
  - The client sent a command that this server doesn't understand.

 UNKNOWN-INSTCMD
  - The client sent an instant command that this server doesn't
    understand.

 CMD-NOT-SUPPORTED
  - The client tried to start an instant cmd (INSTCMD) that the
    UPS equipment doesn't support.

Errors related to message passing (future, some unimplemented)
--------------------------------------------------------------

NO-RESPONSE: The UPS driver did not respond to a command before a timeout.

UNKNOWN-REPLY: The UPS driver gave the server a bogus response.

NOT-IMPLEMENTED: The UPS driver doesn't have this command impemented.

COMMAND-FAILED: The UPS driver tried, but failed to execute this
                command.

Future ideas
============

The LIST commands may be given the ability to handle options some day.
For example, "LIST VARS <ups> +DESC" would return the current value
like now, but it would also append the description of that variable.
