commit 26fb71b5045cd198c1791fe927a6e6098007f555 Author: arnaud.quette@free.fr Date: Fri Mar 26 00:20:59 2010 +0100 Imported Upstream version 2.4.3 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..949847d --- /dev/null +++ b/AUTHORS @@ -0,0 +1,177 @@ +# The NUT AUTHORS file. Don't be shy. If you have contributed to this +# project in some way, send me a patch to add yourself to this file. +# +# Everyone deserves credit, including those who haven't added any code. +# Ideas, clues, and helping out on the mailing lists all count too. +# +# This is a blatant ripoff of the fields found in the Linux kernel's CREDITS +# file. If we need more data, those fields can always be added later. +# +# N = name, E = email, W = web address, D = description, P = PGP info, +# S = snailmail address, etc. +# +# This file is supposed to be roughly alpha-sorted by the last name, but +# if you want to hide at the bottom, that's fine by me. Just clarify +# your preference when submitting changes to this file. + +N: Stephen Brown +E: steve@datalimbo.net +W: http://www.datalimbo.net/ +D: Hacked genericups to add TrippLite Lan2.x support (Internet Office 700) + +N: Bill Carlson +E: wcarlson@wkks.org +W: http://wkks.org/ +D: Fixed the GD/configure problem + +N: Ben Collver +E: collver@softhome.net +W: http://superfluous.oddbox.org +D: Beginning support for HPUX 10.20 and Windows 2000 + +N: Luca Filipozzi +E: lfilipoz@debian.org +D: Original Debian maintainer for nut package. Minor patches to source. + +N: Matthew Gabeler-Lee +E: msg2@po.cwru.edu +W: http://cheetah.cwru.edu +D: Added custom formatting to upslog +D: Helped get apcsmart working with old SmartUPS models + +N: David Goncalves +E: david@lestat.st +W: http://www.lestat.st +D: Python client support (PyNUT module and NUT-Monitor application) + +N: Bruno Hall +D: Contributed UPS compatibility information + +N: Bo Kersey - VirCIO - Managed Server Solutions +E: bo@vircio.com +W: http://www.vircio.com/ +D: Provided a Best Fortress for development of a Best driver (bestups) + +N: Russell Kroll +E: rkroll@exploits.org +W: http://www.networkupstools.org/ +D: Original NUT author and coordinator +P: 1024D/9DC0E77E 6A5C 7D2D 7945 C022 6104 D421 D61D C97F 9DC0 E77E + +N: Rick Lyons +E: rick@powerup.com.au +D: Support for Liebert UPSes using MultiLink cable + +N: Jeremy Maccelari +E: visualn@iafrica.com, jeremy@visuals.co.za +W: http://www.visuals.co.za +D: Support for Mustek UPSes + +N: Philippe Marzouk +E: philm@users.sourceforge.net +D: Support for MGE Pulsar Ellipse UPSes ; co author of mge-shut + +N: Theodor A. Milkov +E: zimage@delbg.com +W: http://www.delbg.com/~zimage/ +D: Adding support for Repotec's RPT-800A, RPT-162A to genericups driver. + +N: Mark Powell +E: medp@primagraphics.co.uk +D: Ported to SunOS4 + +N: Arnaud Quette +E: aquette.dev@gmail.com +E: arnaud.quette@mgeups.com +E: aquette@debian.org +W: http://arnaud.quette.free.fr/ +D: Primary coordinator ; author of snmp-ups, mge-shut, usbhid-ups ; +D: co author of mge-utalk, hidups, SNMP UPS Agent ; contributor to blazer, +D: bestferrups, nut core, and many others ; coordination with MGE UPS +D: SYSTEMS, linux-usb developers (for hidups), Net SNMP and packagers +D: (Mandriva, Debian, SuSE, ...)... +P: 1024D/204DDF1B 1371 07DF 3CF3 9160 7905 144B DB64 14CA 204D DF1B + +N: Lars Balker Rasmussen +E: lbr@mjolner.dk +D: Solaris and minor patches + +N: Carlos Rodrigues +E: carlos.efr@mail.telepac.pt +W: http://students.fct.unl.pt/~cer09566/ +D: author of the "megatec" driver + +N: David Santinoli +E: david@santinoli.com +W: http://www.santinoli.com +D: Support for Online P-series in genericups driver + +N: Jacob Schmier +E: j.schmier@live.com +D: support for Universal-Mount ON Series UPS family in oneac driver + +N: Peter Selinger +E: selinger@users.sourceforge.net +W: http://www.mathstat.dal.ca/~selinger/ +D: wrote belkinunv driver, contributions to usbhid-ups +P: 1024D/CA31696A 12A2 4B3C 3790 B688 E484 7A98 A68B CC37 CA31 696A + +N: Kirill Smelkov +E: kirr@mns.spb.ru +D: Author of al175 + +N: John Stone +E: johns@megapixel.com +W: http://www.megapixel.com/ +D: Support for Best MicroFerrups UPS + +N: Technorama Ltd. +E: oss-list-ups@technorama.net +D: common driver core design, redundant code elimination, security fixes +D: other misc patches and improvements throughout + +N: Jason Thomas +E: jason@topic.com.au +W: http://www.topic.com.au/ +D: Hacked up the UPSonic Driver. + +N: Simon Rozman +E: simon@rozman.net +W: http://simon.rozman.net/ +D: Hacked powercom to add Socomec Sycon Egys 420 VA support + +N: Len J White +E: lwhite@darkfires.net + +N: Walt Holman +E: walt_h@lorettotel.net +D: Hacked up the cpsups driver for CyberPower text protocol UPSes + +N: Fabio Di Niro +E: blaxwan@users.sourceforge.net +D: Author of metasys driver, support for Meta System UPS + +N: Arjen de Korte +E: arjen@de-korte.org +D: Author of safenet driver +P: 1024R/AEF3BA11 664E 032C 9DB5 CB9B 7AFE 7EC1 EE88 BC57 + +N: Håvard Lygre +E: hklygre@online.no +D: First stab at upscode2 driver for NUT 1.4 + +N: Niels Baggesen +E: niels@baggesen.net +D: upgraded the upscode2 driver to NUT-2, and extended it heavily. + +N: Niklas Edmundsson +E: nikke@acc.umu.se +D: 3-phase work, updates for upscode2 + +N: Olli Savia +E: ops@iki.fi +D: pwmib support for snmp-ups + +N: Kjell Claesson +E: Kjell.claesson@epost.tidanet.se +D: Author of bcmxcp driver, 3-phase work. diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..606347e --- /dev/null +++ b/COPYING @@ -0,0 +1,12 @@ + + Most files are licensed under the GNU General Public License (GPL) version 2, + or (at your option) any later version. See "LICENSE-GPL2" in the root of this + distribution. + + The files in the scripts/python/ directory are released under GNU General + Public License (GPL) version 3, or (at your option) any later version. See + "LICENSE.GPL3" in the root of this distribution. + + The Perl client module (scripts/perl/Nut.pm) is released under the same + license as Perl itself. That is to say either GPL version 1 or (at your option) + any later version, or the "Artistic License". diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..4bd5b6f --- /dev/null +++ b/ChangeLog @@ -0,0 +1,1091 @@ +2.4.3 + +2010-02-23 Arnaud Quette + + * [r2366] ChangeLog, configure.in, NEWS, UPGRADING: Final update for + 2.4.3 release + +2010-02-20 Arjen de Korte + + * [r2365] m4/nut_check_ipv6.m4: Fix broken logic to enable IPv6 + support + +2.4.2 + +2010-02-19 Arnaud Quette + + * [r2363] ChangeLog, configure.in: Final update for 2.4.2 release + +2010-02-19 Arnaud Quette + + * [r2362] NEWS, data/driver.list: Add HP R1500 G2 to compatibility + list for bcmxcp + (reported by Stephan Schupfer) + +2010-02-19 Arjen de Korte + + * [r2361] clients/upsmon.h: Fixed typo + * [r2360] clients/upsmon.c, clients/upsmon.h: You can't compare + strings with '!=' in C, so the logic to determine if the stock + message was overridden was flawed (causing problems with + (de)allocation of memory) + +2010-02-19 Arnaud Quette + + * [r2357] conf/nut.conf.sample, conf/upsmon.conf.sample, docs/FAQ, + man/upsmon.conf.5: Remove remaining references to ACL / + allowfrom. + +2010-02-19 Arjen de Korte + + * [r2355] configure.in: Replace __func__ on pre-C99 compilers with + __FUNCTION__ (may be available on older GNU C compilers) or + __LINE__ (which is always available) + +2010-02-16 Arjen de Korte + + * [r2353] drivers/main.h: Static initialization of flexible array + members is non-portable (GNU C extension), so don't use a + flexible array member here + * [r2352] configure.in: Check if the C compiler supports flexible + array members and/or variable-length arrays + * [r2350] drivers/upscode2.c: Don't use signed constants in a + bitfield + +2010-02-15 Arjen de Korte + + * [r2349] drivers/main.h: Fix missing semi-colon + * [r2348] drivers/main.h: Attempt to fix compiler warning on + Solaris (although I have my doubts about the portability of array + declarations within structures) + * [r2347] drivers/snmp-ups.c, drivers/snmp-ups.h: Fix for buggy + Net-SNMP config should be before including headers, since our + autoconf generated header is the first to be included (so the + conflict is caused by subsequently including the Net-SNMP + headers) + * [r2346] drivers/apcsmart.c, drivers/metasys.c, drivers/serial.c: + Fix unreachable code warnings + * [r2345] drivers/upscode2.c: An (int) is only guaranteed to be at + least 16-bit while we need 32-bit here (so it's better to use a + fixed width integer) + +2010-02-14 Arjen de Korte + + * [r2344] configure.in, docs/configure.txt, drivers/powerman-pdu.c, + m4/nut_check_libneon.m4, m4/nut_check_libnetsnmp.m4, + m4/nut_check_libpowerman.m4, m4/nut_check_libusb.m4: Allow to + override CFLAGS and LDFLAGS detected by the *.m4 macros in case + pkg-config is not available + * [r2343] docs/configure.txt, m4/nut_check_libssl.m4: Allow cflags + and ldflags overrides for openssl (may be useful/needed if + pkg-config is not available) + +2010-02-13 Arjen de Korte + + * [r2342] drivers/liebertgxt2.c: Use (unsigned char) instead of + (char) in command definitions (to prevent overflow warnings + definitions) + * [r2341] drivers/mge-shut.h: The usage code must be at least a + 32-bit integer (and 'int' is only guaranteed to be at least + 16-bit). + * [r2340] m4/nut_check_libnetsnmp.m4: Check if Net-SNMP library is + usable + +2010-02-12 Arjen de Korte + + * [r2339] docs/cables/apc.txt: APC cable diagrams as reported on + the mailinglist + [http://lists.alioth.debian.org/pipermail/nut-upsuser/2005-August/000118.html] + +2010-02-11 Charles Lepple + + * [r2338] ChangeLog: Generate ChangeLog entries from r2337 through + r2331. + +2010-02-11 Arnaud Quette + + * [r2337] NEWS: Complete news information for the 2.4.2 release. + +2010-02-11 Arjen de Korte + + * [r2336] (numerous files) No functional changes (properties only) + * [r2335] AUTHORS: No functional changes (properties only) + +2010-02-10 Arnaud Quette + + * [r2334] ChangeLog: Trimmed 2.4.0 entries. + +2010-02-10 Arjen de Korte + + * [r2333] m4/nut_check_ipv6.m4: Check for presence of structures + required for IPv6 support in the header files that are defined by + POSIX (don't rely on the netdb.h header to include them) + +2010-02-10 Charles Lepple + + * [r2332] ChangeLog: Generate ChangeLog entries from SVN r2331 back + through r2117. + +2010-02-10 Arjen de Korte + + * [r2331] drivers/genericups.c: Fix typo in previous commit + * [r2330] drivers/genericups.c: Don't hang up on last close + (initial state of HUPCL is implementation dependent) + [http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=327072] + +2010-02-09 Arjen de Korte + + * [r2329] drivers/main.c: Some drivers set + 'driver.version.internal' in upsdrv_initinfo() so we should set + the generic message before running that + * [r2327] man/upssched.conf.5: Fix wrong reference + [http://lists.alioth.debian.org/pipermail/nut-upsdev/2010-February/004532.html] + * [r2326] server/netuser.c: Check if user is allowed to login + before accepting connection + + [http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=544390] + +2010-02-08 Arjen de Korte + + * [r2324] UPGRADING: The tcp-wrappers support is optional in + addition to the LISTEN directive (not the other way around) + +2010-02-08 Arnaud Quette + + * [r2323] UPGRADING: Add a double explicit note about the ACL + mechanism removal in 2.4.0. + (reported on Debian by Anthony DeRobertis, Bug #526811) + +2010-02-08 Arjen de Korte + + * [r2322] data/driver.list: Added lots of Ippon devices that were + mentioned on the mailinglists (serial devices will undoubtly + work, USB support still experimental) + +2010-02-07 Arjen de Korte + + * [r2321] UPGRADING, drivers/blazer_usb.c, man/blazer.8: Use + 'ippon' subdriver for devices with USB id 06da:0003 (old + 'phoenix' subdriver still available) + * [r2320] drivers/raritan-mib.h, drivers/snmp-ups.c: Fix wrong name + * [r2319] drivers/raritan-mib.h: Add missing file in previous + commit + * [r2318] drivers, drivers/Makefile.am, drivers/apc-mib.c, + drivers/apc-mib.h, drivers/apccmib.h, drivers/baytech-mib.c, + drivers/baytech-mib.h, drivers/baytechmib.h, + drivers/compaq-mib.c, drivers/compaq-mib.h, + drivers/cpqpowermib.h, drivers/eaton-aphel-mib.h, + drivers/eaton-mib.c, drivers/eaton-mib.h, drivers/ietf-mib.c, + drivers/ietf-mib.h, drivers/ietfmib.h, drivers/mge-mib.c, + drivers/mge-mib.h, drivers/mgemib.h, drivers/netvision-mib.c, + drivers/netvision-mib.h, drivers/netvisionmib.h, + drivers/powerware-mib.c, drivers/powerware-mib.h, + drivers/pwmib.h, drivers/raritan-mib.h, + drivers/raritan-pdu-mib.c, drivers/raritan-pdu-mib.h, + drivers/snmp-ups.c, drivers/snmp-ups.h: Extract subdriver info + from main driver body into separate modules. This prevents + namespace conflicts and ensures that changes in one subdriver + don't lead to surprise changes in others. + + It also allows to use a single mapping file to be used in several + subdrivers by specifying a different entry point (which doesn't + work if everything is in one module). + +2010-02-07 Charles Lepple + + * [r2317] drivers/apcsmart.c, drivers/apcsmart.h: apcsmart: Add + input.transfer.reason + + Contributed by Michael Haardt: + http://article.gmane.org/gmane.comp.monitoring.nut.devel/4498 + +2010-02-05 Arjen de Korte + + * [r2316] drivers/cpqpowermib.h: Could this be a Powerware OEM + device? + +2010-02-04 Arjen de Korte + + * [r2315] drivers/cpqpowermib.h: Based on patch from Philip Ward + [http://lists.alioth.debian.org/pipermail/nut-upsdev/2010-February/004509.html] + +2010-02-01 Arjen de Korte + + * [r2305] clients/upsimage.c, common/strerror.c, drivers/bcmxcp.c, + drivers/main-hal.c, drivers/powerman-pdu.c: Prefer snprintf over + sprintf to prevent overflowing buffers (also removes trailing + whitespace) + * [r2303] drivers/Makefile.am, drivers/cpqpowermib.h, + drivers/snmp-ups.c, man/snmp-ups.8: + +2010-01-31 Charles Lepple + + * [r2297] drivers/tripplite_usb.c: Revert trunk commit r2294, which + was meant for a branch. + * [r2296] drivers/clone-outlet.c: clone-outlet.c: remove executable + bit + * [r2294] drivers/tripplite_usb.c: tripplite_usb: initial changes + to test protocol 3004 + +2010-01-30 Arnaud Quette + + * [r2286] tools/Makefile.am, tools/device-recorder.sh: Create a + script to record device running sequence and dump it in a .seq + format. + The .seq file can then be used by dummy-ups to replay the + sequence. + +2010-01-28 Charles Lepple + + * [r2282] m4/nut_report_feature.m4: Another attempt to fix the + feature report on OS X. + +2010-01-27 Arjen de Korte + + * [r2281] m4/nut_report_feature.m4: Attempt to get rid of spurious + '-n' on MacOSX-10.5 BuildBot + * [r2280] m4/nut_check_libhal.m4: Prefer to use 'test' over '[ ]' + (on many shells, this first a built-in function while the second + is a symbolic link to 'test') + +2010-01-27 Charles Lepple + + * [r2279] m4/nut_check_libhal.m4: Remove fallback HAL information + path, and remove extra parentheses. + +2010-01-25 Arjen de Korte + + * [r2278] drivers/megatec.c: Don't check reliability of connection + at driver startup. This confuses users and really serves no + purpose for normal use. In case the connection is unreliable, it + should ultimately be the decision of the user whether or not it + is acceptable (not the driver). + * [r2277] drivers/apc-hid.c, drivers/belkin-hid.c, + drivers/cps-hid.c, drivers/explore-hid.c, drivers/liebert-hid.c, + drivers/mge-hid.c, drivers/powercom-hid.c, + drivers/tripplite-hid.c, include/common.h: The "config.h" header + should be the first included, since it contains the _GNU_SOURCE + declaration (enables Posix extensions to C) + * [r2276] configure.in: Add AC_USE_SYSTEM_EXTENSIONS to use + features of Posix that are extensions to C (requires Autoconf + 2.60 or better) + * [r2275] common/common.c: Fix compiler warning on MacOSX-10.5 + * [r2274] common/common.c: Fix compiler warning on FreeBSD + * [r2273] configure.in: + * [r2272] configure.in, drivers/mge-hid.c: Check for presence of + strptime() before using it + +2010-01-24 Arjen de Korte + + * [r2271] configure.in, drivers/mge-hid.c: The previous patch was a + resounding failure (reverting back to setting _XOPEN_SOURCE in + one specific source file instead) + * [r2270] configure.in: Request SUSv2 compliance for all sources + (experimental) + * [r2269] drivers/mge-hid.c: _XOPEN_SOURCE seems to break on + FreeBSD + * [r2268] drivers/mge-xml.c: Fix compiler warning + +2010-01-24 Charles Lepple + + * [r2267] drivers/mge-hid.c: Define _XOPEN_SOURCE=500 for + strptime() prototype in glibc2 + +2010-01-24 Arjen de Korte + + * [r2266] drivers/mge-hid.c: Removing stuff that was added to fix + strptime on Debian Etch (incompatible with FreeBSD) + +2010-01-23 Arjen de Korte + + * [r2265] drivers/mge-hid.c: Fourth attempt of fixing strptime() + declaration missing on Debian + * [r2264] drivers/mge-hid.c: Third attempt of fixing strptime() + declaration missing on Debian + * [r2263] drivers/mge-hid.c: Second attempt of fixing strptime() + declaration missing on Debian + * [r2262] drivers/apc-hid.c, drivers/belkin-hid.c, + drivers/cps-hid.c, drivers/explore-hid.c, drivers/liebert-hid.c, + drivers/mge-hid.c, drivers/powercom-hid.c, + drivers/tripplite-hid.c, scripts/subdriver/path-to-subdriver.sh: + Remove redundant #include's (are being dealt with by main.h) + * [r2261] data/cmdvartab: Add descriptions for + 'ups.timer.(start|reboot|shutdown)' variables + * [r2260] drivers/mge-hid.c: Need to define _XOPEN_SOURCE for + strptime() prototype in glibc2 + +2010-01-22 Arjen de Korte + + * [r2257] drivers/mge-shut.c, drivers/mge-shut.h: Change naming of + ups.delay.* variables to ups.timer.*, since writing these values + immediately starts the countdown (and not when a shutdown command + is issued) + * [r2256] drivers/powercom-hid.c: Fallback to stored value of + 'ups.delay.(start|shutdown)' only if no parameter is given (to + fix 'load.on' command) + +2010-01-21 Arjen de Korte + + * [r2255] drivers/powercom-hid.c: Fix beeper.status and add + load.on.delay command (to allow starting up with delay when UPS + is shutdown) + +2010-01-19 Arjen de Korte + + * [r2254] data/driver.list, drivers, drivers/Makefile.am, + drivers/liebertgxt2.c, man/Makefile.am, man/liebertgxt2.8: Based + on the patch from the below message (needs to be tested) + + http://lists.alioth.debian.org/pipermail/nut-upsdev/2010-January/004391.html + * [r2253] drivers/powercom-hid.c: Add + 'beeper.(enable|disable|mute)' instcmd's + +2010-01-17 Charles Lepple + + * [r2250] drivers/tripplite_usb.c: tripplite_usb: Detect protocol + before using tl_model + + Reported by Chase Wallis. + +2010-01-17 Arjen de Korte + + * [r2248] man/blazer.8: Add 'ippon' subdriver to man page + * [r2247] drivers/blazer_usb.c: ETIME is not defined on FreeBSD, so + make this test conditional (also fixes wrong sign) + +2010-01-13 Arjen de Korte + + * [r2244] drivers/blazer_usb.c: Close device handle after + usb_reset() is called and reconnect + * [r2243] drivers/blazer_usb.c: Attempt to clear stalled devices by + sending them an usb_reset() command + +2010-01-13 Charles Lepple + + * [r2242] drivers/tripplite_usb.c: tripplite_usb: don't reset + watchdog on SMARTPRO models + + Patch by Chase Wallis: + http://article.gmane.org/gmane.comp.monitoring.nut.devel/4376 + +2010-01-12 Arjen de Korte + + * [r2241] drivers/blazer_usb.c: Fix bug in ippon subdriver + +2010-01-07 Arjen de Korte + + * [r2240] drivers/blazer_usb.c: Fix minor bug in debug code + * [r2239] drivers/blazer_usb.c: Add experimental 'ippon' subdriver + to communicate with UPS devices of the same name + +2010-01-06 Arjen de Korte + + * [r2238] drivers/blazer_usb.c: Clear potential stall condition + while flushing interrupt pipe + * [r2237] drivers/libusb.c, drivers/usbhid-ups.c: Reconnect if + usb_clear_halt() is not implemented (older libusb on *BSD + systems) so that we don't get stuck with a stalled interrupt + endpoint (correction of 2235) + * [r2236] drivers/usbhid-ups.c: EPIPE should not result in + reconnecting since we're reading from a control endpoint here, + not an interrupt endpoint (where this would be an appropriate + action after attempting to fix the stall condition through + usb_clear_halt() first) + * [r2235] drivers/usbhid-ups.c: Reconnect if usb_clear_halt() is + not implemented (older libusb on *BSD systems) so that we don't + get stuck with a stalled interrupt endpoint + +2010-01-05 Arjen de Korte + + * [r2234] drivers/libusb.c: Don't ignore persistent "Broken pipe" + on stalled interrupt endpoint (only ignore them on control + endpoints) + * [r2233] drivers/libusb.c: Clear stall condition on interrupt + endpoint if needed (since we no longer reconnect, this may be + needed) + * [r2232] drivers/libusb.c, drivers/usbhid-ups.c: Change libusb.c + error handling. Most important (functional) change is that + "Broken pipe" is no longer considered a reason to reconnect + (fixes MGE/Eaton Ellipse series UPS stability problems). + +2010-01-04 Arjen de Korte + + * [r2231] drivers/libusb.c: Fix previous patch + * [r2230] drivers/libusb.c: Log message to syslog when + usb_get/set_* operation fails (except timeouts) at LOG_DEBUG to + make sure we have something to work with for debugging frequent + disconnects + +2010-01-02 Arjen de Korte + + * [r2224] m4/nut_check_libneon.m4: Fix output when library is not + installed + * [r2223] m4/nut_check_libhal.m4: Don't wast effort trying to + detect HAL stuff if we already know it is not available + * [r2222] m4/nut_check_libgd.m4: Remove braces around test + conditions + * [r2221] m4/nut_check_libpowerman.m4, m4/nut_check_libssl.m4: + Remove braces around test conditions + * [r2220] m4/nut_check_libusb.m4: Fix one "==" that was left behind + (and slightly improve message when pkg-config is not available) + +2010-01-01 Charles Lepple + + * [r2219] m4/nut_check_libusb.m4: Remove extra parentheses from + libusb test. + + Also change '==' to '=' for string equality test. + +2009-12-31 Arjen de Korte + + * [r2218] m4/nut_check_libusb.m4: Add pkg-config as method to + retrieve CFLAGS and LDFLAGS (but fall back to libusb-config) + +2009-12-30 Arjen de Korte + + * [r2217] drivers/libusb.c: Fix previous patch (failed to remove + closing #endif statement) + * [r2216] drivers/libusb.c, drivers/usbhid-ups.c: Enable the use of + the interrupt pipe on Solaris (for drivers that require this), + but disable it on the usbhid-ups driver (for which it is + optional). + * [r2215] drivers/powercom-hid.c: Honor 'offdelay' configuration + parameter and allow changing the 'ups.delay.shutdown' variable at + runtime + +2009-12-28 Arjen de Korte + + * [r2214] data/driver.list: Add new PowerCOM devices with HID PDC + interface to list of supported models + * [r2213] drivers/powercom-hid.c: The PowerCOM subdriver has now + reached a state where it is useable. Commands have been tested on + a BNT-500AP. + * [r2212] drivers/usbhid-ups.c: The composite commands + 'shutdown.return' and 'shutdown.stayoff' require 'load.on.delay' + and 'load.off.delay' (not 'ups.delay.start' and + 'ups.delay.shutdown'). + +2009-12-27 Charles Lepple + + * [r2203] scripts/hal/Makefile.am: Hard-code source file in + scripts/hal + +2009-12-26 Arjen de Korte + + * [r2202] m4/nut_check_libhal.m4: Revert previous patch that breaks + on OpenSUSE (and add HAL_CALLOUTS_PATH instead of relying on the + default) + * [r2201] m4/nut_check_libhal.m4: Use ${datarootdir} instead of + /usr/share or /usr/local/share (we check for the presence of a + subdirectory, so the chance of a false positive is low) + * [r2200] m4/nut_check_libneon.m4: Only check for optional + functions if we know library is available + * [r2199] m4/nut_check_libgd.m4: Simplify the --with-gd-includes + and --with-gd-libs processing + +2009-12-25 Arjen de Korte + + * [r2198] configure.in: FreeBSD requires both and + so explicitly use only these two headers to check for + availability of uu_lock + * [r2197] m4/nut_check_libusb.m4: Check for presence of 'usb.h' + (not 'libusb.h', which is what we use internally) + +2009-12-24 Charles Lepple + + * [r2196] m4/nut_check_libhal.m4: Test for FDI files in /usr/local + as well as /usr + + This should fix HAL-enabled builds on FreeBSD. + +2009-12-24 Arjen de Korte + + * [r2195] m4/nut_check_libhal.m4: If we can't detect the + HAL_FDI_PATH automatically, set it to /dev/null and emit warning + * [r2194] m4/nut_check_libusb.m4: Fix missing default -lusb library + and improve comments during detection + * [r2193] m4/nut_check_libusb.m4: Work around missing libusb-config + on FreeBSD 8 by falling back to defaults for CFLAGS and LDFLAGS + * [r2192] configure.in: Try to workaround some FreeBSD bugs + * [r2191] drivers/powercom-hid.c: Updated HID to NUT mappings (work + in progress and still quite broken, do not run on production + systems!) + +2009-12-22 Arjen de Korte + + * [r2190] drivers/libhid.c: Add debug information for input reports + that are not in the report descriptor + +2009-12-21 Arjen de Korte + + * [r2189] drivers/libhid.c: Use hexadecimal report numbers in debug + messages (to be consistent throughout the code) + +2009-12-20 Arjen de Korte + + * [r2188] m4/nut_check_libwrap.m4: Small improvement to better + mimic the behavior of AC_SEARCH_LIBS (by checking if we need to + add -lwrap before adding it to LIBS) + +2009-12-19 Arjen de Korte + + * [r2187] m4/ax_create_stdint_h.m4: Update location of Autoconf + Archive in header (so that we can check for modifications) + * [r2186] m4/nut_check_libgd.m4: AC_SEARCH_LIBS puts the result in + LIB, so we need to add that to the LIBGD_LDFLAGS (otherwise, this + will be part of the global LIBS that are used) + +2009-12-18 Arjen de Korte + + * [r2185] m4/nut_check_libgd.m4: Apparently, gdlib-config sometimes + fails to mention '-lgd' when asked for the LDFLAGS, so we need to + test once again if we need to include this library. + * [r2184] common/snprintf.c, configure.in: Instead of trying to + figure out if 'long long' is supported through AC_TRY_RUN + (obsolete), use AC_TYPE_LONG_LONG_INT (and AC_TYPE_LONG_DOUBLE). + Since this is only used by common/snprintf.c, only do this if + snprintf isn't a build-in function (which means probably never). + * [r2183] configure.in: Don't run preprocessor tests on + AC_CHECK_HEADERS (so CPPFLAGS is no longer needed). Replace shell + scripting by autoconf macros. + * [r2182] m4/nut_check_libgd.m4, m4/nut_check_libnetsnmp.m4, + m4/nut_check_libwrap.m4: Don't run preprocessor tests on + AC_CHECK_HEADERS (so CPPFLAGS is no longer needed). + * [r2181] m4/nut_check_libhal.m4: Don't run preprocessor tests on + AC_CHECK_HEADERS (so CPPFLAGS is no longer needed). Reformatted + macro (no functional changes). + * [r2180] m4/nut_check_libwrap.m4: Prefer AC_CHECK_HEADERS over + AC_CHECK_HEADER + * [r2179] m4/nut_check_libgd.m4: Set CPPFLAGS in case autoconf only + runs the preprocessor for AC_CHECK_HEADERS (which doesn't use + CFLAGS) + +2009-12-17 Arjen de Korte + + * [r2178] m4/nut_check_libnetsnmp.m4: Set CPPFLAGS in case autoconf + only runs the preprocessor (which doesn't use CFLAGS) + * [r2177] m4/nut_check_libneon.m4: Cleanup autoconf macro + * [r2176] clients/upsimage.c: Remove redundant test (this is + already handled by autoconf) + * [r2175] Makefile.am: + * [r2174] configure.in: Keep defaults and checks together + * [r2173] drivers/bcmxcp.c: Automatic variables must have a length + that can be computed at compile time rather than runtime. GCC + will happily accept this C++ construction here, but this is not + C. + + Follow the same principle as used elsewhere in the code, by hard + coding this to PW_ANSWER_MAX_SIZE, the maximum size of replies we + expect. + +2009-12-16 Arjen de Korte + + * [r2172] m4/nut_check_libgd.m4: Check for all GD specific header + files while we're at it + * [r2171] clients/upsimage.c: The HAVE_GD_H should not be used + here, it is better to check for HAVE_LIBGD since that one is only + set if both the header file and the gd library are found (and not + just the first). + * [r2170] m4/nut_check_libnetsnmp.m4: Cleanup autoconf macro + * [r2169] m4/nut_check_libgd.m4: Cleanup GD autoconf stuff (also + fixes double -lgd linker flag) + * [r2168] configure.in, m4/nut_check_ipv6.m4, + m4/nut_check_libssl.m4, m4/nut_check_libwrap.m4: Cleanup some + autoconf macros + +2009-12-15 Arjen de Korte + + * [r2167] m4/nut_check_libnetsnmp.m4: Use AC_CHECK_HEADER to check + for required headers. + * [r2166] m4/nut_check_libwrap.m4: Fix autoconf magic for Solaris. + Apparently, allow/deny_severity are not defined as weak symbols, + so autoconf fails with undefined symbols when checking for the + library through AC_SEARCH_LIBS. + +2009-12-15 Charles Lepple + + * [r2165] include/common.h: Fix __attribute__ in common.h + + Patch provided by Tim Rice + http://lists.alioth.debian.org/pipermail/nut-upsdev/2009-December/004288.html + +2009-12-10 Arnaud Quette + + * [r2163] drivers/mge-utalk.c: complete r2151 with the + implementation details that were removed from the new mge-utalk + man page. + +2009-12-09 Arnaud Quette + + * [r2161] drivers/mge-hid.c: complete alarms and status handling + for Eaton / MGE / Dell. + +2009-12-04 Arnaud Quette + + * [r2153] m4/nut_check_libssl.m4: fix a wrong pkg-config call + parameter, that resulted in using pkg-config's own version + instead of OpenSSL's one. + +2009-12-02 Arnaud Quette + + * [r2148] drivers/libhid.c: skip reports 254/255 for Eaton / MGE / + Dell due to special handling needs + +2009-11-30 Arjen de Korte + + * [r2145] man/upsd.8, man/upsd.conf.5, man/upsd.users.5: Add + upgrading notes for versions earlier than nut-2.4.0 + * [r2143] drivers/usbhid-ups.c, drivers/usbhid-ups.h: Use contents + of interrupt report. In case these are broken, set 'pollonly' + flag in ups.conf or use_interrupt_pipe = FALSE in subdriver (when + device matches!) + +2009-11-26 Arjen de Korte + + * [r2141] man/usbhid-ups.8: Document the 'pollonly' flag + +2009-11-25 Arjen de Korte + + * [r2140] drivers/microdowell.c: Fix compiler warning (dead code, + no functional change) + * [r2139] drivers/usbhid-ups.c: Fix compiler warning + * [r2138] drivers/usbhid-ups.c: Add some USB error codes observed + in the field for possible future handling (and the comments from + the headerfiles where these are defined) + +2009-11-24 Arjen de Korte + + * [r2133] drivers/mge-hid.c: We already know if the value to the + reverse conversion functions should be a time or date value, so + there is no need to guess it. + +2009-11-23 Arnaud Quette + + * [r2128] drivers/mge-hid.c: - fix mge_time_date_conversion_nuf() + to actually use the input value + - force ignoring the DST offset for the output value + +2009-11-19 Arnaud Quette + + * [r2122] data/driver.list, drivers/libshut.c, man/mge-shut.8: Add + serial / SHUT support for the new Dell UPS range + - list all models in driver.list using newmge-shut, + - add "battery.runtime.elapsed" support, + - update mge-shut manual page and add an alias for newmge-shut. + +2009-11-19 Arjen de Korte + + * [r2121] drivers/mge-hid.c: Prefer to use non-negated logic when + possible (also minimizes changes) + +2009-11-19 Arnaud Quette + + * [r2119] data/driver.list, docs/new-names.txt, drivers/mge-hid.c, + man/usbhid-ups.8, scripts/dkp/95-devkit-power-hid.rules, + scripts/hal/ups-nut-device.fdi.in, + scripts/hotplug/libhid.usermap, scripts/udev/nut-usbups.rules.in: + Add USB support for the new Dell UPS range + - list all models in driver.list, + - add "battery.runtime.elapsed" in mge-hid.c and NUT namespace, + - adapt ups.model formating to Dell rules, + - update USB helper files, + - update usbhid-ups manual page. + +2009-11-18 Arjen de Korte + + * [r2118] drivers/netxml-ups.c: Re-subscribe to NMC when it doesn't + send us alarm messages anymore + +2009-11-18 Arnaud Quette + + * [r2117] drivers/mge-xml.c: minor typo fix on comment + +Mon Nov 16 01:57:23 UTC 2009 / Charles Lepple + + - drivers/tripplite_usb.c: fix copy-n-paste error in load.on instcmd. + +Fri Oct 9 11:26:49 UTC 2009 / Arjen de Korte + +- m4/nut_check_libssl.m4,nut_check_libusb.m4: show version information during + configuration + +Thu Oct 8 19:38:03 UTC 2009 / Arjen de Korte + + - m4/nut_check_libneon.m4,nut_check_libusb.m4: changes in autoconf magic to + detect optional functions (without making assumptions on where they are + located) + - configure.in: update for the above + - drivers/libusb.c,netxml-ups.c,richcomm_usb.c: update for the above + +Wed Oct 7 17:53:42 UTC 2009 / Arnaud Quette + + * drivers/dummy-ups.c: dummy-ups general improvements + - dummy mode now loop on reading the .dev file, instead of reading it once. + Interacting through this method is also possible, by changing the .dev file + content on the fly, + - dummy mode now support actions (TIMER only ATM) in the .dev file. This + allows to have an automated scripting sequence (see data/evolution.dev and + dummy-ups manpage for examples), + - repeater mode now check the upsd connection, and reconnect if needed, + (reported by Gabor Kiss) + - cleanup the inline TODO list, + - bump the driver version to 0.10. + * man/dummy-ups.8: update according to the above changes. + * data/epdu-managed.dev: new dummy-ups definition file. + +Wed Oct 7 14:05:35 UTC 2009 / Arjen de Korte + + - drivers/snmp-ups.c: remove suspicious code for shutdown.* commands + +Wed Oct 7 13:43:15 UTC 2009 / Arjen de Korte + + - drivers/apc-hid.c: add support for Back-UPS RS series test.battery.* + commands (experimental) + +Tue Oct 6 19:39:22 UTC 2009 / Arjen de Korte + + - m4/nut_check_libssl.m4: use pkg-config for compiler and linker flags + - m4/nut_check_libusb.m4: minor change + +Tue Oct 6 19:16:08 UTC 2009 / Arjen de Korte + + - MAINTAINERS: Remove entry for Peter Selinger (by request) + +Tue Oct 6 12:13:01 UTC 2009 / Arnaud Quette + + - drivers/mge-shut.c: actually apply the low battery level if provided (either + through "-x lowbatt" or ups.conf). Also change the driver reported name from + "MGE UPS SYSTEMS" to "Eaton". + (reported by Daniel O'Connor) + +Mon Oct 5 20:02:42 UTC 2009 / Arnaud Quette + + - drivers/nut_usb.c: remove the calls to usb_set_configuration() and + usb_set_altinterface(), which were not needed and caused troubles + with some Eaton / Powerware models. Also add some older HP T500 / T750 which + seem to be supported, + - data/driver.list: add entries for the above. + +Mon Sep 21 08:30:18 UTC 2009 / Arjen de Korte + + - drivers/tripplite-hid.c: add ECO550UPS to list of supported devices. + - data/driver.list: add an entry for the above. + +Sun Sep 20 19:06:34 UTC 2009 / Arjen de Korte + + - drivers/tripplite-hid.c: fix broken matcher function that would + unconditionally reject possibly supported devices, even when the + productid option was supplied. + +Tue Sep 15 09:06:32 UTC 2009 / Arnaud Quette + + - data/driver.list: add an entry for Eaton E Series DX UPS (1-20 kVA) with + mge-utalk. + +Tue Sep 15 08:16:32 UTC 2009 / Arnaud Quette + + - data/driver.list: add an entry for Eaton E Series NV UPS (400-2000 VA) with + megatec_usb (reported by Vitor Choi Feitosa). + +Tue Sep 8 18:57:51 UTC 2009 / Arjen de Korte + + - m4/nut_check_libnetsnmp.m4: check for presence of header files to see + if development files are installed + +Tue Sep 8 09:39:24 UTC 2009 / Arnaud Quette + + - drivers/ivtscd.c: complete general information (device.{mfr,model,type}), + - man/ivtscd.8, man/Makefile.am: add the manpage for ivtscd driver, + - data/driver.list: add an entry for IVT SCD-series devices. + +Fri Sep 4 08:36:21 UTC 2009 / Arnaud Quette + + - scripts/perl/Nut.pm: embed the NUT Perl client module, + (patch from Gabor Kiss) + - COPYING, scripts/README: update information for Perl module inclusion. + +Fri Sep 4 08:12:52 UTC 2009 / Arnaud Quette + + - drivers/apc-hid.c: fix input.transfer.reason support by using the standard + BOOL lookup mechanism (thanks Arjen), and bump the subdriver version to 0.94. + +Thu Sep 3 11:49:12 UTC 2009 / Arnaud Quette + + - drivers/apc-hid.c: add input.transfer.reason and input.sensitivity, along + with some more reverse engineered information. + (reported by Markus Wildi) + +Wed Sep 2 19:52:21 UTC 2009 / Arjen de Korte + + - drivers/ietfmib.h,drivers/mgemib.h: Indexes start at 1 (not 0). + +Tue Aug 25 20:40:28 UTC 2009 / Arjen de Korte + + - drivers/usbhid-ups.[ch]: remove delayed matching which wasn't really + useful, since it requires claiming the device, breaking any existing + bindings in the process (should also fix Alioth bug #311869) + +Tue Aug 18 01:22:14 UTC 2009 / Charles Lepple + + - drivers/bestfortress.c, man/bestfortress.8, data/driver.list: Resurrect the + bestfortress driver (submitted by Stuart D. Gathman) + +Sat Aug 15 17:42:49 UTC 2009 / Charles Lepple + + - drivers/cps-hid.c, data/driver.list: Add CyberPower OR2200 to usbhid-ups + (reported by James Erickson) + +Wed Aug 12 13:42:21 UTC 2009 / Arnaud Quette + + - data/drivers.list: also list Inform Informer Compact 1000VA with blazer_ser + (reported by Mutlu Tunç) + +Mon Aug 10 12:18:42 UTC 2009 / Arnaud Quette + + - drivers/mge-xml.c: add support for newer Eaton ePDU monitored + - man/netxml-ups.8: add a reference to Eaton ePDU monitored + - data/drivers.list: update the Eaton ePDU monitored to include netxml-ups + +Sun Aug 9 15:43:21 UTC 2009 / Arnaud Quette + + - data/drivers.list: add Inform Informer Compact 1000VA + (reported by Mutlu Tunç) + +Fri Jul 31 03:07:27 UTC 2009 / Charles Lepple + + - drivers/liebert.c: Hard-code the baud rate to 9600 to prevent problems with + noise. + +Wed Jul 29 01:37:06 UTC 2009 / Charles Lepple + + - data/driver.list: Add "CP 1500C" to compatibility list for usbhid-ups + (reported by Svein Skogen) + +Mon Jul 27 22:00:00 UTC 2009 / Arnaud Quette + + - tools/nut-usbinfo.pl, scripts/dkp/95-devkit-power-hid.rules: remove + the 0x prefix from the VendorIDs + +Mon Jul 27 11:21:21 UTC 2009 / Arnaud Quette + + - tools/nut-usbinfo.pl, scripts/dkp/95-devkit-power-hid.rules: generate + the DeviceKit-power rule file, so that it can be maintained up to + date from the NUT source. + +Mon Jul 20 19:20:35 UTC 2009 / Arjen de Korte + + - Renamed 'virtual' to 'clone' driver, to resolve a conflict with the + Postfix virtual domain mail delivery agent man pages + +Sat Jul 11 15:58:16 UTC 2009 / Charles Lepple + + * Makefile.am: Add "." to "find" command + +Sat Jul 11 14:25:00 UTC 2009 / Charles Lepple + + * drivers/nut_usb.c: Add usb_strerror() to USB error messages. + +Tue Jul 7 11:06:32 UTC 2009 / Arnaud Quette + + * device collection completion, for the transition period + - drivers/main.c: remap device.{mfr,model,serial} from the ups.* + equivalent, and preset device.type to ups so that it only has to be + overriden if necessary. + - drivers/skel.c: some update for the device collection + - docs/new-names.txt: add the device collection description + +Mon Jul 6 09:28:10 UTC 2009 / Arnaud Quette + + - drivers/tripplite.c: fix the reading with some SmartUPS models + (patch from Robert Waldie, Opengear) + +Tue Jun 30 13:28:42 UTC 2009 / Arnaud Quette + + - drivers/baytechmib.h: add outlet.{current,voltage} and fix some + comments (from Scott Burns, Opengear) + +Wed May 27 20:35:41 UTC 2009 / Arjen de Korte + + - clients/upsmon.c: multilevel debug information (similar to other NUT + binaries) + +Mon May 25 19:53:02 UTC 2009 / Arjen de Korte + + * Enable timestamp on debug messages by default + - common/common.c: prepend elapsed number of seconds and microseconds + since start of program for upsdebug() messages, + - drivers/upsdrvctl.c: inform people that adding debug flags to upsdrvctl + is not the way to debug a driver, + - revert remainder of previous patch + +Mon May 18 11:48:31 UTC 2009 / Arnaud Quette + + * Enable timestamp on output messages (format "%H:%M:%S: msg") + - common/common.c, include/common.h: modify vupslog() to allow optional + appending of a timestamp on debug output, + - clients/upsmon.c, drivers/main.c, drivers/upsdrvctl.c, server/upsd.c: + enable timestamping using the "-T" option, + - man/upsmon.8, man/nutupsdrv.8, man/upsdrvctl.8, man/upsd.8: document the + timestamp option. + +Thu May 14 19:19:52 UTC 2009 / Arnaud Quette + + - drivers/baytechmib.h: add native NUT support for Baytech SNMP PDUs (RPCs), + - drivers/snmp-ups.c: enable Baytech MIB, + - drivers/Makefile.am: add the new MIB file, + - data/driver.list: add the supported PDUs from BayTech, + - man/snmp-ups.8: document the new MIB and devices. + (patch from Scott Burns, Opengear) + +Thu May 14 21:06:11 UTC 2009 / Arnaud Quette + + - drivers/raritan-mib.h: use the outlets template mechanism and remove all + the OIDs defines for a better readability + - drivers/snmp-ups.c: enable Raritan MIB back. + +Thu May 14 19:19:52 UTC 2009 / Arnaud Quette + + - drivers/eaton-aphel-mib.h: use the outlets template mechanism. + +Thu May 14 14:44:22 UTC 2009 / Arnaud Quette + + - docs/configure.txt: a bit of completion and standardisation. + +Thu May 14 14:23:41 UTC 2009 / Arnaud Quette + + - drivers/snmp-ups.[ch]: add a template mechanism for outlets declaration, and + the needed helpers. Also disable temporarily the Raritan MIB as it conflicts + with Eaton (Aphel) . + +Wed May 13 13:54:32 UTC 2009 / Arnaud Quette + + - man/Makefile.am, man/nut.conf.5: add a manpage for nut.conf + (patch from Debian BTS, #528222) + +Tue May 05 13:26:21 UTC 2009 / Arnaud Quette + + - drivers/apcsmart.h: add support for older SmartUPS 600 responding to other + D codes (D7, D8 and D9) + (patch from Konstantin 'Kastus' Shchuka) + +Tue May 05 02:01:13 UTC 2009 / Charles Lepple + + - drivers/tripplite_usb.c, man/tripplite_usb.8, data/driver.list: update list + of units tested with tripplite_usb + +Mon May 04 08:11:01 UTC 2009 / Arnaud Quette + + - drivers/apcsmart.[ch]: add support for older SmartUPS, which do not respond + to the ^Z, a or b commands (used to inquire the supported data) + (patch from Thomas Juerges) + +Thu Apr 30 21:20:42 UTC 2009 / Arnaud Quette + + - data/driver.list: add Apollo 1000A and 1000F compatibility with genericups + upstype=4 (reported by mvochin) + +Thu Apr 23 12:46:12 UTC 2009 / Arnaud Quette + + - man/snmp-ups.8: remove the EXPERIMENTAL section to the profit of a LIMITATION + section. + +Fri Apr 17 13:26:21 UTC 2009 / Arnaud Quette + + - data/driver.list: add UPSonic DS-800 compatibility with megatec_usb + (reported by Nick Jenkins) + +Sun Mar 29 20:59:09 UTC 2009 / Arjen de Korte + + - drivers/netxml.c: Either do a quick poll or a complete poll (not both). + +Sun Mar 29 20:21:19 UTC 2009 / Arjen de Korte + + * clients/upsimage.c, clients/upsstats.c: + - Add ups.temperature, ambient.temperature and ambient.humidity (sorry folks, + Celsius only for now). + - The graph for the battery.charge now honors battery.charge.low for the red zone. + - The number of minor dashes for the battery.charge is reduced. + - Value on the scales is now right aligned. Display of negative values is corrected. + * conf/upsstats-single.html.sample: + - If ambient.(temperature|humidity) is supported, an 'Ambient' column is added to + display the bars for them. + +Thu Mar 26 20:04:53 UTC 2009 / Arjen de Korte + + * drivers/netxml.[ch], drivers/mge-xml.c: + - Allow multiple entry points for the initial XML page that is loaded + - Use different XML pages for quick and full status updates (the latter + is only polled once every 10 times) + +Mon Mar 23 17:34:10 UTC 2009 / Kjell Claesson + + - data/driver.list, add Eaton Powerware 9130 compatibility with bcmxcp and usbhid-ups. + +Sun Mar 22 01:13:18 UTC 2009 / Alexander I. Gordeev + + - drivers/blazer_usb.c: read data from device until timeout. + +Mon Mar 16 22:10:30 UTC 2009 / Kjell Claesson + + - drivers/bcmxcp.[ch]: Extend alarm map to fix debug crash on PW9130. Driver version 0.22. + +Wed Mar 04 19:37:12 UTC 2009 / Arnaud Quette + + - drivers/mge-utalk.c: fix enable_ups_comm() + (patch from Hans-Werner Paulsen) + +Sun Mar 01 19:51:54 UTC 2009 / Arnaud Quette + + - data/driver.list, drivers/tripplite-hid.c: add HP T750 INTL + (reported by KP Kirchdoerfer) + +Fri Feb 27 09:33:27 UTC 2009 / Arnaud Quette + + - data/driver.list: add Mustek PowerMust 424 / 636 / 848 (USB) compatibility + with blazer_usb (reported by Vitaly Polyakov) + +Fri Feb 27 09:07:05 UTC 2009 / Arnaud Quette + + - drivers/apcsmart.[ch]: add APC Matrix 5000, vintage 12/00 + (patch from Jarett Stevens) + +Tue Feb 17 22:00:01 UTC 2009 / Arnaud Quette + + - drivers/Makefile.am: Fix snmp-ups overlinking with lcrypto. + (Debian Lintian report) + +2.4.1 + +Mon Feb 16 17:41:32 UTC 2009 / Arnaud Quette + + - configure.in: 2.4.1 + +Mon Feb 16 16:13:47 UTC 2009 / David Goncalves + + - scripts/python/app/NUT-Monitor: Changed version from 1.0 to 1.1. Changed + the way NUT-Monitor deals with 'ups.status' var to better handle composite + status (OL + TRIM, OL + CHRG, ...) + +Thu Feb 12 13:23:41 UTC 2009 / Arnaud Quette + + - scripts/udev/Makefile.am, scripts/hal/Makefile.am, scripts/hotplug/Makefile.am, + Makefile.am: fix the autotools issue with the clean/distclean target removing + the USB helper files. + +Wed Feb 11 10:43:10 UTC 2009 / Kjell Claesson + + - data/driver.list: Updated list with ups supported by microdowell driver. + +Thu Feb 05 22:16:10 UTC 2009 / Kjell Claesson + + - drivers/microdowell.c: Cleaned some of the code. Fixed reading of ups.conf variables. + +Wed Feb 04 15:01:20 UTC 2009 / Kjell Claesson + + - Added microdowell.c/h into drivers/. add man/microdowell.8. Adjusted + drivers/Makefile.am and man/makefile.am. Adjusted the code for 2.4.0 + in the microdowell.c. + +*** File trimmed here 28 January 2009 *** + +For entries before this point, start with version 2.4.1 and work back. diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..ceb81b6 --- /dev/null +++ b/INSTALL @@ -0,0 +1,522 @@ +Network UPS Tools: INSTALL + +These are the essential steps for compiling and installing this +software, including configuring safe shutdowns when the UPS battery +runs out of power. + +There are many programs and other features in this package. You should +check out the README file and other accompanying documentation to see +how it all works. + +The paths shown below are the default values you get by just calling +configure by itself. If you have used --prefix or similar, things will +be different. Also, if you didn't install this program from source +yourself, the paths will probably have a number of differences. + +Note: by default, your system probably won't find the man pages, since +they install to /usr/local/ups/man. You can fix this by editing your +MANPATH, or just do this: + + man -M /usr/local/ups/man + + man -M /usr/local/ups/man upsd.conf + +Also, if your favorite system offers up to date binary packages, +always prefer these over a source installation. Along with the known +advantages of such systems for installation, upgrade and removal, there +are many integration issues that have been addressed. + +============================================================================ +============================================================================ +============================================================================ + + Prepare your system + =================== + + 1. Create at least one user and a group for running this software. You + might call them "ups" and "nut". The exact names aren't important as + long as you are consistent. + + The process for doing this varies from one system to the next, and + explaining how to add users is beyond the scope of this document. + + For the purposes of this document, the user name and group name + will be "ups" and "nut" respectively. + + Be sure the new user is a member of the new group! If you forget to + do this, you will have problems later on when you try to start upsd. + +============================================================================ +============================================================================ +============================================================================ + + Build and install + ================= + + + 1. Configure the source tree for your system. Add the --with-user and + --with-group switch to set the user name and group that you created + above. + + ./configure --with-user=ups --with-group=nut + + If you need any other switches for configure, add them here. For + example: + + * to build and install USB drivers, add --with-usb (note that you + need to install libusb development package or files). + + * to build and install SNMP drivers, add --with-snmp (note that + you need to install libsnmp development package or files). + + * to build and install CGI scripts, add --with-cgi. + + * to build and install NUT development files (needed to compile + WMNut and MGE PSP), add --with-lib. + + * to build and install HAL support, add --with-hal. + + See docs/configure.txt or "./configure --help" for the available + options. + + If you alter paths with additional switches, be sure to use those + new paths while reading the rest of the steps. + + *** Reference: docs/configure.txt + +--------------------------------------------------------------------------- + + 2. Build the programs. + + make + + This will build the NUT client and server programs and the + selected drivers. It will also build any other features that were + selected during configuration in step 1. above. + +--------------------------------------------------------------------------- + + 3. Gain privileges for installing software if necessary. + + su + +--------------------------------------------------------------------------- + + + 4. Install the files to a system level directory. + + make install + + This will install the compiled programs and man pages, as well as + some data files required by NUT. Any optional features selected + during configuration will also be installed. + + This will also install sample versions of the NUT configuration + files. Sample files are installed with names like ups.conf.sample + so they will not overwrite any existing real config files you may + have created. + + If you are packaging this software, then you will probably want to + use the DESTDIR variable to redirect the build into another place, + i.e.: + + make DESTDIR=/tmp/package install + make DESTDIR=/tmp/package install-conf + +--------------------------------------------------------------------------- + + 5. Create the state path directory for the driver(s) and server to use + for storing UPS status data and other auxiliary files, and make it + owned by the user you created. + + mkdir -p /var/state/ups + chmod 0770 /var/state/ups + chown root:nut /var/state/ups + +--------------------------------------------------------------------------- + + 6. Set ownership data and permissions on your serial or USB ports + that go to your UPS hardware. Be sure to limit access to just + the user you created earlier. + + These examples assume the second serial port (ttyS1) on a typical + Slackware system. On FreeBSD, that would be cuaa1. Serial ports + vary greatly, so yours may be called something else. + + chmod 0660 /dev/ttyS1 + chown root:nut /dev/ttyS1 + + The setup for USB ports is slightly more complicated. Device files + for USB devices, such as /proc/bus/usb/002/001, are usually + created "on the fly" when a device is plugged in, and disappear + when the device is disconnected. Moreover, the names of these + device files can change randomly. To set up the correct + permissions for the USB device, you may need to set up (operating + system dependent) hotplugging scripts. Sample scripts and + information are provided in the scripts/hotplug and + scripts/udev directories. For most users, the hotplugging scripts + will be installed automatically by "make install". + + (If you want to try if a driver works without setting up + hotplugging, you can add the "-u root" option to upsd, upsmon, and + drivers; this should allow you to follow the below + instructions. However, don't forget to set up the correct + permissions later!). + + NOTE: if you are using something like devfs or udev, make sure + these permissions stay set across a reboot. If they revert to the + old values, your drivers may fail to start. + +--------------------------------------------------------------------------- + + 7. Create one section per UPS in /usr/local/ups/etc/ups.conf + + To find out which driver to use, check the "HARDWARE SUPPORT TABLE" + in the README file, or data/driver.list. + + Once you have picked a driver, create a section for your UPS in + ups.conf. You must supply values for "driver" and "port". + + Some drivers may require other flags or settings. The "desc" value + is optional, but is recommended to provide a better description of + what your UPS is supporting. + + A typical UPS without any extra settings looks like this: + + [myupsname] + driver = mydriver + port = /dev/ttyS1 + desc = "Workstation" + + NOTE: usbhid-ups is a special case and ignores the "port" value. + You must still set this value, but it does not matter what you set + it to; you can set "port" to "auto" if you like. If you only own + one local UBS UPS, the driver will find it automatically. If you + own more than one UBS UPS, refer to the usbhid-ups(8) man page for + more information. + + *** References: man pages: ups.conf(5), nutupsdrv(8), plus + whatever driver(s) you intend to use. + +--------------------------------------------------------------------------- + + 8. Start the driver(s) for your hardware. + + /usr/local/ups/bin/upsdrvctl start + + Make sure the driver doesn't report any errors. It should show a + few details about the hardware and then enter the background. You + should get back to the command prompt a few seconds later. For + reference, a successful start of the belkin driver looks like this: + + # /usr/local/ups/bin/upsdrvctl start + Network UPS Tools - UPS driver controller 1.5.12 + Network UPS Tools - Belkin Smart protocol driver 0.21 (1.5.12) + Detected F6C525-SER on /dev/cuaa0 + # + + If the driver doesn't start cleanly, make sure you have picked the + right one for your hardware. You might need to try other drivers + by changing the "driver=" value in ups.conf. + + Be sure to check the driver's man page to see if it needs any extra + settings in ups.conf to detect your hardware. + + If it says "can't bind /var/state/ups/..." or similar, then your + state path probably isn't writable by the driver. Check the + permissions and mode on that directory (step 5). + + After making changes, try step 6 again. + + *** References: man pages: nutupsdrv(8), upsdrvctl(8) + +--------------------------------------------------------------------------- + + 9. Configure upsd, which serves data from the drivers to the clients. + + First, edit upsd.conf to allow access to your client systems. By + default, upsd will only listen to localhost port 3493/tcp. If you want + to connect to it from other machines, you must specify each interface you + want upsd to listen on for connections, optionally with a port number. + + LISTEN 127.0.0.1 3493 + LISTEN ::1 3493 + + Note: if you run a firewall of some sort, you may have to add rules + to allow these incoming connections. + + Next, create upsd.users. For now, this can be an empty file. + You can come back and add more to it later when it's time to + configure upsmon or run one of the management tools. + + Do not make either file world-readable, since they both hold + access control data and passwords. They just need to be readable by + the user you created in the preparation process. + + The suggested configuration is to chown it to root, chgrp it to the + group you created, then make it readable by the group. + + chown root:nut upsd.conf upsd.users + chmod 0640 upsd.conf upsd.users + + *** References: man pages: upsd.conf(5), upsd.users(5), upsd(8) + +--------------------------------------------------------------------------- + +10. Start the network server. + + /usr/local/ups/sbin/upsd + + Make sure it is able to connect to the driver(s) on your system. + A successful run looks like this: + + # /usr/local/ups/sbin/upsd + Network UPS Tools upsd 1.5.12 + Connected to UPS [belkin]: belkin-cuaa0 + Synchronizing...done + # + + upsd prints dots while it waits for the driver to respond. Your + system may print more or less depending on how many drivers you + have and how fast they are. + + NOTE: if upsd says that it can't connect to a UPS or that the data + is stale, then your ups.conf is not configured correctly, or you + have a driver that isn't working properly. You must fix this before + going on to the next step. + + *** Reference: man page: upsd(8) + +--------------------------------------------------------------------------- + +11. Make sure that the UPS is providing good status data. + + /usr/local/ups/bin/upsc myupsname@localhost ups.status + + You should see just one line in response: + + OL + + OL means your system is running on line power. If it says something + else (like OB - on battery, or LB - low battery), your driver was + probably misconfigured in step 7. If you reconfigure the driver, + use 'upsdrvctl stop' to stop it, then start it again in step 8. + + *** Reference: man page: upsc(8) + +--------------------------------------------------------------------------- + +12. Look at all of the status data which is being monitored. + + /usr/local/ups/bin/upsc myupsname@localhost + + What happens now depends on the kind of UPS and driver you have. + In the list, you should see ups.status with the same value you got + above. A sample run on a MGE UPS SYSTEMS Ellipse ASR 600 looks + like this: + + battery.charge: 82 + battery.charge.low: 30 + battery.runtime: 1563 + driver.name: usbhid-ups + driver.parameter.port: auto + driver.version: 2.0.3 + driver.version.data: MGE HID 0.8 + driver.version.internal: 0.28 + input.transfer.high: 264.0 + input.transfer.low: 184.0 + outlet.desc: Main Outlet + outlet.id: 1 + outlet.switchable: 0 + outlet.1.desc: PowerShare Outlet 1 + outlet.1.id: 2 + outlet.1.switch: 0 + outlet.1.switchable: 0 + output.voltage: 230.0 + ups.delay.shutdown: -1 + ups.delay.start: -10 + ups.load: 0 + ups.mfr: MGE UPS SYSTEMS + ups.model: Ellipse 600 + ups.power.nominal: 600 + ups.serial: AP8F15005 + ups.status: OB DISCHRG + + *** Reference: man page: upsc(8) + +--------------------------------------------------------------------------- + +13. Edit your startup scripts. + + Make sure upsdrvctl and upsd are run every time your system starts. + +============================================================================ +============================================================================ +============================================================================ + + Configuring shutdowns for low battery events + -------------------------------------------- + +The whole point of UPS software is to bring down the OS cleanly when you +run out of battery power. Everything else is just eye candy. To make +sure your system shuts down properly, you will need to perform some +additional configuration and run upsmon. Here are the basics: + +--------------------------------------------------------------------------- + + 1. Create a upsd user for upsmon to use while monitoring this UPS. + + Edit upsd.users and create a new section. upsmon will connect + to upsd and use this user name (in brackets) and password to + authenticate. This example is for a user called "monuser": + + [monuser] + password = mypass + upsmon master # or upsmon slave + + *** References: man pages: upsd(8), upsd.users(5) + +--------------------------------------------------------------------------- + + 2. Reload upsd. Depending on your configuration, you may be able to + do this without stopping upsd: + + /usr/local/ups/sbin/upsd -c reload + + If that doesn't work (check the syslog), just restart it: + + /usr/local/ups/sbin/upsd -c stop + /usr/local/ups/sbin/upsd + + Later: if you want to make reloading work, see the entry in the FAQ + about starting upsd as a different user. + +--------------------------------------------------------------------------- + + 3. Set the POWERDOWNFLAG location for upsmon. + + In upsmon.conf, add a POWERDOWNFLAG directive with a filename. + upsmon will create this file when the UPS needs to be powered off + during a power failure when low battery is reached. + + We will test for the presence of this file in a later step. + + POWERDOWNFLAG /etc/killpower + + *** References: man pages: upsmon(8), upsmon.conf(5) + +--------------------------------------------------------------------------- + + 4. Secure upsmon.conf. + + The recommended setting is to have it owned by root:nut, then + make it readable by the group and not world. This file contains + passwords that could be used by an attacker to start a shutdown, + so keep it secure. + + chown root:nut upsmon.conf + chmod 0640 upsmon.conf + + This step has been placed early in the process so you secure this + file before adding sensitive data in the next step. + +--------------------------------------------------------------------------- + + 5. Create a MONITOR directive for upsmon + + Edit upsmon.conf and create a MONITOR line with the UPS definition + (@), username and password from step 2, and + the master or slave setting. + + If it's the master (i.e., it's connected to this UPS directly): + + MONITOR myupsname@mybox 1 monuser mypass master + + If it's just monitoring this UPS over the network, and some other + system is the master: + + MONITOR myupsname@mybox 1 monuser mypass slave + + The number "1" here is the power value. This should always be set + to 1 unless you have a very special (read: expensive) system with + redundant power supplies. See big-servers.txt and data-room.txt. + + *** References: man pages: upsmon(8), upsmon.conf(5) + +--------------------------------------------------------------------------- + + 6. Define a SHUTDOWNCMD for upsmon. + + Still in upsmon.conf, add a directive that tells upsmon how to + shut down your system. This example seems to work on most systems: + + SHUTDOWNCMD "/sbin/shutdown -h +0" + + Notice the presence of "quotes" here to keep it together. + + If your system has special needs, you may want to set this to + a script which does local shutdown tasks before calling init. + +--------------------------------------------------------------------------- + + 7. Start upsmon. + + /usr/local/ups/sbin/upsmon + + If it complains about something, then check your configuration. + +--------------------------------------------------------------------------- + + 8. Look for messages in the syslog to indicate success. It should look + something like this: + + May 29 01:11:27 mybox upsmon[102]: Startup successful + May 29 01:11:28 mybox upsd[100]: Client monuser@192.168.50.1 + logged into UPS [myupsname] + + Any errors seen here are probably due to an error in the config + files of either upsmon or upsd. You should fix them before + continuing. + +--------------------------------------------------------------------------- + + 9. Edit your startup scripts: add upsmon + + Make sure upsmon starts when your system comes up. Do it after + upsdrvctl and upsd, or it will complain about not being able to + contact the server. + +--------------------------------------------------------------------------- + +10. Edit your shutdown scripts: add upsdrvctl shutdown + + You should configure your system to power down the UPS after the + filesystems are remounted read-only. Have it look for the presence + of the POWERDOWNFLAG (from upsmon.conf), using this as an example: + + if (test -f /etc/killpower) + then + echo "Killing the power, bye!" + /usr/local/ups/bin/upsdrvctl shutdown + + sleep 120 + + # uh oh... the UPS power-off failed + # you probably want to reboot here so you don't get stuck! + # *** see the section on power races in shutdown.txt! *** + fi + + Be careful: that upsdrvctl command will probably power off your + machine. Don't use it unless your system is ready to be halted by + force. If you run RAID, be sure the arrays are ready to lose power. + Your kernel's power-off routines may not execute. + + Make sure that the filesystem(s) holding your UPS drivers and + configuration details are still mounted when that part of the script + is run. You need upsdrvctl, ups.conf, and any drivers for the + hardware on your system. + +--------------------------------------------------------------------------- + +More information can be found in the README file, the shutdown.txt document, +the upsmon(8) man page and the upsmon.conf(5) man page. diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 0000000..7d403cc --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,66 @@ +In the tradition of stealing ideas for top-level files from the Linux +kernel tree, here is the NUT MAINTAINERS file. This file is intended to +help patch contributors route their changes to the right people. + +Note: just because something isn't listed in here doesn't mean it's not +being maintained. It just means that the maintainer hasn't sent me a +patch to update this file yet. + +Note 2: there are always other people who work on a project beyond those +who are listed here. Omission from this list should not be taken as a +slight. Those who are listed below are merely volunteering to be the +"lightning rods" for patches to certain parts of the tree. + +Fields +====== + +P: Person +M: Mail patches to this address +W: Web address +S: Status: + + Supported = someone is paid to do this + Maintained = someone keeps it running + + (add others as necessary) + +In the case of drivers, "maintained" should only be used if you have +access to the hardware in question for testing. + +Drivers +======= + +P: Russell Kroll +M: rkroll@exploits.org +S: Maintained: apcsmart, belkin, bestups, cyberpower, dummycons, + fentonups, driver core (main.c), upsdrvctl + +P: Arnaud Quette +M: aquette.dev@gmail.com +M: arnaud.quette@mgeups.com +S: Maintained or Supported: dummy-ups, usbhid-ups, mge-shut, newmge-shut + mge-utalk, snmp-ups, HAL support + +P: Arjen de Korte +M: arjen@de-korte.org +S: Maintained: safenet, genericups, powerpanel, netxml-ups, usbhid-ups + +P: Fabio Di Niro +M: blaxwan@users.sourceforge.net +S: Maintained: metasys + +Packaging +========= + +P: Nigel Metheringham +M: Nigel.Metheringham@dev.InTechnology.co.uk +S: Maintained: nut.spec.in (for Red Hat RPM builds) + +P: Arnaud Quette +M: aquette@debian.org +S: Maintained: Official Debian packages + +Everything else +=============== + +No other categories have been created yet. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..fea5ed4 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,87 @@ +# top-level Makefile for NUT + +# include directory for aclocal +ACLOCAL_AMFLAGS = -I m4 + +# subdirectories to build and distribute. The order matters, as +# several subdirectories depend on stuff in "common" being built first +SUBDIRS = include common clients conf data docs drivers lib man \ + tools scripts server + +EXTRA_DIST = MAINTAINERS UPGRADING + +# ---------------------------------------------------------------------- +# flags to pass to ./configure when calling "make distcheck" and "make +# distcheck-light". Try to check as many features as possible! Also +# need to give hotplug-dir and udev-dir, so that staged install does +# not fail. + +DISTCHECK_FLAGS = --with-all --with-ssl --with-ipv6 +DISTCHECK_LIGHT_FLAGS = --with-all=auto --with-ssl=auto --with-ipv6=auto + +DISTCHECK_CONFIGURE_FLAGS = ${DISTCHECK_FLAGS} \ + --with-hotplug-dir='$${prefix}/etc/hotplug' \ + --with-udev-dir='$${prefix}/etc/udev' + +distcheck-light: + $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_LIGHT_FLAGS)" distcheck + +# workaround the dist generated files that are also part of the distribution +distcleancheck_listfiles = \ + find . -type f -exec sh -c 'test -f $(srcdir)/{} || echo {}' ';' + +# ---------------------------------------------------------------------- +# targets from old build system (pre-automake). +# supported for a period of time for backward "compatibility". + +WARN="----------------------------------------------------------------------" + +build: + @echo $(WARN) + @echo "Warning: 'make build' is deprecated. Use 'make all' instead." + @echo $(WARN) + $(MAKE) $(AM_MAKEFLAGS) all +install-bin: + @echo $(WARN) + @echo "Warning: 'make install-bin' is deprecated." + @echo "Use 'make install-exec' instead for a similar effect." + @echo $(WARN) + cd common; $(MAKE) $(AM_MAKEFLAGS) install + cd drivers; $(MAKE) $(AM_MAKEFLAGS) install + cd server; $(MAKE) $(AM_MAKEFLAGS) install + cd clients; $(MAKE) $(AM_MAKEFLAGS) install +install-man: install-data-recursive + @echo $(WARN) + @echo "Warning: 'make install-man' is deprecated." + @echo "Use 'cd man; make install' instead." + @echo $(WARN) + cd man; $(MAKE) $(AM_MAKEFLAGS) install +install-conf: + @echo $(WARN) + @echo "Warning: 'make install-conf' is deprecated." + @echo "Use 'cd conf; make install' instead." + @echo $(WARN) + cd conf; $(MAKE) $(AM_MAKEFLAGS) install +# The target install-data already has a standardized meaning under automake +install-dirs: + @echo $(WARN) + @echo "Warning: 'make install-dirs' is deprecated." + @echo "Use 'make installdirs' instead." + @echo $(WARN) + make installdirs +cgi build-cgi install-cgi install-cgi-dir install-cgi-bin \ +install-cgi-man install-cgi-conf install-cgi-html: + @echo "Error: 'make $@' no longer exists." + @echo "Use './configure --with-cgi' instead." +install-lib: + @echo "Error: 'make $@' no longer exists." + @echo "Use './configure --with-lib' instead." +usb build-usb install-usb: + @echo "Error: 'make $@' no longer exists." + @echo "Use './configure --with-usb' instead." +snmp build-snmp install-snmp install-snmp-mgr install-snmp-man: + @echo "Error: 'make $@' no longer exists." + @echo "Use './configure --with-snmp' instead." +setver: + @echo "Error: 'make setver' no longer exists." + @echo "Edit configure.in to set version number." diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..7839a3a --- /dev/null +++ b/Makefile.in @@ -0,0 +1,839 @@ +# Makefile.in generated by automake 1.11 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# top-level Makefile for NUT +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/configure AUTHORS COPYING \ + ChangeLog INSTALL NEWS compile config.guess config.sub depcomp \ + install-sh ltmain.sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_create_stdint_h.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nut_arg_with.m4 \ + $(top_srcdir)/m4/nut_check_ipv6.m4 \ + $(top_srcdir)/m4/nut_check_libgd.m4 \ + $(top_srcdir)/m4/nut_check_libhal.m4 \ + $(top_srcdir)/m4/nut_check_libneon.m4 \ + $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ + $(top_srcdir)/m4/nut_check_libpowerman.m4 \ + $(top_srcdir)/m4/nut_check_libssl.m4 \ + $(top_srcdir)/m4/nut_check_libusb.m4 \ + $(top_srcdir)/m4/nut_check_libwrap.m4 \ + $(top_srcdir)/m4/nut_check_os.m4 \ + $(top_srcdir)/m4/nut_report_feature.m4 \ + $(top_srcdir)/m4/nut_type_socklen_t.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONFPATH = @CONFPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ +DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ +DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAL_CALLOUTS_PATH = @HAL_CALLOUTS_PATH@ +HAL_DEVICE_MATCH_KEY = @HAL_DEVICE_MATCH_KEY@ +HAL_FDI_PATH = @HAL_FDI_PATH@ +HAL_USER = @HAL_USER@ +HAVE_GLIB_2_14 = @HAVE_GLIB_2_14@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGD_CFLAGS = @LIBGD_CFLAGS@ +LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ +LIBHAL_CFLAGS = @LIBHAL_CFLAGS@ +LIBHAL_LDFLAGS = @LIBHAL_LDFLAGS@ +LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ +LIBNEON_LDFLAGS = @LIBNEON_LDFLAGS@ +LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ +LIBNETSNMP_LDFLAGS = @LIBNETSNMP_LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ +LIBPOWERMAN_LDFLAGS = @LIBPOWERMAN_LDFLAGS@ +LIBS = @LIBS@ +LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ +LIBSSL_LDFLAGS = @LIBSSL_LDFLAGS@ +LIBTOOL = @LIBTOOL@ +LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ +LIBUSB_LDFLAGS = @LIBUSB_LDFLAGS@ +LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ +LIBWRAP_LDFLAGS = @LIBWRAP_LDFLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NETLIBS = @NETLIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS_NAME = @OS_NAME@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +RUN_AS_GROUP = @RUN_AS_GROUP@ +RUN_AS_USER = @RUN_AS_USER@ +SED = @SED@ +SERLIBS = @SERLIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STATEPATH = @STATEPATH@ +STRIP = @STRIP@ +SUN_LIBUSB = @SUN_LIBUSB@ +VERSION = @VERSION@ +WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cgiexecdir = @cgiexecdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +driverexecdir = @driverexecdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +hotplugdir = @hotplugdir@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +udevdir = @udevdir@ + +# include directory for aclocal +ACLOCAL_AMFLAGS = -I m4 + +# subdirectories to build and distribute. The order matters, as +# several subdirectories depend on stuff in "common" being built first +SUBDIRS = include common clients conf data docs drivers lib man \ + tools scripts server + +EXTRA_DIST = MAINTAINERS UPGRADING + +# ---------------------------------------------------------------------- +# flags to pass to ./configure when calling "make distcheck" and "make +# distcheck-light". Try to check as many features as possible! Also +# need to give hotplug-dir and udev-dir, so that staged install does +# not fail. +DISTCHECK_FLAGS = --with-all --with-ssl --with-ipv6 +DISTCHECK_LIGHT_FLAGS = --with-all=auto --with-ssl=auto --with-ipv6=auto +DISTCHECK_CONFIGURE_FLAGS = ${DISTCHECK_FLAGS} \ + --with-hotplug-dir='$${prefix}/etc/hotplug' \ + --with-udev-dir='$${prefix}/etc/udev' + + +# workaround the dist generated files that are also part of the distribution +distcleancheck_listfiles = \ + find . -type f -exec sh -c 'test -f $(srcdir)/{} || echo {}' ';' + + +# ---------------------------------------------------------------------- +# targets from old build system (pre-automake). +# supported for a period of time for backward "compatibility". +WARN = "----------------------------------------------------------------------" +all: all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \ + distcheck distclean distclean-generic distclean-libtool \ + distclean-tags distcleancheck distdir distuninstallcheck dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am + + +distcheck-light: + $(MAKE) $(AM_MAKEFLAGS) DISTCHECK_FLAGS="$(DISTCHECK_LIGHT_FLAGS)" distcheck + +build: + @echo $(WARN) + @echo "Warning: 'make build' is deprecated. Use 'make all' instead." + @echo $(WARN) + $(MAKE) $(AM_MAKEFLAGS) all +install-bin: + @echo $(WARN) + @echo "Warning: 'make install-bin' is deprecated." + @echo "Use 'make install-exec' instead for a similar effect." + @echo $(WARN) + cd common; $(MAKE) $(AM_MAKEFLAGS) install + cd drivers; $(MAKE) $(AM_MAKEFLAGS) install + cd server; $(MAKE) $(AM_MAKEFLAGS) install + cd clients; $(MAKE) $(AM_MAKEFLAGS) install +install-man: install-data-recursive + @echo $(WARN) + @echo "Warning: 'make install-man' is deprecated." + @echo "Use 'cd man; make install' instead." + @echo $(WARN) + cd man; $(MAKE) $(AM_MAKEFLAGS) install +install-conf: + @echo $(WARN) + @echo "Warning: 'make install-conf' is deprecated." + @echo "Use 'cd conf; make install' instead." + @echo $(WARN) + cd conf; $(MAKE) $(AM_MAKEFLAGS) install +# The target install-data already has a standardized meaning under automake +install-dirs: + @echo $(WARN) + @echo "Warning: 'make install-dirs' is deprecated." + @echo "Use 'make installdirs' instead." + @echo $(WARN) + make installdirs +cgi build-cgi install-cgi install-cgi-dir install-cgi-bin \ +install-cgi-man install-cgi-conf install-cgi-html: + @echo "Error: 'make $@' no longer exists." + @echo "Use './configure --with-cgi' instead." +install-lib: + @echo "Error: 'make $@' no longer exists." + @echo "Use './configure --with-lib' instead." +usb build-usb install-usb: + @echo "Error: 'make $@' no longer exists." + @echo "Use './configure --with-usb' instead." +snmp build-snmp install-snmp install-snmp-mgr install-snmp-man: + @echo "Error: 'make $@' no longer exists." + @echo "Use './configure --with-snmp' instead." +setver: + @echo "Error: 'make setver' no longer exists." + @echo "Edit configure.in to set version number." + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..d47ff06 --- /dev/null +++ b/NEWS @@ -0,0 +1,979 @@ +If you're upgrading from an earlier version, see the UPGRADING file. + +For a complete list of changes, please refer to the ChangeLog file. + +--------------------------------------------------------------------------- +Release notes for NUT 2.4.3 - what's new since 2.4.2: + + - this is a bugfix release that only solves the regression on IPv6 activation. + +--------------------------------------------------------------------------- +Release notes for NUT 2.4.2 - what's new since 2.4.1: + + - the general USB support has been vastly improved, including many bug + fixes, better OS support, new features and devices. + + - NUT now talks to Solar Controller Devices with the new ivtscd driver. + + - the snmp-ups driver supports more PDU, with a smaller disk footprint. + + - apcsmart supports more older SmartUPS and Matrix units. + + - the bestfortress driver is resurrected. + + - the virtual driver has been renamed to 'clone'. + + - the netxml-ups driver has received some care. + + - various debugging and development improvements have been done, around + driver output; dummy-ups with more interaction and scripting and the + device-recorder.sh script. + + - the build system has received many bugfixes and improvements. + + - the UPower (previously known as DeviceKit-power) rules file is now + generated by NUT. + + - support for new devices: Apollo 1000A and 1000F; various Baytech RPC; old + Best Power Fortress; Cyber Power Systems PR3000E, CP 1500C and OR2200LCDRM2U; + all the new Dell UPS range (serial, USB and network); Eaton E Series NV and + DX UPS, and Powerware 9130; older HP T500 and T750, newer T750 INTL (USB) and + R1500 G2 (serial); Inform Informer Compact 1000VA; many serial and USB + devices from Ippon, like Back Comfo Pro, Smart Power Pro and Smart Winner; + IVT SCD series; Liebert GXT2-3000RT230 and PowerSure PSA; Mustek PowerMust + 424 / 636 / 848 USB; all new PowerCOM USB devices with HID PDC interface; + Tripp-Lite INTERNETOFFICE700, SMART700USB and ECO550UPS; UPSonic DS-800 + (USB). + +--------------------------------------------------------------------------- +Release notes for NUT 2.4.1 - what's new since 2.4.0: + + - the microdowell driver has appeared to support various MicroDowell Enterprise + units (see the "new devices" list below). + + - support for new devices: MicroDowell Enterprise B8, B10, N8, N11, N15, N20, + N22, N30, N40, N50, N60 and HiBox ST. + + - NUT-Monitor now better handles the ups.status field, and has switched to + version 1.1. + + - the situation of the build toolchain has been fixed, with regard to the + "make clean" target and the wrongly removed generated USB files. This brokes + further configure call. + +--------------------------------------------------------------------------- +Release notes for NUT 2.4.0 - what's new since 2.2.2: + + - preliminary support for Power Distribution Units (PDUs): NUT now support + PDUs, either natively (ie using NUT snmp-ups driver), or through a binding to + the Powerman daemon. The list of supported PDUs is already quite long, + including: Eaton ePDUs (Managed and Monitored), some Aphel models, some + Raritan PDUs, and the whole list of Powerman supported devices: + http://powerman.sourceforge.net/supported.html + + - support for new devices: the various PDUs cited above, Chloride Desk Power + 650, Cyber Power Systems Value 400E/600E/800E (USB models), Delta GES602N, + Digitus DN-170020, the whole Eaton ranges (mostly composed of MGE Office + Protection Systems and Powerware units) including BladeUPS, Forza Power + Technologies SL-1001, HP PowerTrust 2997A, HP R/T 2200 G2, Infosec XP 1000 + and XP 500, Ippon Back Power Pro (serial and USB), Kebo 1200D/D Series, + Liebert PowerSure Personal XT, MGE Office Protection Systems Protection + Station, Neus 400va and 600va, Phasak 400VA and 600VA, Plexus 500VA, Powercom + Black Knight PRO / King PRO and Imperial, PowerKinetics BlackOut Buster, + Sweex 1000 USB, UNITEK Alpha 500, WinPower CPM-800. + + - NUT now embeds Python client support through the PyNUTClient module and the + NUT-Monitor application. Both are from David Goncalves, and are still + available from http://www.lestat.st. + For more information, refer to scripts/python/README. + + - the dummy-ups driver now support a "repeater" mode. This allows it to act as + a NUT client, and to forward data. This can be useful for supervision and + load sharing purposes. + + - tcp-wrappers support has been added to the upsd server, to grant users access + by source IP for commands that require to be logged into the server. This + replaces the previous internal implementation (ACL in upsd.conf). + + - the nut.conf file has been introduced to standardize startup configuration + across the various systems. + + - NUT now ships a bash completion function for 'upsc' command + (scripts/misc/nut.bash_completion). Simply copy it to /etc/bash_completion.d + + - many internal changes to improve maintenability, while lowering the + maintenance cost (thus allowing developers to focus on what matters: the + code!). Examples of this are: + - the USB information automatic extraction to generate the various USB helper + files, + - the upsdrv_info_t structure to track more driver information, and remove + the need for the upsdrv_banner() function + - common USB code refactoring, as it is done for the serial functions. + + - tons of bugfixes, cleanup and improvements to make NUT stronger than ever! + +--------------------------------------------------------------------------- +Release notes for NUT 2.2.2 - what's new since 2.2.1: + + - support for new devices: APC BACK-UPS XS LCD, Atlantis Land, + Mustek Powermust Office 650, Oneac XAU models, Powerware PW5115 and + PW9120 (USB), Nitram Elite 2005 + + - Integrated Power Management (NUT HAL integration) has reached a + major milestone: it is now the most advanced UPS integration into + Power Management layer known in existing OSs. It has received many + corrections and improvements, and allows to PowerOff the UPS at the + end of a power cycle (which is the most important feature, not + supported on other systems). + The various files are now installed into the correct location. + + - the usbhid-ups driver has received attention. Most notably, the + shutdown handling has been reworked, and support for MGE UPS SYSTEMS + 3 phases units has been added. + + - snmp-ups now supports MGE* Environment Sensor (ref 66 846). + The ambient.temperature reporting has also been fixed for units + other than APC. + + - the netxml-ups driver has appeared to support MGE* network HTTP/XML + cards. + + - NUT now distributes by default the shared version of libupsclient + (version 1.0.0), and use this for the provided clients (upsmon, upsc, + upsrw, upscmd). This is part of an effort to reduce NUT's footprint, + both on disk and in memory. + + - powerpanel has reach a new step toward the replacement of nitram and + cpsups drivers. The final step is scheduled for NUT 2.4. + + - many changes, cleanup and fixes to the NUT core and various drivers. + +--------------------------------------------------------------------------- +Release notes for NUT 2.2.1 - what's new since 2.2.0: + + - support for new devices: all MGE Office Protection Systems units, + Advice TopGuard 2000, Belkin F6H375-USB, Dynamix UPS1700D, Effekta RM2000MH, + Jageson Technology Jasuny USPS, Powercom SMK-1500A and SXL-1500A, + PowerWalker Line-Interactive VI 400/800 and 600, Powerware 9110, + UNITEK Alpha 2600, UPSonic CXR1000, some vintage serial APC UPSs. + + - the usbhid-ups driver has been improved, and fixed in many areas, through + a backport of the development (trunk) version. + + - the udev rules, for Linux hotplug support of the USB UPSs, has been + updated to support kernel newer than 2.6.22. + + - the megatec and megatec_usb drivers have also been backported from the + development (trunk) version. + + - the client development files have also received some care: + the upsclient pkg-config file has been fixed, and the upsclient.h + file allows older NUT clients to continue using the UPSCONN structure. + +--------------------------------------------------------------------------- +Release notes for NUT 2.2.0 - what's new since 2.0.5: + + - The new build infrastructure, using automake, is now used. + This has major impact on the compilation and installation procedures, + and thus on the NUT packaging. + For more information, refer to UPGRADING and packaging/debian/ for + an example of migration. + + - NUT now provides support for FreeDesktop Hardware Abstraction Layer + (HAL) which brings full Plug And Play experience to USB UPS owners. + For more information, refer to docs/nut-hal.txt. + + - support for new devices: Ablerex 625L, ActivePower 400VA, 2000VA; + Belkin Home Office F6H350-SER, F6H500-SER, F6H650-SER; Belkin Office + Series F6C550-AVR; Belkin Universal UPS F6C100-UNV (USB), F6C1100-UNV + (USB), F6C1200-UNV (USB), F6H350deUNV (serial), F6H350ukUNV (serial), + F6H650ukUNV (serial); Compaq R3000h; Cyber Power Systems PR2200; + Dynex DX-800U; Geek Squad GS1285U; Krauler UP-M500VA; Mecer ME-2000; + MGE UPS SYSTEMS Ellipse MAX; Online Zinto D; PowerTech SMK-800; SVEN + Power Pro+ series, Power Smart RM 2000; Tripp-Lite SmartOnline + SU1500RTXL2ua, smart2200RMXL2U. + + - added IPv6 support, + + - the newmge-shut driver has appeared. This one uses the same HID core + as usbhid-ups, but communicate over a serial link. It will eventually + replace the current mge-shut driver. + + - client commands (upsc, upsrw and upscmd): hostname is now optional, + and defaults to "localhost" + + - many drivers have been improved and have received bug fixes: + powerpanel, megatec, megatec_usb, safenet, tripplite_usb, gamatronic, + + - the hotplug and udev scripts, in charge of setting the right + permissions on the USB devices, are now installed automatically + when appropriate. + + - more generally, the NUT core and documentation, including the manpages, + have been improved and updated. + +--------------------------------------------------------------------------- +Release notes for NUT 2.0.5 - what's new since 2.0.4: + + This release is a backport of the development version. Many changes + have already been backported previously. Thus it is more a + synchronisation release, though it includes many bugfixes and support + for new models. + + - support for new devices: APC Smart-UPS with 6TI firmware; Belkin + Small Enterprise F6C1500-TW-RK; Compaq R3000 XR, R5500 XR; Cyber + Power 550SL, 725SL, 685AVR, 800AVR, 1200AVR, AE550; Eltek; Inform + GUARD; Microsol Rhino; Opti-UPS PowerES 420E; PowerMan RealSmart, + BackPro; Powerware PW9315 3-phase; SOLA 305; Tripp-Lite + SMART550USB, SMART2200RMXL2U, OMNI1000LCD, OMNI900LCD, OMNI650LCD, + 1500 LCD, AVR550U; Viewsonic PowerES 420E. + + - bcmxcp: added 3-phase support + + - megatec: better hardware support, more instant commands + + - mge-hid: support more instant commands + + - newhidups: fixed APC and Tripp Lite bugs, various memory bugs, + improved report buffering, improved Solaris support, added + '-x explore' option for easy diagnosis of new devices + + - solis: shutdown programming, support new cables, Solaris support + + - tripplite_usb: updated SMARTPRO support, fixed OL/OB reporting, + better error handling, some memory bugs + + - new dummy-ups driver simulator + + - added HTML interface for access to CGI scripts + +--------------------------------------------------------------------------- +Release notes for NUT 2.0.4 - what's new since 2.0.3: + + - The newhidups critical bug (segmentation fault) has been fixed. It has + also received some more care, like buxfixes and new models support and + enhancement for Solaris. + [Peter Selinger and Arnaud Quette] + + - A bug has been fixed in NUT core to support resuming from suspend-to-disk. + This should also fix other similar issues, like time synchronisation + through the NTP - Network Time Protocol. + [Arjen de Korte] + + - The mge-shut driver now better detects the Low Battery status, support + new models and fixes some wrong status and data. It also fixes some + issue where the UPS wasn't restarting (refer to mge-shut manpage). + [Arnaud Quette] + + - The genericups custom configuration through ups.conf is working again + [Arjen de Korte] + + - The genericups driver type 22 also support CyberPower 725SL + (and maybe others SL models) + [David Kaufman] + + - The new megatec driver, which will replace a bunch of drivers by nut 2.2 + (refer to docs/megatec.txt and UPGRADING) has been backported from the + trunk (Development tree). The powermust driver has also received some + attention. + [Carlos Rodrigues] + + - The new rhino driver was added to support Microsol Rhino UPS hardware + The solis has also been improved for solaris compatibility, and + internal / external shutdown programming. solis can now save external + shutdown programming to ups, and support new cables for solis 3 + [Silvino B. Magalhães] + + - Several fixes and improvements have been made to upsrw, upsset, + cpsups, tripplite_usb and the FAQ. + [Arjen de Korte and Charles Lepple] + +--------------------------------------------------------------------------- +Release notes for NUT 2.0.3 - what's new since 2.0.2: + + - The recent and major newhidups changes have been backported from the + Development tree. It now: + - supports models from MGE UPS SYSTEMS, APC and Belkin. Mustek and Unitek + units are also recognized for development purpose, + - handles better device reopening, after a disconnection, + - handles multiple devices, with several parameters to find the right UPS. + [Peter Selinger, Charles Lepple and Arnaud Quette] + + - The bcmxcp_usb driver has been added to support Powerware USB units. + [Wolfgang Ocker and Kjell Claesson] + + - The tripplite_usb driver has been added to support Tripp Lite USB units. + [Charles Lepple] + + - The sec driver is back as gamatronic + [Gamatronic, Nadav Moskovitch] + + - The genericups driver has received official care from Gamatronic + to add support for the Gamatronic UPS with alarm interface. + [Gamatronic, Nadav Moskovitch] + + - The powermust driver now supports Soyntec Sekury C 500 and C 800 units. + [Hanno Borns] + + - The mge-shut driver has received a bit of attention too, and enhance + ups.model retrieval for some specific case (release 0.65) + + - The drivers don't change to the "statepath" directory anymore at + initialisation time if called using -k. This avoid unneeded + failure to poweroff the UPS if /var is already unmounted. + [Gaspar Bakos] + + - The belkinunv driver now supports Belkin F6C1100-UNV + [Dave Breiland] + + - The isbmex driver has been upgraded to version 0.05, which fixes + various errors in formulas, add shutdown capability and revert + back baudrate to B9600 (instead of B2400), as it broke the + communication + [Ricardo Martinezgarza] + + - The support of Sysgration UPGUARDS Pro650 in fentonups has + been fixed + [Simon J. Rowe] + + - The packaging files for Red Hat have received various fixes + [Thomas Jarosch] + + - The solis driver has been fixed to avoid a naming colision and + compile on Solaris + [Paweł Kierdelewicz] + + - The snmp-ups driver has corrected the problem when exposing + certain time data. + +--------------------------------------------------------------------------- +Release notes for NUT 2.0.2 - what's new since 2.0.1: + + - the newhidups USB driver has been improved a lot and is no more + experimental. It also now has a basic APC support, which will + soon replace the legacy hidups driver. + + - The mge-utalk driver has improved its support for old units. + + - The mge-shut driver has been improved for restart/shutdown + sequences which was previously blocking the serial port. + + - The general MGE support has been added Pulsar EXtreme C / EX RT, + Comet EX RT, Pulsar SV, Pulsar PSX, Ellipse Office and NOVA AVR USB. + + - The genericups driver now supports Generic RUPS 2000, AEC MiniGuard + UPS 700 (using Megatec M2501 cable), and Powerware 3110. + [Nick Barnes, Paul Andreassen] + + - The powermust driver now supports SquareOne Power QP1000, Mustek + PowerMust 1400VA Plus and 2000VA USB. + [Carlos Rodrigues] + + - The fentonups driver has been enhanced and now supports Sysgration + UPGUARDS Pro650. + [Michel Bouissou, Simon J. Rowe] + + - The cpsups driver now supports MicroDowell B.Box BP 500/750/1000/1500. + [Armin Diehl] + + - The snmp-ups driver now supports Socomec SNMP devices (Netvision MIB), + and Powerware ConnectUPS SNMP cards. + [Thanos Chatziathanassiou, Olli Salvia] + + - The bcmxcp driver is back with support for Powerware UPSs. + [Tore Øpetveit, Kjell Claesson] + + - The cyberpower driver now supports CyberPower 1000AVR. + [Dave Huang] + + - The new solis driver supports Microsol units: Solis 1.0, 1.5, + 2.0 and 3.0. + [Silvino B. Magalhaes] + + - The apcsmart driver has fixed APC600 support. + + - The etapro driver fixes brokeness due to ser_get_line use + [Marek Michalkiewicz] + + - The new upscode2 driver supports Fiskars, Compaq and Powerware + devices. + [Niels Baggesen, Havard Lygre] + + - The tripplite driver has fixed a battery charge bug + [Cedric Tefft] + +--------------------------------------------------------------------------- +Release notes for NUT 2.0.1 - what's new since 2.0.0: + + - The bestuferrups driver has been forked into the new bestfcom driver + which has better handling of the inverter status alarm messages and + more. + [Kent Hill] + + - Mustek UPS support returns with two drivers which have overlapping + coverage: mustek and powermust. + [powermust: Carlos Rodrigues, mustek: Martin Hajduch] + + - Additional CyberPower Systems hardware is supported with the new + cpsups driver. Three recognized models are the CPS1500AVR, + CPS1100VA, and OP500TE. + [Walt Holman, Brad Sawatzky] + + - The genericups driver can now generate staleness warnings in + specific cases where the UPS provides a way to test for its + presence. See the "CON" setting in ups.conf for more details. + [stan / saticed.me.uk] + + - Documentation for monitoring a Back-UPS RS 500 on a system without + USB ports has been added to the cables directory. + [Martin Edlman] + + - The everups driver now supports types 73-76 (NET 700/1000/1400/500-DPC) + [hunter] + + - The new metasys driver supports Meta System models: Line, + HF Millennium, HF Top Line, ECO Network, ECO, Ally HF, Megaline + [BlaXwan] + + - The ippon driver now allows user-defined settings for the delay + before switching off, and the delay before powering on. + [Yuri Elizarov] + + - The victronups driver is now at version 0.1.9, which adds many + instant commands: calibration control, battery and front panel tests, + and bypass control. + [Gert Lynge] + + - The tripplite driver has recieved a major overhaul to bring it up to + working condition for the 2.0 tree, including code cleanups, several + new variables, commands, and user-definable parameters. See + ChangeLog for more. + [Nicholas J Kain] + + - The mge-utalk driver has been upgraded to version 0.81, which fixes + the lack of read-write variables and loss of sync on models which + don't support restoring settings. + [Arnaud Quette] + + - The Micro Ferrups model RE is now supported by the bestuferrups + driver. The driver will also now read the ambient temperature and + will no longer constantly report the data as stale. + [Tim Thompson] + + - The fentonups driver's init sequence has been reworked to work better + with some hardware, including a fix to the parser code. + [MLH] + + - A workaround has been added to the hidups driver to avoid variables + which are stuck by calling HIDIOCINITREPORT in every poll. + [Stuart D. Gathman] + + - SOLA 610 UPS hardware and others which do not support the ID command + may now be monitored by the bestups driver after forcing ID= in + ups.conf. + [Jason White] + + - "pollinterval" is now available via driver.parameter for consistency. + [Arnaud Quette] + + - The mge-shut and newhidups drivers, along with the supporting + hidparser/libhid code have received many updates, including lowering + USB bandwidth consumption, driver unbinding (only in Linux), code + cleanups, and more which can be seen in the ChangeLog file. + [Arnaud Quette] + + - The fentonups driver now recognizes several more Megatec protocol + units: + + SuperPower HP360, Hope-550 [Denis Zaika] + Unitek Alpha 1000is [Antoine Cuvellard] + + - Some variables like uc_sigmask were renamed to avoid clashes with + symbols on systems like HP/UX. + + - All man pages have been reworked to switch literal "-" characters to + hyphens or "\-" as appropriate. + [Shaul Karl] + + - upssched's CANCEL events were broken following the change to + text-based socket messages in 1.5 and have been fixed. + [Steven Schoch] + + - Calls to varargs functions with raw strings from the config files + without an intervening "%s" have been fixed in upsmon, upssched, + snmp-ups and upsd. + [Ulf Harnhammar] + +--------------------------------------------------------------------------- +Release notes for NUT 2.0.0 - what's new since 1.4.x: + + - The new naming scheme for variables and commands (introduced in 1.4) + is now mandatory. The 1.4 tree supported both the old (STATUS) and + the new (ups.status) as a transitional release, and now that time is + over. + + This means that 2.0 is generally smaller than 1.4 code, since the + interim compatibility hacks have been removed. + + - New serial handling code has been added, with greatly simplified + operations. The old mess involving repeated calls to sigaction, + alarm, and read has been condensed to a select-read loop. + + This change allows drivers which don't do any serial communications + at all (hidups, snmp-ups) to drop that baggage, so they are a bit + smaller when compiled. + + - The drivers now recognize "chroot=' and 'user=' in the global section + of ups.conf. This means you don't have to use -r and -u when + starting upsdrvctl. + + - upsmon now supports the -K argument to check for the presence of the + POWERDOWNFLAG file. If it exists and contains the magic string, then + upsmon will exit(EXIT_SUCCESS). Otherwise, it will + exit(EXIT_FAILURE). + + This feature can be used to simplify shutdown scripts, since now you + don't have to keep the script in sync with the upsmon.conf. + + - Many small things like signed value comparisons, int vs. size_t and + proper use of const/struct were fixed throughout the source. These + were mostly for correctness, but a few potential bugs involving very + big or very small numbers were fixed at the same time. + + - The access control system in upsd.conf has been reworked and + simplified. Since access levels have become meaningless in recent + releases, the new system is just ACCEPT or REJECT . + + If you are upgrading from a previous version of the software, you + will have to edit your upsd.conf to use this method. See + the UPGRADING file for more details. + + - The build process now halts when make fails in one of the + subdirectories. + [Petter Reinholdtsen, Charles Lepple] + + - Helper data for using upsclient via pkgconfig is now created if + pkgconfig is detected when configure runs. + [Arnaud Quette] + + - The polling interval in drivers may now be set with 'pollinterval' + in ups.conf. + [Gabriel Faber] + + - Blazer UPS equipment is now supported with the blazer driver. + [Phil Hutton] + + - Energizer USB UPS hardware is now supported on Linux with a new + experimental driver. + [Viktor T. Toth] + + - The newhidups driver has been merged as the first step towards + portable USB UPS support. This will eventually replace the old + Linux-only hidups driver. The newhidups driver is tagged + experimental since it is under active development. + [Arnaud Quette, Charles Lepple] + + - The newapc driver has been renamed to apcsmart, replacing the old + driver with that name. If you used the newapc driver, be sure to + delete the old binary and fix your ups.conf. + + - The apcsmart driver now supports asynchronous notification data + from the hardware, which means it can wake up as soon as something + happens. This affects the OL/OB/LB/RB data in ups.status, and + generally reduces the latency in dispatching status changes by a few + seconds. + + - The apcsmart driver can now support quirky hardware which does not + provide the usual listing of valid command characters. This feature + is necessary to monitor new models like the APC CS 350 and old ones + like the Matrix 5000. It also now has sdtype=4 to handle the strange + shutdown behavior on the CS series. + + - The belkin driver now works around broken firmware version 001, + avoiding a lengthy delay at startup. It also implements the shutdown + sequence differently, and should actually work on more hardware now. + + - The bestups driver has been slowed down to play nicer with the + hardware, and is much more reliable as a result. Among other things, + it should always detect the UPS on the first try, meaning no more + "dot dot dot" when it starts. + + - The cyberpower driver is no longer tagged experimental, and now + supports powering off the load. It also supports battery tests via + instcmds. + + - Effekta MT 2000 RM hardware is now supported by the fentonups driver. + [christoph moar] + + - The new safenet driver supports UPS hardware that uses the protocol + of the same name. This includes models from many manufacturers, + including Fairstone, Fenton, Gemini, Powerwell, Repotec, Soltec and + Sweex. See the README or driver.list for the full details. + [Arjen de Korte] + + - The genericups driver now has type 20 to monitor the Powerware 5119 + RM. See http://lists.exploits.org/ups/Oct2003/00052.html. + [Daniel Thompson] + + - The belkinunv driver has been added to allow monitoring Belkin + Universal UPS hardware. + [Peter Selinger] + + - Cyber Power Systems 1100AVR hardware which has a different protocol + than the existing binary type (supported by 'cyberpower') is now + supported by the experimental cyberpower1100 driver. + [Walt Holman] + + - upsdrvctl now returns success or failure information in the exit + code. Any failure during a requested operation will result in a + nonzero value (specifically EXIT_FAILURE). + +--------------------------------------------------------------------------- +Release notes for NUT 1.4.0 - what's new since 1.2.x: + + - The drivers and upsd now communicate over Unix domain sockets instead + of state files, shared memory, or state files with mmap. This change + makes many things possible, including the new dynamic variable and + command naming scheme described below. + + There is a new development tool called sockdebug in the server + directory for debugging driver-server communications on the sockets. + + - The old static variable scheme has been replaced by a new dynamic + implementation. Vague names have been turned into meaningful names + that fit into an organized system. UTILITY is now input.voltage. + OUTVOLT is now output.voltage. + + This also applies to the names of instant commands. BTEST1 is + test.battery.start, and BTEST0 is test.battery.stop. + + The old names are still supported for compatibility with older + clients. This compatibility mode will be maintained throughout + the 1.4 series, and will be gone by the release of 2.0. Users + with older clients are encouraged to upgrade their software + during this time. + + - The network protocol has been expanded to handle these new names. + Older functions which only apply to the old names will continue to + be supported through the 1.4 series. + + - The drivers and server (upsd) can now change their user ids and + chroot themselves with the new -u and -r arguments. This lets you + create a "chroot jail" with the bare minimum components. + + This technique is used to provide a higher degree of security. If + someone exploited upsd to get a shell somehow, they would be stuck + in the jail. + + - upssched now explicitly confirms reception of timer commands before + exiting. This was done to avoid a race where one process would + exit right when another one was starting. The second one would + believe its command had been handled when it had been lost. + + - upslog has been reworked to use standard getopt parsing to provide + the monitoring settings. The old way of specifying arguments is + still supported for backwards compatibility. + + upslog has also been changed to only parse the format string once, + rather than doing it every time through the loop. This should + provide a minuscule drop in CPU utilization. + + - Usernames are now required in upsmon and upsd. This means that you + must add a username to your MONITOR lines in upsmon.conf and then + create a matching user in upsd.users. + + Installations from the 1.2 era probably already use usernames, so + this mostly affects those from 1.0 and before. + + - Drivers are now pinged regularly by upsd when they aren't posting + updates about the UPS status. This provides another check in the + data validation process. If upsd fails to get a response within + a few seconds, the UPS will be marked stale. + + - A few minor memory leaks were discovered with valgrind and squashed. + + - upsstats now reuses connections to upsd when cycling through multiple + entries in the hosts.conf. This makes things a bit faster and + avoids some of the noise in the syslog. + + This only applies to entries that are adjacent. To take advantage + of this feature, you may have to rearrange them. + + MONITOR ups-1@host-1 ... + MONITOR ups-1@host-2 ... + MONITOR ups-2@host-2 ... + MONITOR ups-3@host-3 ... + + Connection reuse for nonadjacent entries may be considered in the + future. + + - upsd now warns about insecure configuration files at startup. + These files (upsd.conf, upsd.users, and the certfile) should + only be readable by upsd. Never make them world-readable. + + - The programs no longer print "shutting down" when they are just + exiting. This was changed to avoid confusion about the term, since + "shutting down" has a special meaning in UPS software. + + - Signal handlers no longer do any significant amount of work. Some of + the programs used to do numerous things in there, raising concerns + about reentrancy. They now set flags and allow the main loop to do + the actual work from there. + + - A bug in upsmon where NOTIFYFLAG settings could be ignored was fixed. + + - Group handling has been changed. configure no longer accepts + --with-group, and the programs no longer setgid() to a hardcoded + value. They now setgid() to the primary group of whatever the + user value may be. + + This may be compiled in with --with-user as before, and many programs + accept -u to override it at runtime. + + - The state path is no longer created during 'make install'. Users + are now expected to create it themselves. This removes a lot of + evil complexity from the build and install sequences. + + - upsd no longer implements the DROP access command, as it + could confuse the clients by getting them out of sync. DROP is now + implemented as DENY, which sends an error message. If you use DROP, + you should change it to DENY rather than relying on this + compatibility measure. + + - The belkin driver no longer reports OFF and OL at the same time. + + - The bestups driver no longer sleeps during polls, which makes it + more responsive to things like instant commands. + + - The cyberpower driver now has much better hardware detection code + and no longer freezes at startup under some conditions. It also now + supports the shutdown function. Instant commands for shutdowns and + battery tests were also added. + + - The dummyups testing driver has been removed. The dummycons testing + driver can do everything that dummyups once did and much more. + dummycons is also now built by default for easier testing. + + - The newapc driver has been reworked to take advantage of the new + internal driver state functions. Some variables without an obvious + purpose were dropped. + + - The newapc driver now sends all five bytes when using sdtype 1. + Previously it didn't send the entire string, and it didn't work. + [Don Lewis] + + - The hidups driver has been expanded to allow for setting variables, + a shutdown sequence, and more. + [Arnaud Quette] + + - The mge-utalk driver had trouble establishing communications in + some cases due to the RTS line being set. This has been fixed. + + The mge-shut driver has been added to the tree, and has replaced + the older mge-ellipse driver. + [Arnaud Quette, Philippe Marzouk] + + - Outlet-level control has been defined in the variable tree, and will + be added to drivers where the hardware supports it. This can be + used to shut down some components earlier than others to prolong + your runtime on battery. + + This is supported in the mge-shut driver now, and may show up in + others before long. + [Arnaud Quette] + + - KIN-2200AP hardware is now recognized by the powercom driver. + This change may also support other KIN-xxxxAP equipment. + [Preston A. Elder] + + - The 1.1kVA UPS is now supported by the bestuferrups driver. This + driver was also changed to allow easy addition of more models + in the future. + [Bob Apodaca] + + - The fentonups driver can now handle devices which implement the + "I" detection differently, and now supports the Giant/WELI 500 + as a result. + [Joon Guillen] + + - The serial number of the UPS being monitored can now be specified + with serial= in ups.conf in the genericups driver. + [Shaul Karl] + + - The newapc driver now sends ESC to break out of menus when the + initial detection fails. Some new APC models have interactive menus + on the serial port, and the driver couldn't handle them before. + + - The snmp-ups driver now reports ambient temperature and humidity + data for APC equipment. It also now supports the shutdown.reboot and + shutdown.reboot.graceful commands. + [Dmitry Frolov] + + - The list of supported variables and commands in the snmp-ups driver + has been expanded. + [Arnaud Quette, J.W. Hoogervorst] + + - Various drivers now report bypass mode with the BYP status word. + [Arnaud Quette] + + - Energy Sistem equipment is now supported with the esupssmart driver. + [Antonio Trujillo Coronado] + + - The Tripp-Lite SU series (SmartOnline) is supported with the new + tripplitesu driver. + [Allan Hessenflow] + + - The HP PowerTrust A2994A is now recognized by the hp driver. + [Jan Sporbeck] + + - Many drivers were cleaned up to perform basic sanity checks on the + status data before using it. + + - An explicit cleanup function has been added to the driver core to + ensure that all dynamic resources are freed before exiting. This + is part of the larger process to check for memory leaks and other + bad things. + [Arnaud Quette] + + - upsd now provides variable descriptions from an auxiliary file. + This file is optional, which allows for a smaller memory footprint. + It can also be edited for localization or other customizations. + + - upsimage and upsstats can now render BATTVOLT data. + [Andrew R. Ghali] + + - String handling has been cleaned up throughout the tree. Calls to + functions like strcpy and strcat were either replaced with other + (range-checking) functions or were rewritten to avoid it. + + - Many compile-time defaults may now be overridden at runtime. In + the environment NUT_CONFPATH and NUT_STATEPATH may be used. + upsdrvctl has been changed to execve to pass these along to the + drivers. ups.conf now supports driverpath=, and upsd.conf supports + DATAPATH. + [Bryan Henderson] + + - The configure --with-gd switches now actually do something useful + when gd has been installed outside the default search directories. + [Patrik Schindler] + + - The inline keyword is now handled properly on systems which do not + support it or have it specified as another name. This was breaking + compiles on some systems. + [Petter Reinholdtsen] + +--------------------------------------------------------------------------- +Release notes for NUT 1.2.2 - what's new since 1.2.1: + + - The snmp-ups driver has been upgraded and expanded. It now supports + multiple MIBs, meaning it can handle RFC 1628, APCC, and MGE + equipment. You can pick the right one with "mibs=" in ups.conf. + + Support for setting variable and instant commands is also available. + [Arnaud Quette and Dmitry Frolov] + + - The powernet driver has been upgraded. It now supports more + variables, has cleaner logging, and may now be considered stable. + [Dmitry Frolov] + + - The hidups driver now supports physical port IDs. This avoids most + of the problems where the hiddev* names can jump around too easily. + It will now stay in the same place as long as you keep it plugged + into the same physical port. See the ChangeLog file for more details. + [David Brownell] + + - The hidups driver now also supports the MFR variable on APC + Back-UPS ES equipment. + [Jonathan A. Davis] + + - The sms driver has been updated to version 0.70. + [Marcio Gomes] + + - The bestups driver now recognizes Best Power Axxium Rackmount + equipment. + [Ales Casar] + + - The liebert driver now uses O_NONBLOCK, and should now work + consistently on OpenBSD as a result. + [Alex Cichowski] + + - The liebert driver also now uses debouncing logic on the status + lines. It was possible to get false readings that would start a + shutdown or just annoy users with excessive onbatt/online notify + messages. The new code forces the status to settle down for 3 polls + before accepting the new value. + + This means that very short power events may not be detected. The + alternative is having your machine shut down just because it decided + to wiggle over to OB LB for a few seconds. + + - upsmon has had the disconnect logic fixed so the "communications + lost" (COMMBAD) notify will actually go out when the connection + fails. + [Steve Monett] + + - upssched now uses a lock file to prevent a race where two could + start at the same time. The second upssched would "win", and the + first one would be unreachable. This had the side-effect of not + being able to cancel timers on the first one. + + If you use upssched, you must define the LOCKFN directive when + upgrading to this version, or it will not work. + [Gaspar Bakos] + + - The packaging and scripts for Red Hat systems have been updated. + [Antonino Albanese] + + - upsd is now a bit more lenient about access levels in the + 'numlogins' check, which is what caused the problem in upsmon + (next item). + + - upsmon no longer gets stuck in slavesync() when upsd is configured + to drop certain queries. This usually happened at the worst + possible time: in the middle of a shutdown. + [John David Garza] + + - The upsclient functions now do more sanity checking on data from + upsd so a short read won't return garbage to the callers. + + - upsset now works properly with ENUM/VARTYPE values for multiple + UPSes on a single upsd. + [Dmitry Frolov] + + - Various portability fixes for building on SGI were applied. + [Andrea Suatoni] + + - upsd no longer tries to reference a deleted client structure if the + client disconnects at the wrong time. Previously, it tried to use + that pointer after the sendback() function had already failed on + write and deleted the client. This could cause upsd to segfault + depending on what areas were accessed. + [Patrik Schindler] + +--------------------------------------------------------------------------- + +Release notes for NUT 1.2.1 - what's new since 1.2.0: + + - The sms driver is back, with support for Microlink Manager III + hardware. [Marcio Gomes] + + - Fideltronik Ares Series hardware is now supported as genericups type + 19. [Tomek Orzechowski and Arkadiusz Mikiewicz] + + - The drivers no longer silently drop instant commands or set commands + from upsd that happen to get fragmented in transit. + [linux@horizon.com] + + - The old multilink driver is back with a new name: liebert. It + supports Liebert UPStation GXE hardware with the contact-closure + cable. This is currently an experimental driver as there is no + way to power down the load. + + - configure now picks up the right flags for gd automatically if gd + 2.0.8 or higher is installed. This greatly simplifies the CGI build + process for most users. + + - Shutdowns on FreeBSD using the genericups driver should work again. + [Petri Riihikallio] + +--------------------------------------------------------------------------- diff --git a/README b/README new file mode 100644 index 0000000..c43679b --- /dev/null +++ b/README @@ -0,0 +1,659 @@ +================================= + Network UPS Tools Documentation +================================= + +:Info: Program support page: +:Author: Arnaud Quette and others, see AUTHORS file. +:Copyright: Released under the GNU GPL - see COPYING for details. + +Mailing list details: http://alioth.debian.org/mail/?group_id=30602 + +.. contents:: + +=========== +Description +=========== + +Network UPS Tools is a collection of programs which provide a common +interface for monitoring and administering UPS and PDU hardware. NUT comes in +two flavors: the "classic" and the "HAL enabled" one. + +The "classic" flavor +-------------------- + +It is the standard installation that uses a layered approach to connect +all of the NUT parts. + +Drivers are provided for a wide assortment of equipment. They +understand the specific language of each device and map it back to a +compatibility layer. This means both an expensive "smart" protocol UPS +and a simple "power strip" model can be handled transparently. + +This information is cached by the network server ``upsd``, which then +answers queries from the clients. upsd contains a number of access +control features to limit the abilities of the clients. Only authorized +hosts may monitor or control your hardware if you wish. Since the +notion of monitoring over the network is built into the software, you +can hang many systems off one large UPS and they will all shut down +together. You can also use NUT to power on, off or cycle your data centers +nodes, individually or globally through PDUs outlets. + +Clients such as upsmon check on the status of the hardware and do things +when necessary. The most important task is shutting down the operating +system cleanly before the UPS runs out of power. Other programs are +also provided to log UPS status regularly, monitor status through your +web browser, and more. + +The "HAL enabled" flavor +------------------------ + +This one is intended for use: + +- with supported USB UPS, +- on HAL enabled systems (Linux, FreeBSD, Sun Solaris), +- on HAL enabled desktops (Gnome and possibly KDE) + +Using this approach, you don't have to configure NUT files, nor to +manually start components, nor to install a specific NUT client. + +Upon plugging your USB UPS, the right driver will be automatically +launched, and the according Power Manager GUI will pop up. + +Note that this feature is still beta and incomplete. But it +represents a major evolution, and a huge user experience improvement! + +For more information, refer to INSTALL and docs/nut-hal.txt. + +========== +Installing +========== + +If you are installing these programs for the first time, go read the +INSTALL file to find out how to do that. This document contains more +information on what all of this stuff does. + + +========= +Upgrading +========= + +When upgrading from an older version, always check the UPGRADING file to +see what may have changed. Compatibility issues and other changes will +be listed there to ease the process. + + +============= +Documentation +============= + +This file gives an overview of the software. You should read the man +pages, included example configuration files, and auxiliary documentation +for the parts that you intend to use. + + +=================== +Network Information +=================== + +These programs are designed to share information over the network. In +the examples below, ``localhost`` is used as the hostname. This can also +be an IP address or a fully qualified domain name. You can specify a +port number if your upsd process runs on another port. + +In the case of the program ``upsc``, to view the variables on the UPS called +sparky on the ``upsd`` server running on the local machine, you'd do this:: + + /usr/local/ups/bin/upsc sparky@localhost + +The default port number is 3493. You can change this with +"configure --with-port" at compile-time. To make a client talk to upsd +on a specific port, add it after the hostname with a colon, like this:: + + /usr/local/ups/bin/upsc sparky@localhost:1234 + +This is handy when you have a mixed environment and some of the systems +are on different ports. + +The general form for UPS identifiers is this:: + + [@[:]] + +Keep this in mind when viewing the examples below. + + +======== +Manifest +======== + +This package is broken down into several categories: + +- *drivers* - These programs talk directly to your UPS hardware. + +- *server* - upsd serves data from the drivers to the network. + +- *clients* - They talk to upsd and do things with the status data. + +- *cgi-bin* - Special class of clients that you can use with your web server. + + +======= +Drivers +======= + +These programs provide support for specific UPS models. They understand +the protocols and port specifications which define status information +and convert it to a form that upsd can understand. + +To configure drivers, edit ups.conf. For this example, we'll have a UPS +called "sparky" that uses the apcsmart driver and is connected to +``/dev/ttyS1``. That's the second serial port on most Linux-based systems. +The entry in ``ups.conf`` looks like this:: + + [sparky] + driver = apcsmart + port = /dev/ttyS1 + +To start and stop drivers, use upsdrvctl. By default, it will start or +stop every UPS in the config file:: + + /usr/local/ups/bin/upsdrvctl start + /usr/local/ups/bin/upsdrvctl stop + +However, you can also just start or stop one by adding its name:: + + /usr/local/ups/bin/upsdrvctl start sparky + /usr/local/ups/bin/upsdrvctl stop sparky + +To get the driver name for your device, refer to the below section +called "HARDWARE SUPPORT TABLE". + +Extra Settings +-------------- + +Some drivers may require additional settings to properly communicate +with your hardware. If it doesn't detect your UPS by default, check the +driver's man page or help (-h) to see which options are available. + +For example, the apcsmart driver allows setting "cable" to "940-0095B". +To use this feature, just add another line to your ups.conf section for +that UPS:: + + [sparky] + driver = apcsmart + port = /dev/ttyS1 + cable = 940-0095B + +Hardware Support Table +---------------------- + +The NUT Hardware support table is available in the source directory: + + nut-X.Y.Z/data/driver.list + +This one should also be distributed with your favorite packages. +For example, it is available on Debian systems as: + + /usr/share/nut/driver.list + +For another take on this list, try the web page: + + http://random.networkupstools.org/compat/ + +If your driver has vanished, see the FAQ and UPGRADING files. + +Generic UPS Driver +------------------ + +The ``genericups`` driver will support many models that use the same basic +principle to communicate with the computer. This is known as "contact +closure", and basically involves raising or lowering signals to indicate +power status. + +This type of UPS tends to be cheaper, and only provides the very simplest +data about power and battery status. Advanced features like battery +charge readings and such require a "smart" UPS and a driver which +supports it. + +See the genericups(8) man page for more information. + +There is also a document called contact-closure.txt included with the +source distribution that contains information on this kind of hardware +and details on adding additional types to the genericups driver. + +UPS Shutdowns +------------- + +upsdrvctl can also shut down (power down) all of your UPS hardware. + +**WARNING:** if you play around with this command, expect your filesystems +to die. Don't power off your computers unless they're ready for it:: + + /usr/local/ups/bin/upsdrvctl shutdown + /usr/local/ups/bin/upsdrvctl shutdown sparky + +You should read the shutdown.txt file in the docs subdirectory to +learn more about when to use this feature. If called at the wrong time, +you may cause data loss by turning off a system with a filesystem +mounted read-write. + + +============== +Network Server +============== + +``upsd`` is responsible for passing data from the drivers to the client +programs via the network. It should be run immediately after ``upsdrvctl`` +in your system's startup scripts. + +``upsd`` should be kept running whenever possible, as it is the only source +of status information for the monitoring clients like ``upsmon``. + + +====== +upsmon +====== + +``upsmon`` provides the essential feature that you expect to find in UPS +monitoring software: safe shutdowns when the power fails. + +In the layered scheme of NUT software, it is a client. It has this +separate section in the documentation since it is so important. + +You configure it by telling it about UPSes that you want to monitor in +upsmon.conf. Each UPS can be defined as one of three possible types: + +- Master + + This UPS supplies power to the system running upsmon, and + this system is also responsible for shutting it down when + the battery is depleted. This occurs after any slave systems + have disconnected safely. + + If your UPS is plugged directly into a system's serial port, + the upsmon on that system should define that UPS as a master. + +- Slave + + This UPS supplies power to the system running upsmon, but + this system can't shut it down directly. This system will + shut down the operating system before the master turns off the + power. + + Use this mode when you run multiple computers on the same UPS. + Obviously, only one can be connected to the serial port on the + UPS, and that system is the master. Everything else is a + slave. + +- Monitor-only + + This UPS will still generate notifications about status + changes (on battery, on line, etc.) but no shutdowns of the + local system result from critical situations on that UPS. + +For a typical home user, there's one computer connected to one UPS. +That means you run a driver, upsd, and upsmon in master mode. + +Additional Information +---------------------- + +More information on configuring upsmon can be found in these places: + + - The man page - upsmon(8) + + - big-servers.txt in the docs subdirectory + + - shutdown.txt in the docs subdirectory + + - The stock upsmon.conf that comes with the package + + +======= +Clients +======= + +Clients talk to upsd over the network and do useful things with the data +from the drivers. There are tools for command line access, and a few +special clients which can be run through your web server as CGI +programs. + +For more details on specific programs, refer to their man pages. + +upsc +---- + +upsc is a simple client that will display the values of variables known +to upsd and your UPS drivers. It will list every variable by default, +or just one if you specify an additional argument. This can be useful +in shell scripts for monitoring something without writing your own +network code. + +upsc is a quick way to find out if your driver(s) and upsd are working +together properly. Just run upsc to see what's going on, i.e.:: + + morbo:~$ upsc su700@localhost + ambient.humidity: 035.6 + ambient.humidity.alarm.maximum: NO,NO + ambient.humidity.alarm.minimum: NO,NO + ambient.temperature: 25.14 + + [ and so on ] + +If you are interested in writing a simple client that monitors upsd, +the source code for upsc is a good way to learn about using the +upsclient functions. + +See the upsc(8) man page for more information. + +upslog +------ + +upslog will write status information from upsd to a file at set +intervals. You can use this to generate graphs or reports with other +programs such as gnuplot. + +upsrw +----- + +upsrw allows you to display and change the read/write variables in your +UPS hardware. Not all devices or drivers implement this, so this may +not have any effect on your system. + +A driver that supports read/write variables will give results like this:: + + $ upsrw su700@localhost + + ( many skipped ) + + [ups.test.interval] + Interval between self tests + Type: ENUM + Option: "1209600" + Option: "604800" SELECTED + Option: "0" + + ( more skipped ) + +On the other hand, one that doesn't support them won't print anything:: + + $ upsrw fenton@gearbox + + ( nothing ) + +upsrw requires administrator powers to change settings in the hardware. +Refer to upsd.users(5) for information on defining users in upsd. + +upscmd +------ + +Some UPS hardware and drivers support the notion of an instant command - +a feature such as starting a battery test, or powering off the load. +You can use upscmd to list or invoke instant commands if your +hardware/drivers support them. + +Use the -l command to list them, like this:: + + $ upscmd -l su700@localhost + Instant commands supported on UPS [su700@localhost]: + + load.on - Turn on the load immediately + test.panel.start - Start testing the UPS panel + calibrate.start - Start run time calibration + calibrate.stop - Stop run time calibration + + [ snip ] + +upscmd requires administrator powers to start instant commands. +To define users and passwords in upsd, see upsd.users(5). + +============ +CGI Programs +============ + +The CGI programs are clients that run through your web server. They +allow you to see UPS status and perform certain administrative commands +from any web browser. Javascript and cookies are not required. + +These programs are not installed or compiled by default. To compile +and install them, first run 'configure --with-cgi', then do 'make' and +'make install'. If you receive errors about "gd" during configure, go +get it and install it before continuing. + +You can get the source here: + + http://www.boutell.com/gd/ + +In the event that you need libpng or zlib in order to compile gd, +they can be found at these URLs: + + http://www.libpng.org/pub/png/pngcode.html + + http://www.gzip.org/zlib/ + +Access Restrictions +------------------- + +The CGI programs use hosts.conf to see if they are allowed to talk to a +host. This keeps malicious visitors from creating queries from your web +server to random hosts on the Internet. + +If you get error messages that say "Access to that host is not +authorized", you're probably missing an entry in your hosts.conf. + +upsstats +-------- + +upsstats generates web pages from HTML templates, and plugs in status +information in the right places. It looks like a distant relative of +APC's old Powerchute interface. You can use it to monitor several +systems or just focus on one. + +It also can generate IMG references to upsimage. + +upsimage +-------- + +This is usually called by upsstats via IMG SRC tags to draw either the +utility or outgoing voltage, battery charge percent, or load percent. + +upsset +------ + +upsset provides several useful administration functions through a web +interface. You can use upsset to kick off instant commands on your UPS +hardware like running a battery test. You can also use it to change +variables in your UPS that accept user-specified values. + +Essentially, upsset provides the functions of upsrw and upscmd, but +with a happy pointy-clicky interface. + +upsset will not run until you convince it that you have secured your +system. You *must* secure your CGI path so that random interlopers +can't run this program remotely. See the upsset.conf file. Once you +have secured the directory, you can enable this program in that +configuration file. It is not active by default. + + +===================== +Support / Help / etc. +===================== + +The main URL: + + http://www.networkupstools.org/ + +There is also a mailing list for general queries and discussion about +this software called nut-upsuser. It typically moves around 50-100 messages +per month at the time of this writing. To join, go to the below address and +subscribe to the desired list. + +Finally, there is a developer list called nut-upsdev. This is not +an install help list, and any such mails probably will be ignored. + +The mailing lists are archived on the web: + + http://alioth.debian.org/mail/?group_id=30602 + +Try running some searches against the archives. Many times, problems have +already been answered by someone else. Currently, there is no internal +search engine, so you will have to try with a search engine like Google. + +There is more documentation in the docs/ directory within the source +tree. Be sure to read through the files in there (especially the +FAQ) before mailing the list for help. Many times the questions have +already been answered in the files which are right in front of you. + + +=================================== +Making your own clients (upsclient) +=================================== + +The upsclient.a library can be linked into other programs to give access +to upsd and UPS status information. Clients like upsc are provided as +examples of how to retrieve data using the upsclient functions. Other +programs not included in this package may also use this library, as wmnut. + +This library file and the associated header files are not installed by +default. You must './configure --with-lib' to enable building and +installing these files. The libraries can then be build and installed +with 'make' and 'make install' as usual. This must be done before +building other (non-NUT) programs which depend on them. + +To obtain the right compilation and link flags, two helpers are provided: +one for platform providing pkg-config, and the other (libupsclient-config) +for platform not providing pkg-config. + + +================= +Version Numbering +================= + +The version numbers work like this: if the middle number is odd, it's a +development tree, otherwise it is the stable tree. + +The past stable trees were 1.0, 1.2, 1.4 and 2.0, with the latest stable tree +designated 2.2. The development trees were 1.1, 1.3, 1.5 and 2.1. + +The jump to 2.2 is mostly due to the large changes to the features list. +There have also been a number of architectural changes which may not be +noticeable to most users. + + +==================================== +Backwards and Forwards Compatibility +==================================== + +The old network code spans a range from about 0.41.1 when TCP support +was introduced up to the recent 1.4 series. It used variable names +like STATUS, UTILITY, and LOADPCT. Many of these names go back to the +earliest prototypes of this software from 1997. At that point there +was no way to know that so many drivers would come along and introduce +so many new variables and commands. The resulting mess grew out of +control over the years. + +During the 1.3 development cycle, all variables and instant commands +were renamed to fit into a tree-like structure. There are major groups, +like input, output and battery. Members of those groups have been +arranged to make sense - input.voltage and output.voltage compliment +each other. The old names were UTILITY and OUTVOLT. The benefits in +this change are obvious. + +The 1.4 clients can talk to either type of server, and can handle either +naming scheme. 1.4 servers have a compatibility mode where they can +answer queries for both names, even though the drivers are internally +using the new format. + +When 1.4 clients talk to 1.4 or 2.0 (or more recent) servers, they will +use the new names. + +Here's a table to make it easier to visualize: + + +--------+------------------------+ + | | Server | + +--------+-----+-----+-----+------+ + | Client | 1.0 | 1.2 | 1.4 | 2.0+ | + +========+=====+=====+=====+======+ + | 1.0 | yes | yes | yes | no | + +--------+-----+-----+-----+------+ + | 1.2 | yes | yes | yes | no | + +--------+-----+-----+-----+------+ + | 1.4 | yes | yes | yes | yes | + +--------+-----+-----+-----+------+ + | 2.0 | no | no | yes | yes | + +--------+-----+-----+-----+------+ + +Version 2.0 (and more recent) does not contain backwards compatibility for +the old protocol and variable/command names. As a result, 2.0 clients can't +talk to anything older than a 1.4 server. If you ask a 2.0 client to +fetch "STATUS", it will fail. You'll have to ask for "ups.status" +instead. + +Authors of separate monitoring programs should have used the 1.4 series +to write support for the new variables and command names. Client +software can easily support both versions as long as they like. If upsd +returns 'ERR UNKNOWN-COMMAND' to a GET request, you need to use REQ. + + +========================== +Hacking / Development Info +========================== + +Additional documentation can be found in the docs subdirectory. + +Information on creating new drivers can be found in new-drivers.txt. +Also be sure to look at skel.c and main.c. All drivers are just +collections of support functions built around a common core, so most of +the dull housekeeping work has been handled for you. + +Information on the NUT variables naming can be found in new-names.txt. +Information on the architecture and how it all fits together is in the +design.txt file. In short, there's a lot more documentation out there. + +Also be sure to read developers.txt, as it explains a lot about the +tree, including some of the functions that are provided for your use. + + +================================ +Acknowledgements / Contributions +================================ + +MGE UPS SYSTEMS provided extensive technical documents for their UPS product +line, along with many units for development of NUT-related projects. The +company also sponsored and later hired Arnaud Quette to further officially +support these efforts. + +Several drivers such as mge-utalk, mge-shut, snmp-ups, hidups, and usbhid-ups +are the result of this collaboration, in addition to the WMNut, MGE HID Parser +the libhid projects, .... The features page has improved artwork thanks to Luc +and Arnaud of MGE. Other client projects such as KNutClient and ups-monitor +have also received assistance. + +The master NUT site and several related projects are hosted on MGE's equipment +at no cost to the project. + +More information on their open source support can be found on their web site: +http://opensource.mgeups.com/contrib.htm + +Fenton Technologies contributed a PowerPal 660 to the project. Their open +stance and quick responses to technical inquiries are appreciated for +making the development of the fentonups driver possible. + +Bo Kersey of VirCIO (http://www.vircio.com) provided a Best Power +Fortress 750 to facilitate the bestups driver. + +Invensys Energy Systems provided the SOLA/Best "Phoenixtec" protocol +document currently residing at the following URL: + + http://random.networkupstools.org/protocols/sola.html + +PowerKinetics technical support provided documentation on their MiniCOL +protocol, which is archived in the NUT protocol library online: + + http://random.networkupstools.org/protocols/minicol/ + +Cyber Power Systems contributed a 700AVR model for testing and driver +development. + +Liebert Corporation supplied serial test boxes and a UPStation GXT2 +with the Web/SNMP card for development of the liebert driver and +expansion of the existing snmp-ups driver. + diff --git a/UPGRADING b/UPGRADING new file mode 100644 index 0000000..63ed28d --- /dev/null +++ b/UPGRADING @@ -0,0 +1,373 @@ +This file lists changes that affect users who installed older versions +of this software. When upgrading from an older version, be sure to +check this file to see if you need to make changes to your system. + +--------------------------------------------------------------------------- +Changes from 2.4.2 to 2.4.3: + + - nothing that affects upgraded systems. + +--------------------------------------------------------------------------- +Changes from 2.4.1 to 2.4.2: + + - The default subdriver for the blazer_usb driver USB id 06da:0003 has + changed. If you use such a device and it is no longer working with this + driver, override the 'subdriver' default in 'ups.conf' (see man 8 blazer). + - NUT ACL and the allowfrom mechanism has been replaced in 2.4.0 by the LISTEN + directive and tcp-wrappers respectively. This information was missing + below, so a double note has been added. + +--------------------------------------------------------------------------- +Changes from 2.4.0 to 2.4.1: + + - nothing that affects upgraded systems. + +--------------------------------------------------------------------------- +Changes from 2.2.2 to 2.4.0: + + - The nut.conf file has been introduced to standardize startup configuration + across the various systems. + - The cpsups and nitram drivers have been replaced by the powerpanel driver, + and removed from the tree. The cyberpower driver may suffer the same in the + future. + - The al175 and energizerups drivers have been removed from the tree, since + these were tagged broken for a long time. + - Developers of external client application using libupsclient must rename + their "UPSCONN" client structure to "UPSCONN_t". + - The upsd server will now disconnect clients that remain silent for more than + 60 seconds. + - The files under scripts/python/client are distributed under GPL 3+, whereas + the rest of the files are distributed under GPL 2+. Refer to COPYING for more + information. + - The generated udev rules file has been renamed with dash only, no underscore + anymore (ie 52-nut-usbups.rules instead of 52_nut-usbups.rules) + - (Note: this has been missed at release time): The NUT internal network access + control (ACL using ACCEPT / REJECT in upsd.conf) has been replaced by + the LISTEN directive. This can also be complemented by tcp-wrappers. + Refer to upsd and upsd.conf manual pages for more information. + +--------------------------------------------------------------------------- +Changes from 2.2.1 to 2.2.2: + + - The configure option "--with-lib" has been replaced by "--with-dev". + This enable the additional build and distribution of the static + version of libupsclient, along with the pkg-config helper and manual + pages. The default configure option is to distribute only the shared + version of libupsclient. This can be overriden by using the + "--disable-shared" configure option (distribute static only binaries). + - The UPS poweroff handling of the usbhid-ups driver has been reworked. + Though regression is not expected, users of this driver are + encouraged to test this feature by calling "upsmon -c fsd" and + report any issue on the NUT mailing lists. + +--------------------------------------------------------------------------- +Changes from 2.2.0 to 2.2.1: + + - nothing that affects upgraded systems. + (The below message is repetead due to previous omission) + - Developers of external client application using libupsclient are + encouraged to rename their "UPSCONN" client structure to "UPSCONN_t" + since the former will disappear by the release of NUT 2.4. + +--------------------------------------------------------------------------- +Changes from 2.0.5 to 2.2.0: + + - users of the newhidups driver are advised that the driver name has changed + to usbhid-ups. + - users of the hidups driver must switch to usbhid-ups. + - users of the following drivers (powermust, blazer, fentonups, mustek, + esupssmart, ippon, sms) must switch to megatec, which replaces + all these drivers. Please refer to doc/megatec.txt for details. + - users of the mge-shut driver are encouraged to test newmge-shut, which + is an alternate driver scheduled to replace mge-shut, + - users of the cpsups driver are encouraged to switch to powerpanel which + is scheduled to replace cpsups, + - packagers will have to rework the whole nut packaging due to the + major changes in the build system (completely modified, and now using + automake). Refer to packaging/debian/ for an example of migration. + - specifying '-a ' is now mandatory when starting a driver manually, + ie not using upsdrvctl. + - Developers of external client application using libupsclient are + encouraged to rename the "UPSCONN" client structure to "UPSCONN_t" + since the former will disapear by the release of NUT 2.4. + +--------------------------------------------------------------------------- +Changes from 2.0.4 to 2.0.5: + + - users of the newhidups driver: the driver is now more strict about + refusing to connect to unknown devices. If your device was + previously supported, but fails to be recognized now, add + 'productid=XXXX' to ups.conf. Please report the device to the NUT + developer's mailing list. + +--------------------------------------------------------------------------- +Changes from 2.0.3 to 2.0.4: + + - nothing that affects upgraded systems. + - users of the following drivers (powermust, blazer, fentonups, mustek, + esupssmart, ippon, sms, masterguard) are encouraged to switch to megatec, + which should replace all these drivers by nut 2.2. For more information, + please refer to doc/megatec.txt + +--------------------------------------------------------------------------- +Changes from 2.0.2 to 2.0.3: + + - nothing that affects upgraded systems. + - hidups users are encouraged to switch to newhidups, as hidups will be + removed by nut 2.2. + +--------------------------------------------------------------------------- +Changes from 2.0.1 to 2.0.2: + + - The newhidups driver, which is the long run USB support approach, + needs hotplug files installed to setup the right permissions on + device file to operate. Check newhidups manual page for more information. + +--------------------------------------------------------------------------- +Changes from 2.0.0 to 2.0.1: + + - The cyberpower1100 driver is now called cpsups since it supports + more than just one model. If you use this driver, be sure to remove + the old binary and update your ups.conf 'driver=' setting with the + new name. + + - The upsstats.html template page has been changed slightly to reflect + better HTML compliance, so you may want to update your installed copy + accordingly. If you've customized your file, don't just copy the new + one over it, or your changes will be lost! + +--------------------------------------------------------------------------- +Changes from 1.4.0 to 2.0.0: + + - The sample config files are no longer installed by default. If you + want to install them, use 'make install-conf' for the main programs, + and 'make install-cgi-conf' for the CGI programs. + + - ACCESS is no longer supported in upsd.conf. Use ACCEPT and REJECT. + + Old way: + + ACCESS grant all adminbox + ACCESS grant all webserver + ACCESS deny all all + + New way: + + ACCEPT adminbox + ACCEPT webserver + REJECT all + + Note that ACCEPT and REJECT can take multiple arguments, so this + will also work: + + ACCEPT adminbox webserver + REJECT all + + - The drivers no longer support sddelay in ups.conf or -d on the + command line. If you need a delay after calling 'upsdrvctl + shutdown', add a call to sleep in your shutdown script. + + - The templates used by upsstats have changed considerably to reflect + the new variable names. If you use upsstats, you will need to + install new copies or edit your existing files to use the new names. + + - Nobody needed UDP mode, so it has been removed. The only users + seemed to be a few people like me with ancient asapm-ups binaries. + If you really want to run asapm-ups again, bug me for the new patch + which makes it work with upsclient. + + - 'make install-misc' is now 'make install-lib'. The misc directory + has been gone for a long time, and the target was ambiguous. + + - The newapc driver has been renamed to apcsmart. If you previously + used newapc, make sure you delete the old binary and fix your + ups.conf. Otherwise, you may run the old driver from 1.4. + +--------------------------------------------------------------------------- + +Changes from 1.2.2 to 1.4.0: + + - The clients no longer support the notion of a "default UPS" when + communicating with newer versions of upsd. If you leave off a UPS + name, they will fall back on compatibility mode and will use the + old variable and command names. + + That is, "upsc localhost" will give you things like STATUS, and you + have to do "upsc myups@localhost" to get the new ones like + ups.status. + + The old variable names and default UPS mode will be supported + throughout the 1.4 series to allow users to convert to the new + style. This support will be formally dropped in 2.0. + + - upsmon is part of the "no default upsname" change. You must change + the MONITOR directives in your upsmon.conf if you were using this + technique before. + + Old way: + + MONITOR bigserver 1 monuser password master + + New way: + + MONITOR myups@bigserver 1 monuser password master + + Just look at the top of ups.conf on 'bigserver' to figure out what + the first UPS is called, and stick it and a @ on that MONITOR line. + + - upsrw's appearance has changed to avoid wrapping when displaying + the new longer variable names and descriptions. It still displays + the old format when talking to an older upsd. + + To see the difference, try "upsrw localhost" and then compare it to + "upsrw myups@localhost", assuming a new version of upsd is running + on localhost. + + - upslog now uses the new variable names in the default format + string. It will still monitor the old variable names for backwards + compatibility, but you will have to specify the format string + explicitly. + + - 'make install' no longer creates the state path. Instructions for + creating it properly have been added to the INSTALL file. + + Technically, this only affects packagers, since this is the + UPGRADING file and normal users should already have a state path. + If you are a packager, you will need to add the right mkdir + chown + + chmod magic to your install process to keep things working. + + This also means that you no longer need any special permissions to + bundle this software into a package. The installer no longer + requires root now that the chown is gone. + + - configure --with-group no longer does anything useful. The programs + which will drop permissions support "-u ", and will pick up + the group id based on the values in /etc/passwd for that user name. + + configure --with-user still works as before, and provides the default + value if you don't specify another one with -u. + + - The "DROP" action in upsd.conf now behaves a little differently. + + It still causes new TCP connections to be closed without reading + from the socket, and still causes UDP datagrams to be ignored. + + The only difference is that commands that are denied after the + remote host connects will now generate an error message. Previously, + upsd would just ignore them, and the clients could get out of sync. + + DENY also has been changed slightly to silently ignore UDP packets. + + Essentially, DROP and DENY are now the same thing. If you use DROP + anywhere, you should change to DENY before it goes away in the future. + + - upsmon now requires a username on the MONITOR lines. If you have an + older installation from the 1.x era or earlier, you probably need + to convert them. + + Old way: MONITOR ups@mybox 1 mypass master + New way: MONITOR ups@mybox 1 username mypass master + + You will also have to add a [username] section to the upsd.users + with a matching password, an allowfrom value, and "upsmon master" or + "upsmon slave". + + If upsmon says the login failed due to "username required" or fails to + start, saying "Unable to use old-style MONITOR line without a username", + then you're still using the old method. + +--------------------------------------------------------------------------- + +Changes from 1.2.1 to 1.2.2: + + - upssched.conf now requires the LOCKFN directive to prevent races when + handling two events that happen at nearly the same time. + + If you use upssched, you must add this to your upssched.conf or it + will fail to run. + +--------------------------------------------------------------------------- + +Changes from 1.0.0 to 1.2.0: + + - upsct is gone. upsc now uses the new upsclient library which is + TCP only, so there is no need for a separate client for TCP polling. + + - upsct2 has been renamed to upsrw since the name was already + ambiguous and it looked even more out of place with upsct gone. + + - The multimon.cgi behavior has been absorbed into upsstats.cgi. + + - Calling upsstats.cgi with no arguments will make it render + the template file called upsstats.html in your confpath. The default + version of this file looks a lot like multimon, but is flexible. + You will have to copy this file from upsstats.html.sample to + upsstats.html the first time you install this version. + + - Calling upsstats.cgi with host= set will still render a single status + page as before, but the markup for that page now comes from + upsstats-single.html. This is also a template and may be + reconfigured to suit your needs. It must also be copied over from + the .sample filename the first time. + + - upsmon can now send a username when authenticating to upsd. It is + recommended that you change to this mode, as the old host-based + authentication is clunky and eventually will be removed. + + Old way: + + MONITOR myups@bigserver 1 blah master + + New way: + + MONITOR myups@bigserver 1 monmaster blah master + + Note that the username has been inserted between the power value and + the password. When switching to this method, be sure to add a user + to upsd.users, i.e.: + + [monmaster] + password = blah + allowfrom = localhost + upsmon master + + You still need to give the upsmon host(s) at least "monitor" access, + so don't delete those old ACCESS lines in your upsd.conf. Just + lower the access level and remove the password. + + Old way: + + ACCESS grant master localhost blah + + New way: + + ACCESS grant monitor localhost + + - The old upsfetch "library" (used loosely) has been replaced by + upsclient. This will be installed if you do "make install-misc", + but it goes into $(prefix)/lib and $(prefix)/include by default. + + The upsclient interface is not compatible with upsfetch. Old + accessory programs which linked to upsfetch will have to be updated + to work with upsclient instead. + + Existing binaries that were linked against upsfetch will still work + since the network protocol used by upsd has not changed. + + - SET and INSTCMD no longer work via host-level authentication. This + is only a meaningful change if you are using very old versions of + upscmd/upsct2/upsset.cgi, or if you're talking to upsd directly. + + You must now set a USERNAME first, and authentication will occur + through upsd.users as a result. + + This means that the "manager" level in upsd.conf ACCESS directives + is no longer meaningful, and you should remove them. + + - INSTALLROOT is no longer available for redirecting 'make install' - + use DESTDIR instead. + + - Makefile targets have been reworked to allow fine-grained control + over what happens at install-time. 'make install' and 'make + install-cgi' still do everything, but you can call subsets instead + if necessary. See ChangeLog. diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..b52cc76 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1155 @@ +# generated automatically by aclocal 1.11 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],, +[m4_warning([this file was generated for autoconf 2.64. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# longlong.m4 serial 13 +dnl Copyright (C) 1999-2007 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl From Paul Eggert. + +# Define HAVE_LONG_LONG_INT if 'long long int' works. +# This fixes a bug in Autoconf 2.61, but can be removed once we +# assume 2.62 everywhere. + +# Note: If the type 'long long int' exists but is only 32 bits large +# (as on some very old compilers), HAVE_LONG_LONG_INT will not be +# defined. In this case you can treat 'long long int' like 'long int'. + +AC_DEFUN([AC_TYPE_LONG_LONG_INT], +[ + AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int], + [AC_LINK_IFELSE( + [_AC_TYPE_LONG_LONG_SNIPPET], + [dnl This catches a bug in Tandem NonStop Kernel (OSS) cc -O circa 2004. + dnl If cross compiling, assume the bug isn't important, since + dnl nobody cross compiles for this platform as far as we know. + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[@%:@include + @%:@ifndef LLONG_MAX + @%:@ define HALF \ + (1LL << (sizeof (long long int) * CHAR_BIT - 2)) + @%:@ define LLONG_MAX (HALF - 1 + HALF) + @%:@endif]], + [[long long int n = 1; + int i; + for (i = 0; ; i++) + { + long long int m = n << i; + if (m >> i != n) + return 1; + if (LLONG_MAX / 2 < m) + break; + } + return 0;]])], + [ac_cv_type_long_long_int=yes], + [ac_cv_type_long_long_int=no], + [ac_cv_type_long_long_int=yes])], + [ac_cv_type_long_long_int=no])]) + if test $ac_cv_type_long_long_int = yes; then + AC_DEFINE([HAVE_LONG_LONG_INT], 1, + [Define to 1 if the system has the type `long long int'.]) + fi +]) + +# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works. +# This fixes a bug in Autoconf 2.61, but can be removed once we +# assume 2.62 everywhere. + +# Note: If the type 'unsigned long long int' exists but is only 32 bits +# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT +# will not be defined. In this case you can treat 'unsigned long long int' +# like 'unsigned long int'. + +AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT], +[ + AC_CACHE_CHECK([for unsigned long long int], + [ac_cv_type_unsigned_long_long_int], + [AC_LINK_IFELSE( + [_AC_TYPE_LONG_LONG_SNIPPET], + [ac_cv_type_unsigned_long_long_int=yes], + [ac_cv_type_unsigned_long_long_int=no])]) + if test $ac_cv_type_unsigned_long_long_int = yes; then + AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], 1, + [Define to 1 if the system has the type `unsigned long long int'.]) + fi +]) + +# Expands to a C program that can be used to test for simultaneous support +# of 'long long' and 'unsigned long long'. We don't want to say that +# 'long long' is available if 'unsigned long long' is not, or vice versa, +# because too many programs rely on the symmetry between signed and unsigned +# integer types (excluding 'bool'). +AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET], +[ + AC_LANG_PROGRAM( + [[/* Test preprocessor. */ + #if ! (-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) + error in preprocessor; + #endif + #if ! (18446744073709551615ULL <= -1ull) + error in preprocessor; + #endif + /* Test literals. */ + long long int ll = 9223372036854775807ll; + long long int nll = -9223372036854775807LL; + unsigned long long int ull = 18446744073709551615ULL; + /* Test constant expressions. */ + typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll) + ? 1 : -1)]; + typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1 + ? 1 : -1)]; + int i = 63;]], + [[/* Test availability of runtime routines for shift and division. */ + long long int llmax = 9223372036854775807ll; + unsigned long long int ullmax = 18446744073709551615ull; + return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i) + | (llmax / ll) | (llmax % ll) + | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i) + | (ullmax / ull) | (ullmax % ull));]]) +]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/ax_create_stdint_h.m4]) +m4_include([m4/libtool.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) +m4_include([m4/nut_arg_with.m4]) +m4_include([m4/nut_check_ipv6.m4]) +m4_include([m4/nut_check_libgd.m4]) +m4_include([m4/nut_check_libhal.m4]) +m4_include([m4/nut_check_libneon.m4]) +m4_include([m4/nut_check_libnetsnmp.m4]) +m4_include([m4/nut_check_libpowerman.m4]) +m4_include([m4/nut_check_libssl.m4]) +m4_include([m4/nut_check_libusb.m4]) +m4_include([m4/nut_check_libwrap.m4]) +m4_include([m4/nut_check_os.m4]) +m4_include([m4/nut_report_feature.m4]) +m4_include([m4/nut_type_socklen_t.m4]) diff --git a/clients/Makefile.am b/clients/Makefile.am new file mode 100644 index 0000000..59e92c7 --- /dev/null +++ b/clients/Makefile.am @@ -0,0 +1,53 @@ +# Network UPS Tools: clients + +# by default, link programs in this directory with libcommon.a +LDADD = ../common/libcommon.a libupsclient.la $(NETLIBS) +if WITH_SSL + LDADD += $(LIBSSL_LDFLAGS) +endif + +# Avoid per-target CFLAGS, because this will prevent re-use of object +# files. In any case, CFLAGS are only -I options, so there is no harm, +# but only add them if we really use the target. +AM_CFLAGS = -I$(top_srcdir)/include +if WITH_SSL + AM_CFLAGS += $(LIBSSL_CFLAGS) +endif +if WITH_CGI + AM_CFLAGS += $(LIBGD_CFLAGS) +endif + +bin_PROGRAMS = upsc upslog upsrw upscmd +dist_bin_SCRIPTS = upssched-cmd +sbin_PROGRAMS = upsmon upssched +lib_LTLIBRARIES = libupsclient.la +if WITH_DEV + include_HEADERS = upsclient.h ../include/parseconf.h +endif +if WITH_CGI + cgiexec_PROGRAMS = upsstats.cgi upsimage.cgi upsset.cgi +endif + +upsc_SOURCES = upsc.c upsclient.h +upscmd_SOURCES = upscmd.c upsclient.h +upsrw_SOURCES = upsrw.c upsclient.h +upslog_SOURCES = upslog.c upsclient.h upslog.h +upsmon_SOURCES = upsmon.c upsmon.h upsclient.h + +upssched_SOURCES = upssched.c upssched.h +upssched_LDADD = ../common/libcommon.a ../common/libparseconf.la $(NETLIBS) + +upsimage_cgi_SOURCES = upsimage.c upsclient.h upsimagearg.h cgilib.c cgilib.h +upsimage_cgi_LDADD = $(LDADD) $(LIBGD_LDFLAGS) + +upsset_cgi_SOURCES = upsset.c upsclient.h cgilib.c cgilib.h +upsstats_cgi_SOURCES = upsstats.c upsclient.h status.h upsstats.h \ + upsimagearg.h cgilib.c cgilib.h + +# not LDADD. +libupsclient_la_SOURCES = upsclient.c upsclient.h +libupsclient_la_LIBADD = ../common/libparseconf.la +if WITH_SSL + libupsclient_la_LIBADD += $(LIBSSL_LDFLAGS) +endif +libupsclient_la_LDFLAGS = -version-info 1:0:0 diff --git a/clients/Makefile.in b/clients/Makefile.in new file mode 100644 index 0000000..27cd0c6 --- /dev/null +++ b/clients/Makefile.in @@ -0,0 +1,912 @@ +# Makefile.in generated by automake 1.11 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# Network UPS Tools: clients + + + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +@WITH_SSL_TRUE@am__append_1 = $(LIBSSL_LDFLAGS) +@WITH_SSL_TRUE@am__append_2 = $(LIBSSL_CFLAGS) +@WITH_CGI_TRUE@am__append_3 = $(LIBGD_CFLAGS) +bin_PROGRAMS = upsc$(EXEEXT) upslog$(EXEEXT) upsrw$(EXEEXT) \ + upscmd$(EXEEXT) +sbin_PROGRAMS = upsmon$(EXEEXT) upssched$(EXEEXT) +@WITH_CGI_TRUE@cgiexec_PROGRAMS = upsstats.cgi$(EXEEXT) \ +@WITH_CGI_TRUE@ upsimage.cgi$(EXEEXT) upsset.cgi$(EXEEXT) +@WITH_SSL_TRUE@am__append_4 = $(LIBSSL_LDFLAGS) +subdir = clients +DIST_COMMON = $(am__include_HEADERS_DIST) $(dist_bin_SCRIPTS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_create_stdint_h.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/m4/nut_arg_with.m4 \ + $(top_srcdir)/m4/nut_check_ipv6.m4 \ + $(top_srcdir)/m4/nut_check_libgd.m4 \ + $(top_srcdir)/m4/nut_check_libhal.m4 \ + $(top_srcdir)/m4/nut_check_libneon.m4 \ + $(top_srcdir)/m4/nut_check_libnetsnmp.m4 \ + $(top_srcdir)/m4/nut_check_libpowerman.m4 \ + $(top_srcdir)/m4/nut_check_libssl.m4 \ + $(top_srcdir)/m4/nut_check_libusb.m4 \ + $(top_srcdir)/m4/nut_check_libwrap.m4 \ + $(top_srcdir)/m4/nut_check_os.m4 \ + $(top_srcdir)/m4/nut_report_feature.m4 \ + $(top_srcdir)/m4/nut_type_socklen_t.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(cgiexecdir)" "$(DESTDIR)$(sbindir)" \ + "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +@WITH_SSL_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) +libupsclient_la_DEPENDENCIES = ../common/libparseconf.la \ + $(am__DEPENDENCIES_2) +am_libupsclient_la_OBJECTS = upsclient.lo +libupsclient_la_OBJECTS = $(am_libupsclient_la_OBJECTS) +libupsclient_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libupsclient_la_LDFLAGS) $(LDFLAGS) -o $@ +PROGRAMS = $(bin_PROGRAMS) $(cgiexec_PROGRAMS) $(sbin_PROGRAMS) +am_upsc_OBJECTS = upsc.$(OBJEXT) +upsc_OBJECTS = $(am_upsc_OBJECTS) +upsc_LDADD = $(LDADD) +upsc_DEPENDENCIES = ../common/libcommon.a libupsclient.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +am_upscmd_OBJECTS = upscmd.$(OBJEXT) +upscmd_OBJECTS = $(am_upscmd_OBJECTS) +upscmd_LDADD = $(LDADD) +upscmd_DEPENDENCIES = ../common/libcommon.a libupsclient.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +am_upsimage_cgi_OBJECTS = upsimage.$(OBJEXT) cgilib.$(OBJEXT) +upsimage_cgi_OBJECTS = $(am_upsimage_cgi_OBJECTS) +am__DEPENDENCIES_3 = ../common/libcommon.a libupsclient.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +upsimage_cgi_DEPENDENCIES = $(am__DEPENDENCIES_3) \ + $(am__DEPENDENCIES_1) +am_upslog_OBJECTS = upslog.$(OBJEXT) +upslog_OBJECTS = $(am_upslog_OBJECTS) +upslog_LDADD = $(LDADD) +upslog_DEPENDENCIES = ../common/libcommon.a libupsclient.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +am_upsmon_OBJECTS = upsmon.$(OBJEXT) +upsmon_OBJECTS = $(am_upsmon_OBJECTS) +upsmon_LDADD = $(LDADD) +upsmon_DEPENDENCIES = ../common/libcommon.a libupsclient.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +am_upsrw_OBJECTS = upsrw.$(OBJEXT) +upsrw_OBJECTS = $(am_upsrw_OBJECTS) +upsrw_LDADD = $(LDADD) +upsrw_DEPENDENCIES = ../common/libcommon.a libupsclient.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +am_upssched_OBJECTS = upssched.$(OBJEXT) +upssched_OBJECTS = $(am_upssched_OBJECTS) +upssched_DEPENDENCIES = ../common/libcommon.a \ + ../common/libparseconf.la $(am__DEPENDENCIES_1) +am_upsset_cgi_OBJECTS = upsset.$(OBJEXT) cgilib.$(OBJEXT) +upsset_cgi_OBJECTS = $(am_upsset_cgi_OBJECTS) +upsset_cgi_LDADD = $(LDADD) +upsset_cgi_DEPENDENCIES = ../common/libcommon.a libupsclient.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +am_upsstats_cgi_OBJECTS = upsstats.$(OBJEXT) cgilib.$(OBJEXT) +upsstats_cgi_OBJECTS = $(am_upsstats_cgi_OBJECTS) +upsstats_cgi_LDADD = $(LDADD) +upsstats_cgi_DEPENDENCIES = ../common/libcommon.a libupsclient.la \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +SCRIPTS = $(dist_bin_SCRIPTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libupsclient_la_SOURCES) $(upsc_SOURCES) $(upscmd_SOURCES) \ + $(upsimage_cgi_SOURCES) $(upslog_SOURCES) $(upsmon_SOURCES) \ + $(upsrw_SOURCES) $(upssched_SOURCES) $(upsset_cgi_SOURCES) \ + $(upsstats_cgi_SOURCES) +DIST_SOURCES = $(libupsclient_la_SOURCES) $(upsc_SOURCES) \ + $(upscmd_SOURCES) $(upsimage_cgi_SOURCES) $(upslog_SOURCES) \ + $(upsmon_SOURCES) $(upsrw_SOURCES) $(upssched_SOURCES) \ + $(upsset_cgi_SOURCES) $(upsstats_cgi_SOURCES) +am__include_HEADERS_DIST = upsclient.h ../include/parseconf.h +HEADERS = $(include_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONFPATH = @CONFPATH@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DRIVER_BUILD_LIST = @DRIVER_BUILD_LIST@ +DRIVER_INSTALL_TARGET = @DRIVER_INSTALL_TARGET@ +DRIVER_MAN_LIST = @DRIVER_MAN_LIST@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +HAL_CALLOUTS_PATH = @HAL_CALLOUTS_PATH@ +HAL_DEVICE_MATCH_KEY = @HAL_DEVICE_MATCH_KEY@ +HAL_FDI_PATH = @HAL_FDI_PATH@ +HAL_USER = @HAL_USER@ +HAVE_GLIB_2_14 = @HAVE_GLIB_2_14@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBGD_CFLAGS = @LIBGD_CFLAGS@ +LIBGD_LDFLAGS = @LIBGD_LDFLAGS@ +LIBHAL_CFLAGS = @LIBHAL_CFLAGS@ +LIBHAL_LDFLAGS = @LIBHAL_LDFLAGS@ +LIBNEON_CFLAGS = @LIBNEON_CFLAGS@ +LIBNEON_LDFLAGS = @LIBNEON_LDFLAGS@ +LIBNETSNMP_CFLAGS = @LIBNETSNMP_CFLAGS@ +LIBNETSNMP_LDFLAGS = @LIBNETSNMP_LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBPOWERMAN_CFLAGS = @LIBPOWERMAN_CFLAGS@ +LIBPOWERMAN_LDFLAGS = @LIBPOWERMAN_LDFLAGS@ +LIBS = @LIBS@ +LIBSSL_CFLAGS = @LIBSSL_CFLAGS@ +LIBSSL_LDFLAGS = @LIBSSL_LDFLAGS@ +LIBTOOL = @LIBTOOL@ +LIBUSB_CFLAGS = @LIBUSB_CFLAGS@ +LIBUSB_LDFLAGS = @LIBUSB_LDFLAGS@ +LIBWRAP_CFLAGS = @LIBWRAP_CFLAGS@ +LIBWRAP_LDFLAGS = @LIBWRAP_LDFLAGS@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +NETLIBS = @NETLIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OS_NAME = @OS_NAME@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +RUN_AS_GROUP = @RUN_AS_GROUP@ +RUN_AS_USER = @RUN_AS_USER@ +SED = @SED@ +SERLIBS = @SERLIBS@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STATEPATH = @STATEPATH@ +STRIP = @STRIP@ +SUN_LIBUSB = @SUN_LIBUSB@ +VERSION = @VERSION@ +WORDS_BIGENDIAN = @WORDS_BIGENDIAN@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +cgiexecdir = @cgiexecdir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +driverexecdir = @driverexecdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +hotplugdir = @hotplugdir@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfigdir = @pkgconfigdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +udevdir = @udevdir@ + +# by default, link programs in this directory with libcommon.a +LDADD = ../common/libcommon.a libupsclient.la $(NETLIBS) \ + $(am__append_1) + +# Avoid per-target CFLAGS, because this will prevent re-use of object +# files. In any case, CFLAGS are only -I options, so there is no harm, +# but only add them if we really use the target. +AM_CFLAGS = -I$(top_srcdir)/include $(am__append_2) $(am__append_3) +dist_bin_SCRIPTS = upssched-cmd +lib_LTLIBRARIES = libupsclient.la +@WITH_DEV_TRUE@include_HEADERS = upsclient.h ../include/parseconf.h +upsc_SOURCES = upsc.c upsclient.h +upscmd_SOURCES = upscmd.c upsclient.h +upsrw_SOURCES = upsrw.c upsclient.h +upslog_SOURCES = upslog.c upsclient.h upslog.h +upsmon_SOURCES = upsmon.c upsmon.h upsclient.h +upssched_SOURCES = upssched.c upssched.h +upssched_LDADD = ../common/libcommon.a ../common/libparseconf.la $(NETLIBS) +upsimage_cgi_SOURCES = upsimage.c upsclient.h upsimagearg.h cgilib.c cgilib.h +upsimage_cgi_LDADD = $(LDADD) $(LIBGD_LDFLAGS) +upsset_cgi_SOURCES = upsset.c upsclient.h cgilib.c cgilib.h +upsstats_cgi_SOURCES = upsstats.c upsclient.h status.h upsstats.h \ + upsimagearg.h cgilib.c cgilib.h + + +# not LDADD. +libupsclient_la_SOURCES = upsclient.c upsclient.h +libupsclient_la_LIBADD = ../common/libparseconf.la $(am__append_4) +libupsclient_la_LDFLAGS = -version-info 1:0:0 +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu clients/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu clients/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libupsclient.la: $(libupsclient_la_OBJECTS) $(libupsclient_la_DEPENDENCIES) + $(libupsclient_la_LINK) -rpath $(libdir) $(libupsclient_la_OBJECTS) $(libupsclient_la_LIBADD) $(LIBS) +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-cgiexecPROGRAMS: $(cgiexec_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(cgiexecdir)" || $(MKDIR_P) "$(DESTDIR)$(cgiexecdir)" + @list='$(cgiexec_PROGRAMS)'; test -n "$(cgiexecdir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(cgiexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(cgiexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-cgiexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(cgiexec_PROGRAMS)'; test -n "$(cgiexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(cgiexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(cgiexecdir)" && rm -f $$files + +clean-cgiexecPROGRAMS: + @list='$(cgiexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +upsc$(EXEEXT): $(upsc_OBJECTS) $(upsc_DEPENDENCIES) + @rm -f upsc$(EXEEXT) + $(LINK) $(upsc_OBJECTS) $(upsc_LDADD) $(LIBS) +upscmd$(EXEEXT): $(upscmd_OBJECTS) $(upscmd_DEPENDENCIES) + @rm -f upscmd$(EXEEXT) + $(LINK) $(upscmd_OBJECTS) $(upscmd_LDADD) $(LIBS) +upsimage.cgi$(EXEEXT): $(upsimage_cgi_OBJECTS) $(upsimage_cgi_DEPENDENCIES) + @rm -f upsimage.cgi$(EXEEXT) + $(LINK) $(upsimage_cgi_OBJECTS) $(upsimage_cgi_LDADD) $(LIBS) +upslog$(EXEEXT): $(upslog_OBJECTS) $(upslog_DEPENDENCIES) + @rm -f upslog$(EXEEXT) + $(LINK) $(upslog_OBJECTS) $(upslog_LDADD) $(LIBS) +upsmon$(EXEEXT): $(upsmon_OBJECTS) $(upsmon_DEPENDENCIES) + @rm -f upsmon$(EXEEXT) + $(LINK) $(upsmon_OBJECTS) $(upsmon_LDADD) $(LIBS) +upsrw$(EXEEXT): $(upsrw_OBJECTS) $(upsrw_DEPENDENCIES) + @rm -f upsrw$(EXEEXT) + $(LINK) $(upsrw_OBJECTS) $(upsrw_LDADD) $(LIBS) +upssched$(EXEEXT): $(upssched_OBJECTS) $(upssched_DEPENDENCIES) + @rm -f upssched$(EXEEXT) + $(LINK) $(upssched_OBJECTS) $(upssched_LDADD) $(LIBS) +upsset.cgi$(EXEEXT): $(upsset_cgi_OBJECTS) $(upsset_cgi_DEPENDENCIES) + @rm -f upsset.cgi$(EXEEXT) + $(LINK) $(upsset_cgi_OBJECTS) $(upsset_cgi_LDADD) $(LIBS) +upsstats.cgi$(EXEEXT): $(upsstats_cgi_OBJECTS) $(upsstats_cgi_DEPENDENCIES) + @rm -f upsstats.cgi$(EXEEXT) + $(LINK) $(upsstats_cgi_OBJECTS) $(upsstats_cgi_LDADD) $(LIBS) +install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n' \ + -e 'h;s|.*|.|' \ + -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) { files[d] = files[d] " " $$1; \ + if (++n[d] == $(am__install_max)) { \ + print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ + else { print "f", d "/" $$4, $$1 } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-dist_binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 's,.*/,,;$(transform)'`; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cgilib.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsclient.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upscmd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsimage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upslog.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsmon.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsrw.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upssched.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsset.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/upsstats.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(includedir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(includedir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) $(HEADERS) +install-binPROGRAMS: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cgiexecdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-cgiexecPROGRAMS clean-generic \ + clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-cgiexecPROGRAMS \ + install-dist_binSCRIPTS install-libLTLIBRARIES \ + install-sbinPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-cgiexecPROGRAMS \ + uninstall-dist_binSCRIPTS uninstall-includeHEADERS \ + uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-cgiexecPROGRAMS clean-generic clean-libLTLIBRARIES \ + clean-libtool clean-sbinPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-binPROGRAMS install-cgiexecPROGRAMS \ + install-data install-data-am install-dist_binSCRIPTS \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-includeHEADERS \ + install-info install-info-am install-libLTLIBRARIES \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-sbinPROGRAMS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-cgiexecPROGRAMS uninstall-dist_binSCRIPTS \ + uninstall-includeHEADERS uninstall-libLTLIBRARIES \ + uninstall-sbinPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/clients/cgilib.c b/clients/cgilib.c new file mode 100644 index 0000000..2eb9ce8 --- /dev/null +++ b/clients/cgilib.c @@ -0,0 +1,202 @@ +/* cgilib - common routines for CGI programs + + Copyright (C) 1999 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include + +#include "common.h" +#include "cgilib.h" +#include "parseconf.h" + +static char *unescape(char *buf) +{ + size_t i, buflen; + char ch, *newbuf, hex[8]; + + buflen = strlen(buf) + 2; + newbuf = xmalloc(buflen); + *newbuf = '\0'; + + fflush(stdout); + for (i = 0; i < buflen - 1; i++) { + ch = buf[i]; + + if (ch == '+') + ch = ' '; + + if (ch == '%') { + if (i + 2 > buflen) + fatalx(EXIT_FAILURE, "string too short for escaped char"); + hex[0] = buf[++i]; + hex[1] = buf[++i]; + hex[2] = '\0'; + if (!isxdigit((unsigned char) hex[0]) + || !isxdigit((unsigned char) hex[0])) + fatalx(EXIT_FAILURE, "bad escape char"); + ch = strtol(hex, NULL, 16); + + if ((ch == 10) || (ch == 13)) + ch = ' '; + } + + snprintfcat(newbuf, buflen, "%c", ch); + } + + return newbuf; +} + +void extractcgiargs(void) +{ + char *query, *ptr, *eq, *varname, *value, *amp; + char *cleanval, *cleanvar; + + query = getenv("QUERY_STRING"); + if (query == NULL) + return; /* not run as a cgi script! */ + if (strlen(query) == 0) + return; /* no query string to parse! */ + + /* varname=value&varname=value&varname=value ... */ + + ptr = query; + + while (ptr) { + varname = ptr; + eq = strchr(varname, '='); + if (!eq) { + ptr = strchr(varname, '&'); + if (ptr) + *ptr++ = '\0'; + + cleanvar = unescape(varname); + parsearg(cleanvar, ""); + free(cleanvar); + + continue; + } + + *eq = '\0'; + value = eq + 1; + amp = strchr(value, '&'); + if (amp) { + ptr = amp + 1; + *amp = '\0'; + } + else + ptr = NULL; + + cleanvar = unescape(varname); + cleanval = unescape(value); + parsearg(cleanvar, cleanval); + free(cleanvar); + free(cleanval); + } +} + +void extractpostargs(void) +{ + char buf[SMALLBUF], *ptr, *cleanval; + int ch; + + ch = fgetc(stdin); + buf[0] = '\0'; + + while (ch != EOF) { + if (ch == '&') { + ptr = strchr(buf, '='); + if (!ptr) + parsearg(buf, ""); + else { + *ptr++ = '\0'; + cleanval = unescape(ptr); + parsearg(buf, cleanval); + free(cleanval); + } + buf[0] = '\0'; + } + else + snprintfcat(buf, sizeof(buf), "%c", ch); + + ch = fgetc(stdin); + } + + if (strlen(buf) != 0) { + ptr = strchr(buf, '='); + if (!ptr) + parsearg(buf, ""); + else { + *ptr++ = '\0'; + cleanval = unescape(ptr); + parsearg(buf, cleanval); + free(cleanval); + } + } +} + +/* called for fatal errors in parseconf like malloc failures */ +static void cgilib_err(const char *errmsg) +{ + upslogx(LOG_ERR, "Fatal error in parseconf(ups.conf): %s", errmsg); +} + +int checkhost(const char *host, char **desc) +{ + char fn[SMALLBUF]; + PCONF_CTX_t ctx; + + if (!host) + return 0; /* deny null hostnames */ + + snprintf(fn, sizeof(fn), "%s/hosts.conf", confpath()); + + pconf_init(&ctx, cgilib_err); + + if (!pconf_file_begin(&ctx, fn)) { + pconf_finish(&ctx); + fprintf(stderr, "%s\n", ctx.errmsg); + + return 0; /* failed: deny access */ + } + + while (pconf_file_next(&ctx)) { + if (pconf_parse_error(&ctx)) { + fprintf(stderr, "Error: %s:%d: %s\n", + fn, ctx.linenum, ctx.errmsg); + continue; + } + + /* MONITOR */ + if (ctx.numargs < 3) + continue; + + if (strcmp(ctx.arglist[0], "MONITOR") != 0) + continue; + + if (!strcmp(ctx.arglist[1], host)) { + if (desc) + *desc = xstrdup(ctx.arglist[2]); + + pconf_finish(&ctx); + return 1; /* found: allow access */ + } + } + + pconf_finish(&ctx); + + return 0; /* not found: access denied */ +} diff --git a/clients/cgilib.h b/clients/cgilib.h new file mode 100644 index 0000000..328184d --- /dev/null +++ b/clients/cgilib.h @@ -0,0 +1,31 @@ +/* cgilib.h - headers for cgilib.c + + Copyright (C) 1999 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* other programs that link to this should provide parsearg() ... */ +void parsearg(char *var, char *value); + +/* actually extract the values from QUERY_STRING */ +void extractcgiargs(void); + +/* like extractcgiargs, but this one is for POSTed values */ +void extractpostargs(void); + +/* see if a host is allowed per the hosts.conf */ +int checkhost(const char *host, char **desc); + diff --git a/clients/status.h b/clients/status.h new file mode 100644 index 0000000..20cb858 --- /dev/null +++ b/clients/status.h @@ -0,0 +1,37 @@ +/* status.h - translation of status abbreviations to descriptions + + Copyright (C) 1999 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct { + char *name; + char *desc; + int severity; +} stattab[] = +{ + { "OFF", "OFF", 1 }, + { "OL", "ONLINE", 0 }, + { "OB", "ON BATTERY", 2 }, + { "LB", "LOW BATTERY", 2 }, + { "RB", "REPLACE BATTERY", 2 }, + { "OVER", "OVERLOAD", 2 }, + { "TRIM", "VOLTAGE TRIM", 1 }, + { "BOOST", "VOLTAGE BOOST", 1 }, + { "CAL", "CALIBRATION", 1 }, + { "BYPASS", "BYPASS", 2 }, + { NULL, NULL, 0 } +}; diff --git a/clients/upsc.c b/clients/upsc.c new file mode 100644 index 0000000..e07490b --- /dev/null +++ b/clients/upsc.c @@ -0,0 +1,229 @@ +/* upsc - simple "client" to test communications + + Copyright (C) 1999 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common.h" + +#include +#include +#include + +#include "upsclient.h" + +static char *upsname = NULL, *hostname = NULL; +static UPSCONN_t *ups = NULL; + +static void usage(const char *prog) +{ + printf("Network UPS Tools upsc %s\n\n", UPS_VERSION); + + printf("usage: %s -l | -L [[:port]]\n", prog); + printf(" %s []\n", prog); + + printf("\nDemo program to display UPS variables.\n\n"); + + printf("First form (lists UPSes):\n"); + printf(" -l - lists each UPS on , one per line.\n"); + printf(" -L - lists each UPS followed by its description (from ups.conf).\n"); + printf(" Default hostname: localhost\n"); + + printf("\nSecond form (lists variables and values):\n"); + printf(" - upsd server, [@[:]] form\n"); + printf(" - optional, display this variable only.\n"); + printf(" Default: list all variables for \n"); +} + +static void printvar(const char *var) +{ + int ret; + unsigned int numq, numa; + const char *query[4]; + char **answer; + + /* old-style variable name? */ + if (!strchr(var, '.')) { + fatalx(EXIT_FAILURE, "Error: old-style variable names are not supported"); + } + + query[0] = "VAR"; + query[1] = upsname; + query[2] = var; + + numq = 3; + + ret = upscli_get(ups, numq, query, &numa, &answer); + + if (ret < 0) { + + /* new var and old upsd? try to explain the situation */ + if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) { + fatalx(EXIT_FAILURE, "Error: variable unknown (old upsd detected)"); + } + + fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); + } + + if (numa < numq) { + fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least %d)", numa, numq); + } + + printf("%s\n", answer[3]); +} + +static void list_vars(void) +{ + int ret; + unsigned int numq, numa; + const char *query[4]; + char **answer; + + query[0] = "VAR"; + query[1] = upsname; + numq = 2; + + ret = upscli_list_start(ups, numq, query); + + if (ret < 0) { + + /* check for an old upsd */ + if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) { + fatalx(EXIT_FAILURE, "Error: upsd is too old to support this query"); + } + + fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); + } + + while (upscli_list_next(ups, numq, query, &numa, &answer) == 1) { + + /* VAR */ + if (numa < 4) { + fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least 4)", numa); + } + + printf("%s: %s\n", answer[2], answer[3]); + } +} + +static void list_upses(int verbose) +{ + int ret; + unsigned int numq, numa; + const char *query[4]; + char **answer; + + query[0] = "UPS"; + numq = 1; + + ret = upscli_list_start(ups, numq, query); + + if (ret < 0) { + /* check for an old upsd */ + if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) { + fatalx(EXIT_FAILURE, "Error: upsd is too old to support this query"); + } + + fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); + } + + while (upscli_list_next(ups, numq, query, &numa, &answer) == 1) { + + /* UPS */ + if (numa < 3) { + fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least 3)", numa); + } + + if(verbose) { + printf("%s: %s\n", answer[1], answer[2]); + } else { + printf("%s\n", answer[1]); + } + } +} + +static void clean_exit(void) +{ + if (ups) { + upscli_disconnect(ups); + } + + free(upsname); + free(hostname); + free(ups); +} + +int main(int argc, char **argv) +{ + int i, port; + int varlist = 0, verbose = 0; + const char *prog = xbasename(argv[0]); + + while ((i = getopt(argc, argv, "+hlLV")) != -1) { + + switch (i) + { + case 'L': + verbose = 1; + case 'l': + varlist = 1; + break; + + case 'V': + fatalx(EXIT_SUCCESS, "Network UPS Tools upscmd %s", UPS_VERSION); + + case 'h': + default: + usage(prog); + exit(EXIT_SUCCESS); + } + } + + argc -= optind; + argv += optind; + + /* be a good little client that cleans up after itself */ + atexit(clean_exit); + + if (varlist) { + if (upscli_splitaddr(argv[0] ? argv[0] : "localhost", &hostname, &port) != 0) { + fatalx(EXIT_FAILURE, "Error: invalid hostname.\nRequired format: [hostname[:port]]"); + } + } else { + if (upscli_splitname(argv[0], &upsname, &hostname, &port) != 0) { + fatalx(EXIT_FAILURE, "Error: invalid UPS definition.\nRequired format: upsname[@hostname[:port]]"); + } + } + + ups = xmalloc(sizeof(*ups)); + + if (upscli_connect(ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) { + fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); + } + + if (varlist) { + list_upses(verbose); + exit(EXIT_SUCCESS); + } + + if (argc > 1) { + printvar(argv[1]); + } else { + list_vars(); + } + + exit(EXIT_SUCCESS); +} diff --git a/clients/upsclient.c b/clients/upsclient.c new file mode 100644 index 0000000..ae29b2c --- /dev/null +++ b/clients/upsclient.c @@ -0,0 +1,1108 @@ +/* upsclient - network communications functions for UPS clients + + Copyright (C) + 2002 Russell Kroll + 2008 Arjen de Korte + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "config.h" /* safe because it doesn't contain prototypes */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "upsclient.h" +#include "timehead.h" + +#define UPSCLIENT_MAGIC 0x19980308 + +#define SMALLBUF 512 + +#ifdef SHUT_RDWR +#define shutdown_how SHUT_RDWR +#else +#define shutdown_how 2 +#endif + +struct { + int flags; + const char *str; +} upscli_errlist[] = +{ + { 0, "Unknown error" }, /* 0: UPSCLI_ERR_UNKNOWN */ + { 0, "Variable not supported by UPS" }, /* 1: UPSCLI_ERR_VARNOTSUPP */ + { 0, "No such host" }, /* 2: UPSCLI_ERR_NOSUCHHOST */ + { 0, "Invalid response from server" }, /* 3: UPSCLI_ERR_INVRESP */ + { 0, "Unknown UPS" }, /* 4: UPSCLI_ERR_UNKNOWNUPS */ + { 0, "Invalid list type" }, /* 5: UPSCLI_ERR_INVLISTTYPE */ + { 0, "Access denied" }, /* 6: UPSCLI_ERR_ACCESSDENIED */ + { 0, "Password required" }, /* 7: UPSCLI_ERR_PWDREQUIRED */ + { 0, "Password incorrect" }, /* 8: UPSCLI_ERR_PWDINCORRECT */ + { 0, "Missing argument" }, /* 9: UPSCLI_ERR_MISSINGARG */ + { 0, "Data stale" }, /* 10: UPSCLI_ERR_DATASTALE */ + { 0, "Variable unknown" }, /* 11: UPSCLI_ERR_VARUNKNOWN */ + { 0, "Already logged in" }, /* 12: UPSCLI_ERR_LOGINTWICE */ + { 0, "Already set password" }, /* 13: UPSCLI_ERR_PWDSETTWICE */ + { 0, "Unknown variable type" }, /* 14: UPSCLI_ERR_UNKNOWNTYPE */ + { 0, "Unknown variable" }, /* 15: UPSCLI_ERR_UNKNOWNVAR */ + { 0, "Read-only variable" }, /* 16: UPSCLI_ERR_VARREADONLY */ + { 0, "New value is too long" }, /* 17: UPSCLI_ERR_TOOLONG */ + { 0, "Invalid value for variable" }, /* 18: UPSCLI_ERR_INVALIDVALUE */ + { 0, "Set command failed" }, /* 19: UPSCLI_ERR_SETFAILED */ + { 0, "Unknown instant command" }, /* 20: UPSCLI_ERR_UNKINSTCMD */ + { 0, "Instant command failed" }, /* 21: UPSCLI_ERR_CMDFAILED */ + { 0, "Instant command not supported" }, /* 22: UPSCLI_ERR_CMDNOTSUPP */ + { 0, "Invalid username" }, /* 23: UPSCLI_ERR_INVUSERNAME */ + { 0, "Already set username" }, /* 24: UPSCLI_ERR_USERSETTWICE */ + { 0, "Unknown command" }, /* 25: UPSCLI_ERR_UNKCOMMAND */ + { 0, "Invalid argument" }, /* 26: UPSCLI_ERR_INVALIDARG */ + { 1, "Send failure: %s" }, /* 27: UPSCLI_ERR_SENDFAILURE */ + { 1, "Receive failure: %s" }, /* 28: UPSCLI_ERR_RECVFAILURE */ + { 1, "socket failure: %s" }, /* 29: UPSCLI_ERR_SOCKFAILURE */ + { 1, "bind failure: %s" }, /* 30: UPSCLI_ERR_BINDFAILURE */ + { 1, "Connection failure: %s" }, /* 31: UPSCLI_ERR_CONNFAILURE */ + { 1, "Write error: %s" }, /* 32: UPSCLI_ERR_WRITE */ + { 1, "Read error: %s" }, /* 33: UPSCLI_ERR_READ */ + { 0, "Invalid password" }, /* 34: UPSCLI_ERR_INVPASSWORD */ + { 0, "Username required" }, /* 35: UPSCLI_ERR_USERREQUIRED */ + { 0, "SSL is not available", }, /* 36: UPSCLI_ERR_SSLFAIL */ + { 2, "SSL error: %s", }, /* 37: UPSCLI_ERR_SSLERR */ + { 0, "Server disconnected", }, /* 38: UPSCLI_ERR_SRVDISC */ + { 0, "Driver not connected", }, /* 39: UPSCLI_ERR_DRVNOTCONN */ + { 0, "Memory allocation failure", }, /* 40: UPSCLI_ERR_NOMEM */ + { 3, "Parse error: %s", }, /* 41: UPSCLI_ERR_PARSE */ + { 0, "Protocol error", }, /* 42: UPSCLI_ERR_PROTOCOL */ +}; + +const char *upscli_strerror(UPSCONN_t *ups) +{ +#ifdef HAVE_SSL + unsigned long err; + char sslbuf[UPSCLI_ERRBUF_LEN]; +#endif + + if (!ups) { + return upscli_errlist[UPSCLI_ERR_INVALIDARG].str; + } + + if (ups->upsclient_magic != UPSCLIENT_MAGIC) { + return upscli_errlist[UPSCLI_ERR_INVALIDARG].str; + } + + if (ups->upserror > UPSCLI_ERR_MAX) { + return "Invalid error number"; + } + + switch (upscli_errlist[ups->upserror].flags) { + + case 0: /* simple error */ + return upscli_errlist[ups->upserror].str; + + case 1: /* add message from system's strerror */ + snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + upscli_errlist[ups->upserror].str, + strerror(ups->syserrno)); + return ups->errbuf; + + case 2: /* SSL error */ +#ifdef HAVE_SSL + err = ERR_get_error(); + if (err) { + ERR_error_string(err, sslbuf); + snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + upscli_errlist[ups->upserror].str, + sslbuf); + } else { + snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + upscli_errlist[ups->upserror].str, + "peer disconnected"); + } +#else + snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + "SSL error, but SSL wasn't enabled at compile-time"); +#endif /* HAVE_SSL */ + return ups->errbuf; + + case 3: /* parsing (parseconf) error */ + snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, + upscli_errlist[ups->upserror].str, + ups->pc_ctx.errmsg); + return ups->errbuf; + } + + /* fallthrough */ + + snprintf(ups->errbuf, UPSCLI_ERRBUF_LEN, "Unknown error flag %d", + upscli_errlist[ups->upserror].flags); + + return ups->errbuf; +} + +/* Read up to buflen bytes from fd and return the number of bytes + read. If no data is available within d_sec + d_usec, return 0. + On error, a value < 0 is returned (errno indicates error). */ +static int select_read(const int fd, void *buf, const size_t buflen, const long d_sec, const long d_usec) +{ + int ret; + fd_set fds; + struct timeval tv; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + tv.tv_sec = d_sec; + tv.tv_usec = d_usec; + + ret = select(fd + 1, &fds, NULL, NULL, &tv); + + if (ret < 1) { + return ret; + } + + return read(fd, buf, buflen); +} + +/* internal: abstract the SSL calls for the other functions */ +static int net_read(UPSCONN_t *ups, char *buf, size_t buflen) +{ + int ret; + +#ifdef HAVE_SSL + if (ups->ssl) { + ret = SSL_read(ups->ssl, buf, buflen); + + if (ret < 1) { + ups->upserror = UPSCLI_ERR_SSLERR; + } + + return ret; + } +#endif + + ret = select_read(ups->fd, buf, buflen, 5, 0); + + /* error reading data, server disconnected? */ + if (ret < 0) { + ups->upserror = UPSCLI_ERR_READ; + ups->syserrno = errno; + } + + /* no data available, server disconnected? */ + if (ret == 0) { + ups->upserror = UPSCLI_ERR_SRVDISC; + } + + return ret; +} + +/* Write up to buflen bytes to fd and return the number of bytes + written. If no data is available within d_sec + d_usec, return 0. + On error, a value < 0 is returned (errno indicates error). */ +static int select_write(const int fd, const void *buf, const size_t buflen, const long d_sec, const long d_usec) +{ + int ret; + fd_set fds; + struct timeval tv; + + FD_ZERO(&fds); + FD_SET(fd, &fds); + + tv.tv_sec = d_sec; + tv.tv_usec = d_usec; + + ret = select(fd + 1, NULL, &fds, NULL, &tv); + + if (ret < 1) { + return ret; + } + + return write(fd, buf, buflen); +} + +/* internal: abstract the SSL calls for the other functions */ +static int net_write(UPSCONN_t *ups, const char *buf, size_t buflen) +{ + int ret; + +#ifdef HAVE_SSL + if (ups->ssl) { + ret = SSL_write(ups->ssl, buf, buflen); + + if (ret < 1) { + ups->upserror = UPSCLI_ERR_SSLERR; + } + + return ret; + } +#endif + + ret = select_write(ups->fd, buf, buflen, 0, 0); + + /* error writing data, server disconnected? */ + if (ret < 0) { + ups->upserror = UPSCLI_ERR_WRITE; + ups->syserrno = errno; + } + + /* not ready for writing, server disconnected? */ + if (ret == 0) { + ups->upserror = UPSCLI_ERR_SRVDISC; + } + + return ret; +} + +/* stub first */ +#ifndef HAVE_SSL +static int upscli_sslinit(UPSCONN_t *ups) +{ + return 0; /* not supported */ +} + +int upscli_sslcert(UPSCONN_t *ups, const char *dir, const char *file, int verify) +{ + if (!ups) { + return -1; + } + + /* if forcing the verification, this fails since we have no SSL */ + if (verify == 1) { + ups->upserror = UPSCLI_ERR_SSLFAIL; + return -1; + } + + return 0; /* not supported */ +} + +#else + +static int upscli_sslinit(UPSCONN_t *ups) +{ + char buf[UPSCLI_NETBUF_LEN]; + + /* see if upsd even talks SSL/TLS */ + snprintf(buf, sizeof(buf), "STARTTLS\n"); + + if (upscli_sendline(ups, buf, strlen(buf)) != 0) { + return -1; + } + + if (upscli_readline(ups, buf, sizeof(buf)) != 0) { + return -1; + } + + if (strncmp(buf, "OK STARTTLS", 11) != 0) { + return 0; /* not supported */ + } + + /* upsd is happy, so let's crank up the client */ + + SSL_library_init(); + SSL_load_error_strings(); + + ups->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); + + if (!ups->ssl_ctx) { + return 0; + } + + ups->ssl = SSL_new(ups->ssl_ctx); + + if (!ups->ssl) { + return 0; + } + + if (SSL_set_fd(ups->ssl, ups->fd) != 1) { + return -1; + } + + SSL_set_connect_state(ups->ssl); + + return 1; /* OK */ +} + +/* set the paths for the certs to verify the server */ +int upscli_sslcert(UPSCONN_t *ups, const char *file, const char *path, int verify) +{ + int ret, ssl_mode = SSL_VERIFY_NONE; + + if (!ups) { + return -1; + } + + if (!ups->ssl_ctx) { + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + switch(verify) { + + case 0: + ssl_mode = SSL_VERIFY_NONE; + break; + case 1: + ssl_mode = SSL_VERIFY_PEER; + break; + default: + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + ret = SSL_CTX_load_verify_locations(ups->ssl_ctx, file, path); + + if (ret != 1) { + ups->upserror = UPSCLI_ERR_SSLERR; + return -1; + } + + SSL_set_verify(ups->ssl, ssl_mode, NULL); + + return 1; +} + +#endif /* HAVE_SSL */ + +int upscli_connect(UPSCONN_t *ups, const char *host, int port, int flags) +{ + int sock_fd; +#ifndef HAVE_IPV6 + struct sockaddr_in local, server; + struct hostent *serv; +#else + struct addrinfo hints, *res, *ai; + char sport[NI_MAXSERV]; + int v; +#endif + + if (!ups) { + return -1; + } + + /* clear out any lingering junk */ + memset(ups, 0, sizeof(*ups)); + ups->upsclient_magic = UPSCLIENT_MAGIC; + ups->fd = -1; + + if (!host) { + ups->upserror = UPSCLI_ERR_NOSUCHHOST; + return -1; + } + +#ifndef HAVE_IPV6 + serv = gethostbyname(host); + + if (!serv) { + struct in_addr listenaddr; + + if (!inet_aton(host, &listenaddr)) { + ups->upserror = UPSCLI_ERR_NOSUCHHOST; + return -1; + } + + serv = gethostbyaddr(&listenaddr, sizeof(listenaddr), AF_INET); + + if (!serv) { + ups->upserror = UPSCLI_ERR_NOSUCHHOST; + return -1; + } + } + + if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + ups->upserror = UPSCLI_ERR_SOCKFAILURE; + ups->syserrno = errno; + close(sock_fd); + return -1; + } + + memset(&local, '\0', sizeof(local)); + local.sin_family = AF_INET; + local.sin_port = htons(INADDR_ANY); + + memset(&server, '\0', sizeof(server)); + server.sin_family = AF_INET; + server.sin_port = htons(port); + + memcpy(&server.sin_addr, serv->h_addr, serv->h_length); + + if (bind(sock_fd, (struct sockaddr *) &local, sizeof(local)) < 0) { + ups->upserror = UPSCLI_ERR_BINDFAILURE; + ups->syserrno = errno; + close(sock_fd); + return -1; + } + + if (connect(sock_fd, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) < 0) { + ups->upserror = UPSCLI_ERR_CONNFAILURE; + ups->syserrno = errno; + close(sock_fd); + return -1; + } + + ups->fd = sock_fd; +#else + snprintf(sport, sizeof(sport), "%hu", (unsigned short int)port); + + memset(&hints, 0, sizeof(hints)); + + if (flags & UPSCLI_CONN_INET6) { + hints.ai_family = AF_INET6; + } else if (flags & UPSCLI_CONN_INET) { + hints.ai_family = AF_INET; + } else { + hints.ai_family = AF_UNSPEC; + } + + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + while ((v = getaddrinfo(host, sport, &hints, &res)) != 0) { + switch (v) + { + case EAI_AGAIN: + continue; + case EAI_NONAME: + ups->upserror = UPSCLI_ERR_NOSUCHHOST; + return -1; + case EAI_MEMORY: + ups->upserror = UPSCLI_ERR_NOMEM; + return -1; + case EAI_SYSTEM: + ups->syserrno = errno; + break; + } + + ups->upserror = UPSCLI_ERR_UNKNOWN; + return -1; + } + + for (ai = res; ai != NULL; ai = ai->ai_next) { + + sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + + if (sock_fd < 0) { + switch (errno) + { + case EAFNOSUPPORT: + case EINVAL: + break; + default: + ups->upserror = UPSCLI_ERR_SOCKFAILURE; + ups->syserrno = errno; + } + continue; + } + + while ((v = connect(sock_fd, ai->ai_addr, ai->ai_addrlen)) < 0) { + switch (errno) + { + case EAFNOSUPPORT: + break; + case EINTR: + case EAGAIN: + continue; + default: + ups->upserror = UPSCLI_ERR_CONNFAILURE; + ups->syserrno = errno; + } + break; + } + + if (v < 0) { + close(sock_fd); + continue; + } + + ups->fd = sock_fd; + ups->upserror = 0; + ups->syserrno = 0; + break; + } + + freeaddrinfo(res); + + if (ups->fd < 0) { + return -1; + } +#endif + pconf_init(&ups->pc_ctx, NULL); + + ups->host = strdup(host); + + if (!ups->host) { + ups->upserror = UPSCLI_ERR_NOMEM; + upscli_disconnect(ups); + return -1; + } + + ups->port = port; + + if (flags & UPSCLI_CONN_TRYSSL) { + upscli_sslinit(ups); + + /* see if something made us die inside sslinit */ + if (ups->upserror != 0) { + upscli_disconnect(ups); + return -1; + } + } + + if ((flags & UPSCLI_CONN_REQSSL) && (upscli_sslinit(ups) != 1)) { + ups->upserror = UPSCLI_ERR_SSLFAIL; + upscli_disconnect(ups); + return -1; + } + + return 0; +} + +/* map upsd error strings back to upsclient internal numbers */ +static struct { + int errnum; + const char *text; +} upsd_errlist[] = +{ + { UPSCLI_ERR_VARNOTSUPP, "VAR-NOT-SUPPORTED" }, + { UPSCLI_ERR_UNKNOWNUPS, "UNKNOWN-UPS" }, + { UPSCLI_ERR_ACCESSDENIED, "ACCESS-DENIED" }, + { UPSCLI_ERR_PWDREQUIRED, "PASSWORD-REQUIRED" }, + { UPSCLI_ERR_PWDINCORRECT, "PASSWORD-INCORRECT" }, + { UPSCLI_ERR_MISSINGARG, "MISSING-ARGUMENT" }, + { UPSCLI_ERR_DATASTALE, "DATA-STALE" }, + { UPSCLI_ERR_VARUNKNOWN, "VAR-UNKNOWN" }, + { UPSCLI_ERR_LOGINTWICE, "ALREADY-LOGGED-IN" }, + { UPSCLI_ERR_PWDSETTWICE, "ALREADY-SET-PASSWORD" }, + { UPSCLI_ERR_UNKNOWNTYPE, "UNKNOWN-TYPE" }, + { UPSCLI_ERR_UNKNOWNVAR, "UNKNOWN-VAR" }, + { UPSCLI_ERR_VARREADONLY, "READONLY" }, + { UPSCLI_ERR_TOOLONG, "TOO-LONG" }, + { UPSCLI_ERR_INVALIDVALUE, "INVALID-VALUE" }, + { UPSCLI_ERR_SETFAILED, "SET-FAILED" }, + { UPSCLI_ERR_UNKINSTCMD, "UNKNOWN-INSTCMD" }, + { UPSCLI_ERR_CMDFAILED, "INSTCMD-FAILED" }, + { UPSCLI_ERR_CMDNOTSUPP, "CMD-NOT-SUPPORTED" }, + { UPSCLI_ERR_INVUSERNAME, "INVALID-USERNAME" }, + { UPSCLI_ERR_USERSETTWICE, "ALREADY-SET-USERNAME" }, + { UPSCLI_ERR_UNKCOMMAND, "UNKNOWN-COMMAND" }, + { UPSCLI_ERR_INVPASSWORD, "INVALID-PASSWORD" }, + { UPSCLI_ERR_USERREQUIRED, "USERNAME-REQUIRED" }, + { UPSCLI_ERR_DRVNOTCONN, "DRIVER-NOT-CONNECTED" }, + + { 0, NULL, } +}; + +static int upscli_errcheck(UPSCONN_t *ups, char *buf) +{ + int i; + + if (!ups) { + return -1; + } + + if (!buf) { + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + /* see if it's even an error now */ + if (strncmp(buf, "ERR", 3) != 0) { + return 0; + } + + /* look it up in the table */ + for (i = 0; upsd_errlist[i].text != NULL; i++) { + if (!strncmp(&buf[4], upsd_errlist[i].text, + strlen(upsd_errlist[i].text))) { + ups->upserror = upsd_errlist[i].errnum; + return -1; + } + } + + /* hmm - don't know what upsd is telling us */ + ups->upserror = UPSCLI_ERR_UNKNOWN; + return -1; +} + +static void build_cmd(char *buf, size_t bufsize, const char *cmdname, + int numarg, const char **arg) +{ + int i; + size_t len; + char enc[UPSCLI_NETBUF_LEN]; + const char *format; + + memset(buf, '\0', bufsize); + snprintf(buf, bufsize, "%s", cmdname); + + /* encode all arguments so they arrive intact */ + for (i = 0; i < numarg; i++) { + + if (strchr(arg[i], ' ')) { + format = " \"%s\""; /* wrap in "" */ + } else { + format = " %s"; + } + + /* snprintfcat would tie us to common */ + + len = strlen(buf); + snprintf(buf + len, bufsize - len, format, + pconf_encode(arg[i], enc, sizeof(enc))); + } + + len = strlen(buf); + snprintf(buf + len, bufsize - len, "\n"); +} + +/* make sure upsd is giving us what we asked for */ +static int verify_resp(int num, const char **q, char **a) +{ + int i; + + for (i = 0; i < num; i++) { + if (strcasecmp(q[i], a[i]) != 0) { + + /* FUTURE: handle -/+ options here */ + return 0; /* mismatch */ + } + } + + return 1; /* OK */ +} + +int upscli_get(UPSCONN_t *ups, unsigned int numq, const char **query, + unsigned int *numa, char ***answer) +{ + char cmd[UPSCLI_NETBUF_LEN], tmp[UPSCLI_NETBUF_LEN]; + + if (!ups) { + return -1; + } + + if (numq < 1) { + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + /* create the string to send to upsd */ + build_cmd(cmd, sizeof(cmd), "GET", numq, query); + + if (upscli_sendline(ups, cmd, strlen(cmd)) != 0) { + return -1; + } + + if (upscli_readline(ups, tmp, sizeof(tmp)) != 0) { + return -1; + } + + if (upscli_errcheck(ups, tmp) != 0) { + return -1; + } + + if (!pconf_line(&ups->pc_ctx, tmp)) { + ups->upserror = UPSCLI_ERR_PARSE; + return -1; + } + + /* q: [GET] VAR * + * a: VAR */ + + if (ups->pc_ctx.numargs < numq) { + ups->upserror = UPSCLI_ERR_PROTOCOL; + return -1; + } + + if (!verify_resp(numq, query, ups->pc_ctx.arglist)) { + ups->upserror = UPSCLI_ERR_PROTOCOL; + return -1; + } + + *numa = ups->pc_ctx.numargs; + *answer = ups->pc_ctx.arglist; + + return 0; +} + +int upscli_list_start(UPSCONN_t *ups, unsigned int numq, const char **query) +{ + char cmd[UPSCLI_NETBUF_LEN], tmp[UPSCLI_NETBUF_LEN]; + + if (!ups) { + return -1; + } + + if (numq < 1) { + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + /* create the string to send to upsd */ + build_cmd(cmd, sizeof(cmd), "LIST", numq, query); + + if (upscli_sendline(ups, cmd, strlen(cmd)) != 0) { + return -1; + } + + if (upscli_readline(ups, tmp, sizeof(tmp)) != 0) { + return -1; + } + + if (upscli_errcheck(ups, tmp) != 0) { + return -1; + } + + if (!pconf_line(&ups->pc_ctx, tmp)) { + ups->upserror = UPSCLI_ERR_PARSE; + return -1; + } + + if (ups->pc_ctx.numargs < 2) { + ups->upserror = UPSCLI_ERR_PROTOCOL; + return -1; + } + + /* the response must start with BEGIN LIST */ + if ((strcasecmp(ups->pc_ctx.arglist[0], "BEGIN") != 0) || + (strcasecmp(ups->pc_ctx.arglist[1], "LIST") != 0)) { + ups->upserror = UPSCLI_ERR_PROTOCOL; + return -1; + } + + /* q: [LIST] VAR * + * a: [BEGIN LIST] VAR */ + + /* compare q[0]... to a[2]... */ + + if (!verify_resp(numq, query, &ups->pc_ctx.arglist[2])) { + ups->upserror = UPSCLI_ERR_PROTOCOL; + return -1; + } + + return 0; +} + +int upscli_list_next(UPSCONN_t *ups, unsigned int numq, const char **query, + unsigned int *numa, char ***answer) +{ + char tmp[UPSCLI_NETBUF_LEN]; + + if (!ups) { + return -1; + } + + if (upscli_readline(ups, tmp, sizeof(tmp)) != 0) { + return -1; + } + + if (upscli_errcheck(ups, tmp) != 0) { + return -1; + } + + if (!pconf_line(&ups->pc_ctx, tmp)) { + ups->upserror = UPSCLI_ERR_PARSE; + return -1; + } + + if (ups->pc_ctx.numargs < 1) { + ups->upserror = UPSCLI_ERR_PROTOCOL; + return -1; + } + + *numa = ups->pc_ctx.numargs; + *answer = ups->pc_ctx.arglist; + + /* see if this is the end */ + if (ups->pc_ctx.numargs >= 2) { + if ((!strcmp(ups->pc_ctx.arglist[0], "END")) && + (!strcmp(ups->pc_ctx.arglist[1], "LIST"))) + return 0; + } + + /* q: VAR */ + /* a: VAR */ + + if (!verify_resp(numq, query, ups->pc_ctx.arglist)) { + ups->upserror = UPSCLI_ERR_PROTOCOL; + return -1; + } + + /* just another part of the list */ + return 1; +} + +int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen) +{ + int ret; + + if (!ups) { + return -1; + } + + if (ups->fd < 0) { + ups->upserror = UPSCLI_ERR_DRVNOTCONN; + return -1; + } + + if ((!buf) || (buflen < 1)) { + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + if (ups->upsclient_magic != UPSCLIENT_MAGIC) { + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + ret = net_write(ups, buf, buflen); + + if (ret < 1) { + upscli_disconnect(ups); + return -1; + } + + return 0; +} + +int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen) +{ + int ret; + size_t recv; + + if (!ups) { + return -1; + } + + if (ups->fd < 0) { + ups->upserror = UPSCLI_ERR_DRVNOTCONN; + return -1; + } + + if ((!buf) || (buflen < 1)) { + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + if (ups->upsclient_magic != UPSCLIENT_MAGIC) { + ups->upserror = UPSCLI_ERR_INVALIDARG; + return -1; + } + + for (recv = 0; recv < (buflen-1); recv++) { + + if (ups->readidx == ups->readlen) { + + ret = net_read(ups, ups->readbuf, sizeof(ups->readbuf)); + + if (ret < 1) { + upscli_disconnect(ups); + return -1; + } + + ups->readlen = ret; + ups->readidx = 0; + } + + buf[recv] = ups->readbuf[ups->readidx++]; + + if (buf[recv] == '\n') { + break; + } + } + + buf[recv] = '\0'; + return 0; +} + +/* split upsname[@hostname[:port]] into separate components */ +int upscli_splitname(const char *buf, char **upsname, char **hostname, int *port) +{ + char *s, tmp[SMALLBUF], *last = NULL; + + /* paranoia */ + if ((!buf) || (!upsname) || (!hostname) || (!port)) { + return -1; + } + + if (snprintf(tmp, sizeof(tmp), "%s", buf) < 1) { + fprintf(stderr, "upscli_splitname: can't parse empty string\n"); + return -1; + } + + s = strchr(tmp, '@'); + + if ((*upsname = strdup(strtok_r(tmp, "@", &last))) == NULL) { + fprintf(stderr, "upscli_splitname: strdup failed\n"); + return -1; + } + + /* only a upsname is specified, fill in defaults */ + if (s == NULL) { + if ((*hostname = strdup("localhost")) == NULL) { + fprintf(stderr, "upscli_splitname: strdup failed\n"); + return -1; + } + + *port = PORT; + return 0; + } + + return upscli_splitaddr(s+1, hostname, port); +} + +/* split hostname[:port] into separate components */ +int upscli_splitaddr(const char *buf, char **hostname, int *port) +{ + char *s, tmp[SMALLBUF], *last = NULL; + + /* paranoia */ + if ((!buf) || (!hostname) || (!port)) { + return -1; + } + + if (snprintf(tmp, sizeof(tmp), "%s", buf) < 1) { + fprintf(stderr, "upscli_splitaddr: can't parse empty string\n"); + return -1; + } + + if (*tmp == '[') { + if (strchr(tmp, ']') == NULL) { + fprintf(stderr, "upscli_splitaddr: missing closing bracket in [domain literal]\n"); + return -1; + } + + if ((*hostname = strdup(strtok_r(tmp+1, "]", &last))) == NULL) { + fprintf(stderr, "upscli_splitaddr: strdup failed\n"); + return -1; + } + + /* no port specified, use default */ + if (((s = strtok_r(NULL, "\0", &last)) == NULL) || (*s != ':')) { + *port = PORT; + return 0; + } + } else { + s = strchr(tmp, ':'); + + if ((*hostname = strdup(strtok_r(tmp, ":", &last))) == NULL) { + fprintf(stderr, "upscli_splitaddr: strdup failed\n"); + return -1; + } + + /* no port specified, use default */ + if (s == NULL) { + *port = PORT; + return 0; + } + } + + if ((*(++s) == '\0') || ((*port = strtol(s, NULL, 10)) < 1 )) { + fprintf(stderr, "upscli_splitaddr: no port specified after ':' separator\n"); + return -1; + } + + return 0; +} + +int upscli_disconnect(UPSCONN_t *ups) +{ + if (!ups) { + return -1; + } + + if (ups->upsclient_magic != UPSCLIENT_MAGIC) { + return -1; + } + + pconf_finish(&ups->pc_ctx); + + free(ups->host); + ups->host = NULL; + + if (ups->fd < 0) { + return 0; + } + + net_write(ups, "LOGOUT\n", 7); + +#ifdef HAVE_SSL + if (ups->ssl) { + SSL_shutdown(ups->ssl); + SSL_free(ups->ssl); + ups->ssl = NULL; + } + + if (ups->ssl_ctx) { + SSL_CTX_free(ups->ssl_ctx); + ups->ssl_ctx = NULL; + } +#endif + + shutdown(ups->fd, shutdown_how); + + close(ups->fd); + ups->fd = -1; + + return 0; +} + +int upscli_fd(UPSCONN_t *ups) +{ + if (!ups) { + return -1; + } + + if (ups->upsclient_magic != UPSCLIENT_MAGIC) { + return -1; + } + + return ups->fd; +} + +int upscli_upserror(UPSCONN_t *ups) +{ + if (!ups) { + return -1; + } + + if (ups->upsclient_magic != UPSCLIENT_MAGIC) { + return -1; + } + + return ups->upserror; +} + +int upscli_ssl(UPSCONN_t *ups) +{ + if (!ups) { + return -1; + } + + if (ups->upsclient_magic != UPSCLIENT_MAGIC) { + return -1; + } + + if (ups->ssl) { + return 1; + } + + return 0; +} diff --git a/clients/upsclient.h b/clients/upsclient.h new file mode 100644 index 0000000..1b05341 --- /dev/null +++ b/clients/upsclient.h @@ -0,0 +1,166 @@ +/* upsclient.h - definitions for upsclient functions + + Copyright (C) 2002 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef UPSCLIENT_H_SEEN +#define UPSCLIENT_H_SEEN + +#ifdef HAVE_SSL +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define UPSCLI_ERRBUF_LEN 256 +#define UPSCLI_NETBUF_LEN 512 /* network i/o buffer */ + +#include "parseconf.h" + +typedef struct { + char *host; + int port; + int fd; + int flags; + int upserror; + int syserrno; + int upsclient_magic; + + PCONF_CTX_t pc_ctx; + + char errbuf[UPSCLI_ERRBUF_LEN]; + +#ifdef HAVE_SSL + SSL_CTX *ssl_ctx; + SSL *ssl; +#else + void *ssl_ctx; + void *ssl; +#endif + + char readbuf[64]; + size_t readlen; + size_t readidx; + +} UPSCONN_t; + +const char *upscli_strerror(UPSCONN_t *ups); + +int upscli_connect(UPSCONN_t *ups, const char *host, int port, int flags); + +/* --- functions that only use the new names --- */ + +int upscli_get(UPSCONN_t *ups, unsigned int numq, const char **query, + unsigned int *numa, char ***answer); + +int upscli_list_start(UPSCONN_t *ups, unsigned int numq, const char **query); + +int upscli_list_next(UPSCONN_t *ups, unsigned int numq, const char **query, + unsigned int *numa, char ***answer); + +int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen); + +int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen); + +int upscli_splitname(const char *buf, char **upsname, char **hostname, + int *port); + +int upscli_splitaddr(const char *buf, char **hostname, int *port); + +int upscli_sslcert(UPSCONN_t *ups, const char *file, const char *path, int verify); + +int upscli_disconnect(UPSCONN_t *ups); + +/* these functions return elements from UPSCONN_t to avoid direct references */ + +int upscli_fd(UPSCONN_t *ups); +int upscli_upserror(UPSCONN_t *ups); + +/* returns 1 if SSL mode is active for this connection */ +int upscli_ssl(UPSCONN_t *ups); + +/* upsclient error list */ + +#define UPSCLI_ERR_UNKNOWN 0 /* Unknown error */ +#define UPSCLI_ERR_VARNOTSUPP 1 /* Variable not supported by UPS */ +#define UPSCLI_ERR_NOSUCHHOST 2 /* No such host */ +#define UPSCLI_ERR_INVRESP 3 /* Invalid response from server */ +#define UPSCLI_ERR_UNKNOWNUPS 4 /* Unknown UPS */ +#define UPSCLI_ERR_INVLISTTYPE 5 /* Invalid list type */ +#define UPSCLI_ERR_ACCESSDENIED 6 /* Access denied */ +#define UPSCLI_ERR_PWDREQUIRED 7 /* Password required */ +#define UPSCLI_ERR_PWDINCORRECT 8 /* Password incorrect */ +#define UPSCLI_ERR_MISSINGARG 9 /* Missing argument */ +#define UPSCLI_ERR_DATASTALE 10 /* Data stale */ +#define UPSCLI_ERR_VARUNKNOWN 11 /* Variable unknown */ +#define UPSCLI_ERR_LOGINTWICE 12 /* Already logged in */ +#define UPSCLI_ERR_PWDSETTWICE 13 /* Already set password */ +#define UPSCLI_ERR_UNKNOWNTYPE 14 /* Unknown variable type */ +#define UPSCLI_ERR_UNKNOWNVAR 15 /* Unknown variable */ +#define UPSCLI_ERR_VARREADONLY 16 /* Read-only variable */ +#define UPSCLI_ERR_TOOLONG 17 /* New value is too long */ +#define UPSCLI_ERR_INVALIDVALUE 18 /* Invalid value for variable */ +#define UPSCLI_ERR_SETFAILED 19 /* Set command failed */ +#define UPSCLI_ERR_UNKINSTCMD 20 /* Unknown instant command */ +#define UPSCLI_ERR_CMDFAILED 21 /* Instant command failed */ +#define UPSCLI_ERR_CMDNOTSUPP 22 /* Instant command not supported */ +#define UPSCLI_ERR_INVUSERNAME 23 /* Invalid username */ +#define UPSCLI_ERR_USERSETTWICE 24 /* Already set username */ +#define UPSCLI_ERR_UNKCOMMAND 25 /* Unknown command */ +#define UPSCLI_ERR_INVALIDARG 26 /* Invalid argument */ +#define UPSCLI_ERR_SENDFAILURE 27 /* Send failure: %s */ +#define UPSCLI_ERR_RECVFAILURE 28 /* Receive failure: %s */ +#define UPSCLI_ERR_SOCKFAILURE 29 /* socket failure: %s */ +#define UPSCLI_ERR_BINDFAILURE 30 /* bind failure: %s */ +#define UPSCLI_ERR_CONNFAILURE 31 /* Connection failure: %s */ +#define UPSCLI_ERR_WRITE 32 /* Write error: %s */ +#define UPSCLI_ERR_READ 33 /* Read error: %s */ +#define UPSCLI_ERR_INVPASSWORD 34 /* Invalid password */ +#define UPSCLI_ERR_USERREQUIRED 35 /* Username required */ +#define UPSCLI_ERR_SSLFAIL 36 /* SSL is not available */ +#define UPSCLI_ERR_SSLERR 37 /* SSL error: %s */ +#define UPSCLI_ERR_SRVDISC 38 /* Server disconnected */ +#define UPSCLI_ERR_DRVNOTCONN 39 /* Driver not connected */ +#define UPSCLI_ERR_NOMEM 40 /* Memory allocation failure */ +#define UPSCLI_ERR_PARSE 41 /* Parse error: %s */ +#define UPSCLI_ERR_PROTOCOL 42 /* Protocol error */ + +#define UPSCLI_ERR_MAX 42 /* stop here */ + +/* list types for use with upscli_getlist */ + +#define UPSCLI_LIST_VARS 1 /* all variables */ +#define UPSCLI_LIST_RW 2 /* just read/write variables */ +#define UPSCLI_LIST_CMDS 3 /* instant commands */ + +/* flags for use with upscli_connect */ + +#define UPSCLI_CONN_TRYSSL 0x0001 /* try SSL, OK if not supported */ +#define UPSCLI_CONN_REQSSL 0x0002 /* try SSL, fail if not supported */ +#ifdef HAVE_IPV6 +#define UPSCLI_CONN_INET 0x0004 /* IPv4 only */ +#define UPSCLI_CONN_INET6 0x0008 /* IPv6 only */ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* UPSCLIENT_H_SEEN */ diff --git a/clients/upscmd.c b/clients/upscmd.c new file mode 100644 index 0000000..cba125d --- /dev/null +++ b/clients/upscmd.c @@ -0,0 +1,311 @@ +/* upscmd - simple "client" to test instant commands via upsd + + Copyright (C) 2000 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common.h" + +#include +#include +#include +#include +#include + +#include "upsclient.h" + +static char *upsname = NULL, *hostname = NULL; +static UPSCONN_t *ups = NULL; + +struct list_t { + char *name; + struct list_t *next; +}; + +static void usage(const char *prog) +{ + printf("Network UPS Tools upscmd %s\n\n", UPS_VERSION); + printf("usage: %s [-h]\n", prog); + printf(" %s [-l ]\n", prog); + printf(" %s [-u ] [-p ] []\n\n", prog); + printf("Administration program to initiate instant commands on UPS hardware.\n"); + printf("\n"); + printf(" -h display this help text\n"); + printf(" -l show available commands on UPS \n"); + printf(" -u set username for command authentication\n"); + printf(" -p set password for command authentication\n"); + printf("\n"); + printf(" UPS identifier - [@[:]]\n"); + printf(" Valid instant command - test.panel.start, etc.\n"); + printf(" [] Additional data for command - number of seconds, etc.\n"); +} + +static void print_cmd(char *cmdname) +{ + int ret; + unsigned int numq, numa; + const char *query[4]; + char **answer; + + query[0] = "CMDDESC"; + query[1] = upsname; + query[2] = cmdname; + numq = 3; + + ret = upscli_get(ups, numq, query, &numa, &answer); + + if ((ret < 0) || (numa < numq)) { + printf("%s\n", cmdname); + return; + } + + /* CMDDESC */ + printf("%s - %s\n", cmdname, answer[3]); +} + +static void listcmds(void) +{ + int ret; + unsigned int numq, numa; + const char *query[4]; + char **answer; + struct list_t *lhead = NULL, *llast = NULL, *ltmp, *lnext; + + query[0] = "CMD"; + query[1] = upsname; + numq = 2; + + ret = upscli_list_start(ups, numq, query); + + if (ret < 0) { + + /* old upsd = no way to continue */ + if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) { + fatalx(EXIT_FAILURE, "Error: upsd is too old to support this query"); + } + + fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); + } + + while (upscli_list_next(ups, numq, query, &numa, &answer) == 1) { + + /* CMD */ + if (numa < 3) { + fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least 3)", numa); + } + + /* we must first read the entire list of commands, + before we can start reading the descriptions */ + + ltmp = xcalloc(1, sizeof(*ltmp)); + ltmp->name = xstrdup(answer[2]); + + if (llast) { + llast->next = ltmp; + } else { + lhead = ltmp; + } + + llast = ltmp; + } + + /* walk the list and try to get descriptions, freeing as we go */ + printf("Instant commands supported on UPS [%s]:\n\n", upsname); + + for (ltmp = lhead; ltmp; ltmp = lnext) { + lnext = ltmp->next; + + print_cmd(ltmp->name); + + free(ltmp->name); + free(ltmp); + } +} + +static void do_cmd(char **argv, const int argc) +{ + char buf[SMALLBUF]; + + if (argc > 1) { + snprintf(buf, sizeof(buf), "INSTCMD %s %s %s\n", upsname, argv[0], argv[1]); + } else { + snprintf(buf, sizeof(buf), "INSTCMD %s %s\n", upsname, argv[0]); + } + + if (upscli_sendline(ups, buf, strlen(buf)) < 0) { + fatalx(EXIT_FAILURE, "Can't send instant command: %s", upscli_strerror(ups)); + } + + if (upscli_readline(ups, buf, sizeof(buf)) < 0) { + fatalx(EXIT_FAILURE, "Instant command failed: %s", upscli_strerror(ups)); + } +} + +static void clean_exit(void) +{ + if (ups) { + upscli_disconnect(ups); + } + + free(upsname); + free(hostname); + free(ups); +} + +int main(int argc, char **argv) +{ + int i, ret, port; + int have_un = 0, have_pw = 0, cmdlist = 0; + char buf[SMALLBUF], username[SMALLBUF], password[SMALLBUF]; + const char *prog = xbasename(argv[0]); + + while ((i = getopt(argc, argv, "+lhu:p:V")) != -1) { + + switch (i) + { + case 'l': + cmdlist = 1; + break; + + case 'u': + snprintf(username, sizeof(username), "%s", optarg); + have_un = 1; + break; + + case 'p': + snprintf(password, sizeof(password), "%s", optarg); + have_pw = 1; + break; + + case 'V': + fatalx(EXIT_SUCCESS, "Network UPS Tools upscmd %s", UPS_VERSION); + + case 'h': + default: + usage(prog); + exit(EXIT_SUCCESS); + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) { + usage(prog); + exit(EXIT_SUCCESS); + } + + /* be a good little client that cleans up after itself */ + atexit(clean_exit); + + if (upscli_splitname(argv[0], &upsname, &hostname, &port) != 0) { + fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]"); + } + + ups = xcalloc(1, sizeof(*ups)); + + if (upscli_connect(ups, hostname, port, 0) < 0) { + fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups)); + } + + if (cmdlist) { + listcmds(); + exit(EXIT_SUCCESS); + } + + if (argc < 2) { + usage(prog); + exit(EXIT_SUCCESS); + } + + /* also fallback for old command names */ + if (!strchr(argv[1], '.')) { + fatalx(EXIT_FAILURE, "Error: old command names are not supported"); + } + + if (!have_un) { + struct passwd *pw; + + memset(username, '\0', sizeof(username)); + pw = getpwuid(getuid()); + + if (pw) { + printf("Username (%s): ", pw->pw_name); + } else { + printf("Username: "); + } + + if (!fgets(username, sizeof(username), stdin)) { + fatalx(EXIT_FAILURE, "Error reading from stdin!"); + } + + /* deal with that pesky newline */ + if (strlen(username) > 1) { + username[strlen(username) - 1] = '\0'; + } else { + if (!pw) { + fatalx(EXIT_FAILURE, "No username available - even tried getpwuid"); + } + + snprintf(username, sizeof(username), "%s", pw->pw_name); + } + } + + /* getpass leaks slightly - use -p when testing in valgrind */ + if (!have_pw) { + /* using getpass or getpass_r might not be a + good idea here (marked obsolete in POSIX) */ + char *pwtmp = GETPASS("Password: "); + + if (!pwtmp) { + fatalx(EXIT_FAILURE, "getpass failed: %s", strerror(errno)); + } + + snprintf(password, sizeof(password), "%s", pwtmp); + } + + snprintf(buf, sizeof(buf), "USERNAME %s\n", username); + + if (upscli_sendline(ups, buf, strlen(buf)) < 0) { + fatalx(EXIT_FAILURE, "Can't set username: %s", upscli_strerror(ups)); + } + + ret = upscli_readline(ups, buf, sizeof(buf)); + + if (ret < 0) { + if (upscli_upserror(ups) != UPSCLI_ERR_UNKCOMMAND) { + fatalx(EXIT_FAILURE, "Set username failed: %s", upscli_strerror(ups)); + } + + fatalx(EXIT_FAILURE, + "Set username failed due to an unknown command.\n" + "You probably need to upgrade upsd."); + } + + snprintf(buf, sizeof(buf), "PASSWORD %s\n", password); + + if (upscli_sendline(ups, buf, strlen(buf)) < 0) { + fatalx(EXIT_FAILURE, "Can't set password: %s", upscli_strerror(ups)); + } + + if (upscli_readline(ups, buf, sizeof(buf)) < 0) { + fatalx(EXIT_FAILURE, "Set password failed: %s", upscli_strerror(ups)); + } + + do_cmd(&argv[1], argc - 1); + + exit(EXIT_SUCCESS); +} diff --git a/clients/upsimage.c b/clients/upsimage.c new file mode 100644 index 0000000..9a64463 --- /dev/null +++ b/clients/upsimage.c @@ -0,0 +1,731 @@ +/* upsimage - cgi program to create graphical ups information reports + + Status: + 20020814 - Simon Rozman + - redesigned the meters + 20020823 - Simon Rozman + - added support for width, height and scale_height parameters + - added support for outvolt + - noimage now writes out a clue, why upsimage failed + 20020902 - Simon Rozman + - background now transparent by default + - added support for colorization parameters + - removed linear antialiasing of the scale, until I come up with a better algorithm + 20020913 - Simon Rozman + - added width, height and scale_height to imgarg table + 20020928 - Simon Rozman + - added imgvar table to hold description, how to draw each UPS variable supported + - added support for ACFREQ, OUT_FREQ and UPSTEMP + + Copyrights: + (C) 1998 Russell Kroll + (C) 2002 Simon Rozman + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "common.h" +#include "upsclient.h" +#include "cgilib.h" +#include +#include +#include + +#include "upsimagearg.h" + +#define MAX_CGI_STRLEN 64 + +static char *monhost = NULL, *cmd = NULL; + +static int port; +static char *upsname, *hostname; +static UPSCONN_t ups; + +#define RED(x) ((x >> 16) & 0xff) +#define GREEN(x) ((x >> 8) & 0xff) +#define BLUE(x) (x & 0xff) + + +void parsearg(char *var, char *value) +{ + int i, v; + + /* avoid bogus junk from evil people */ + if ((strlen(var) > MAX_CGI_STRLEN) || (strlen(value) > MAX_CGI_STRLEN)) + return; + + if (!strcmp(var, "host")) { + free(monhost); + monhost = xstrdup(value); + return; + } + + if (!strcmp(var, "display")) { + free(cmd); + cmd = xstrdup(value); + return; + } + + /* see if this is one of the shared (upsimagearg.h) variables */ + for (i = 0; imgarg[i].name != NULL; i++) { + if (!strcmp(imgarg[i].name, var)) { + if (!strncmp(value, "0x", 2)) + v = strtoul(value + 2, (char **)NULL, 16); + else + v = atoi(value); + + /* avoid false numbers from bad people */ + if (v < imgarg[i].min) + imgarg[i].val = imgarg[i].min; + else if (v > imgarg[i].max) + imgarg[i].val = imgarg[i].max; + else + imgarg[i].val = v; + return; + } + } +} + +/* return the value from the URL or the default if it wasn't set */ +static int get_imgarg(const char *name) +{ + int i; + + for (i = 0; imgarg[i].name != NULL; i++) + if (!strcmp(imgarg[i].name, name)) + return imgarg[i].val; + + return -1; +} + +/* write the HTML header then have gd dump the image */ +static void drawimage(gdImagePtr im) +{ + printf("Pragma: no-cache\n"); + printf("Content-type: image/png\n\n"); + + gdImagePng(im, stdout); + gdImageDestroy(im); + + upscli_disconnect(&ups); + + exit(EXIT_SUCCESS); +} + +/* helper function to allocate color in the image */ +static int color_alloc(gdImagePtr im, int rgb) +{ + return gdImageColorAllocate(im, RED(rgb), GREEN(rgb), BLUE(rgb)); +} + +/* draws the scale behind the bar indicator */ +static void drawscale( + gdImagePtr im, /* image where we would like to draw scale */ + int lvllo, int lvlhi, /* min and max numbers on the scale */ + int step, int step5, int step10, /* steps for minor, submajor and major dashes */ + int redlo1, int redhi1, /* first red zone start and end */ + int redlo2, int redhi2, /* second red zone start and end */ + int grnlo, int grnhi) /* green zone start and end */ +{ + int col1, col2, back_color, scale_num_color, ok_zone_maj_color, + ok_zone_min_color, neutral_zone_maj_color, + neutral_zone_min_color, warn_zone_maj_color, + warn_zone_min_color; + char lbltxt[SMALLBUF]; + int y, level, range; + int width, height, scale_height; + + back_color = color_alloc(im, get_imgarg("back_col")); + scale_num_color = color_alloc(im, get_imgarg("scale_num_col")); + ok_zone_maj_color = color_alloc(im, get_imgarg("ok_zone_maj_col")); + ok_zone_min_color = color_alloc(im, get_imgarg("ok_zone_min_col")); + neutral_zone_maj_color = color_alloc(im, get_imgarg("neutral_zone_maj_col")); + neutral_zone_min_color = color_alloc(im, get_imgarg("neutral_zone_min_col")); + warn_zone_maj_color = color_alloc(im, get_imgarg("warn_zone_maj_col")); + warn_zone_min_color = color_alloc(im, get_imgarg("warn_zone_min_col")); + + width = get_imgarg("width"); + height = get_imgarg("height"); + scale_height = get_imgarg("scale_height"); + + /* start out with a background color and make it transparent */ + gdImageFilledRectangle(im, 0, 0, width, height, back_color); + gdImageColorTransparent(im, back_color); + + range = lvlhi - lvllo; + + /* draw scale to correspond with the values */ + for (level = lvlhi; level >= lvllo; level -= step) { + /* select dash RGB color according to the level */ + if (((redlo1 <= level) && (level <=redhi1)) || + ((redlo2 <= level) && (level <=redhi2))) { + col1 = warn_zone_maj_color; + col2 = warn_zone_min_color; + } else if ((grnlo <= level) && (level <= grnhi)) { + col1 = ok_zone_maj_color; + col2 = ok_zone_min_color; + } else { + col1 = neutral_zone_maj_color; + col2 = neutral_zone_min_color; + } + + /* calculate integer value for y */ + y = scale_height * (lvlhi - level) / range; + + /* draw major, semimajor or minor dash accordingly */ + if (level % step10 == 0) { + gdImageLine(im, 0, y, width, y, col1); + } else { + if (level % step5 == 0) + gdImageLine(im, 5, y, width - 5, y, col2); + else + gdImageLine(im, 10, y, width - 10, y, col2); + } + } + + /* put the values on the scale */ + for (level = lvlhi; level >= lvllo; level -= step) { + if (level % step10 == 0) { + y = scale_height * (lvlhi - level) / range; + snprintf(lbltxt, sizeof(lbltxt), "%d", level); + gdImageString(im, gdFontMediumBold, width - strlen(lbltxt)*gdFontMediumBold->w, y, + (unsigned char *) lbltxt, scale_num_color); + } + } +} + +/* draws the bar style indicator */ +static void drawbar( + int lvllo, int lvlhi, /* min and max numbers on the scale */ + int step, int step5, int step10, /* steps for minor, submajor and major dashes */ + int redlo1, int redhi1, /* first red zone start and end */ + int redlo2, int redhi2, /* second red zone start and end */ + int grnlo, int grnhi, /* green zone start and end */ + double value, /* UPS variable value to draw */ + const char *format /* printf style format to be used when rendering summary text */ +) +{ + gdImagePtr im; + int bar_color, summary_color; + char text[SMALLBUF]; + int bar_y; + int width, height, scale_height; + + /* get the dimension parameters */ + width = get_imgarg("width"); + height = get_imgarg("height"); + scale_height = get_imgarg("scale_height"); + + /* create the image */ + im = gdImageCreate(width, height); + + /* draw the scale */ + drawscale(im, lvllo, lvlhi, step, step5, step10, redlo1, redhi1, + redlo2, redhi2, grnlo, grnhi); + + /* allocate colors for the bar and summary text */ + bar_color = color_alloc(im, get_imgarg("bar_col")); + summary_color = color_alloc(im, get_imgarg("summary_col")); + + /* rescale UPS value to fit in the scale */ + bar_y = (1 - (value - lvllo) / (lvlhi - lvllo)) * scale_height; + + /* sanity checks: */ + + /* 1: if value is above maximum, then bar_y goes negative */ + if (bar_y < 0) + bar_y = 0; + + /* 2: if value is below minimum, bar_y goes off the scale */ + if (bar_y > scale_height) + bar_y = scale_height; + + /* draw it */ + gdImageFilledRectangle(im, 25, bar_y, width - 25, scale_height, + bar_color); + + /* stick the text version of the value at the bottom center */ + snprintf(text, sizeof(text), format, value); + gdImageString(im, gdFontMediumBold, + (width - strlen(text)*gdFontMediumBold->w)/2, + height - gdFontMediumBold->h, + (unsigned char *) text, summary_color); + + drawimage(im); + + /* NOTREACHED */ +} + +/* draws the error image */ +static void noimage(const char *fmt, ...) +{ + gdImagePtr im; + int back_color, summary_color; + int width, height; + char msg[SMALLBUF]; + va_list ap; + + va_start(ap, fmt); + vsnprintf(msg, sizeof(msg), fmt, ap); + va_end(ap); + + width = get_imgarg("width"); + height = get_imgarg("height"); + + im = gdImageCreate(width, height); + back_color = color_alloc(im, get_imgarg("back_col")); + summary_color = color_alloc(im, get_imgarg("summary_col")); + + gdImageFilledRectangle(im, 0, 0, width, height, back_color); + gdImageColorTransparent(im, back_color); + + if (width > height) + gdImageString(im, gdFontMediumBold, + (width - strlen(msg)*gdFontMediumBold->w)/2, + (height - gdFontMediumBold->h)/2, + (unsigned char *) msg, summary_color); + else + gdImageStringUp(im, gdFontMediumBold, + (width - gdFontMediumBold->h)/2, + (height + strlen(msg)*gdFontMediumBold->w)/2, + (unsigned char *) msg, summary_color); + + drawimage(im); + + /* NOTREACHED */ +} + +/* draws bar indicator when minimum, nominal or maximum values for the given + UPS variable can be determined. + deviation < 0 means that values below nom should be grey instead of + green */ +static void drawgeneralbar(double var, int min, int nom, int max, + int deviation, const char *format) +{ + int hi, lo, step1, step5, step10, graybelownom=0; + + if(deviation < 0) { + deviation=-deviation; + graybelownom=1; + } + + if ((nom == -1) && ((min == -1) || (max == -1))) + noimage("Can't determine range"); + + /* if min, max and nom are mixed up, arrange them appropriately */ + if (nom != -1) { + if (min == -1) + min = nom - 3*deviation; + + if (max == -1) + max = nom + 3*deviation; + } else { + /* if nominal value isn't available, assume, it's the + average between min and max */ + nom = (min + max) / 2; + } + + /* draw scale in the background */ + if ((max - min) <= 50) { + /* the scale is sparse enough to draw finer scale */ + step1 = 1; + step5 = 5; + step10 = 10; + } else if((max - min) <= 100) { + step1 = 2; + step5 = 10; + step10 = 20; + } else { + step1 = 5; + step5 = 20; + step10 = 40; + } + + /* round min and max points to get high and low numbers for graph */ + lo = ((min - deviation) / step10) * step10; + hi = ((max + deviation + step10/2) / step10) * step10; + + if(!graybelownom) { + drawbar(lo, hi, step1, step5, step10, max, hi, lo, min, + nom - deviation, nom + deviation, var, format); + } + else { + drawbar(lo, hi, step1, step5, step10, 0, min, max, hi, + nom, max, var, format); + } + + /* NOTREACHED */ +} + +/* draws input and output voltage bar style indicators */ +static void draw_utility(double var, int min, int nom, int max, + int deviation, const char *format) +{ + /* hack: deal with hardware that doesn't have known transfer points */ + if (min == -1) { + if(var < 200) { + min = 90; + } + else if(var < 300) { + min = 200; + } + else { + min = 340; + } + } + + /* somewhere between 220 and 230 V, to keep everybody satisfied */ + if (nom == -1) { + if(var < 200) { + nom = 110; + } + else if(var < 300) { + nom = 225; + } + else { + nom = 400; + } + } + + /* symmetrical around nom */ + if (max == -1) + max = nom+(nom-min); + + /* Acceptable range of voltage is 85%-110% of nominal voltage + * in EU at least. Be conservative and say +-10% */ + deviation = nom*0.1; + + drawgeneralbar(var, min, nom, max, deviation, format); + + /* NOTREACHED */ +} + +/* draws battery.percent bar style indicator */ +static void draw_battpct(double var, int min, int nom, int max, + int deviation, const char *format) +{ + if (min < 0) { + min = 50; + } + + drawbar(0, 100, 2, 10, 20, 0, min, -1, -1, 80, 100, var, format); +} + +/* draws battery.voltage bar style indicator */ +static void draw_battvolt(double var, int min, int nom, int max, + int deviation, const char *format) +{ + if(nom == -1) { + /* Use a fixed set of reasonable nominal voltages, seems to + * be the only way to get reasonable behaviour during + * discharge */ + + if(var < 9) + nom = 6; + else if(var < 18) + nom = 12; + else if(var < 30) + nom = 24; + else if(var < 60) + nom = 48; + else if(var < 120) + nom = 96; + else if(var < 230) + nom = 192; + else + nom = 384; + + } + + if(min == -1) { + min = nom/2*1.6+1; /* Assume a 2V cell is dead at 1.6V */ + } + + if(max == -1) { + max = nom/2*2.3+1; /* Assume 2.3V float charge voltage */ + } + + if (nom < min || nom > max) + nom = -1; + + + deviation = -(nom*0.05); /* 5% deviation from nominal voltage */ + if(deviation==0) { + deviation = -1; + } + + drawgeneralbar(var, min, nom, max, deviation, format); +} + +/* draws ups.load bar style indicator */ +static void draw_upsload(double var, int min, int nom, int max, + int deviation, const char *format) +{ + drawbar(0, 125, 5, 5, 25, 100, 125, -1, -1, 0, 50, var, format); +} + +/* draws temperature bar style indicator */ +static void draw_temperature(double var, int min, int nom, int max, + int deviation, const char *format) +{ + int hi = get_imgarg("tempmax"); + int lo = get_imgarg("tempmin"); + + drawbar(lo, hi, 1, 5, 10, lo, min, max, hi, -1, -1, var, format); +} + +/* draws humidity bar style indicator */ +static void draw_humidity(double var, int min, int nom, int max, + int deviation, const char *format) +{ + drawbar(0, 100, 2, 10, 20, 0, min, max, 100, -1, -1, var, format); +} + +static int get_var(const char *var, char *buf, size_t buflen) +{ + int ret; + unsigned int numq, numa; + const char *query[4]; + char **answer; + + query[0] = "VAR"; + query[1] = upsname; + query[2] = var; + + numq = 3; + + ret = upscli_get(&ups, numq, query, &numa, &answer); + + if (ret < 0) + return 0; + + if (numa < numq) + return 0; + + snprintf(buf, buflen, "%s", answer[3]); + return 1; +} + +int main(int argc, char **argv) +{ + char str[SMALLBUF]; + int i, min, nom, max; + double var = 0; + + extractcgiargs(); + + /* no 'host=' or 'display=' given */ + if ((!monhost) || (!cmd)) + noimage("No host or display"); + + if (!checkhost(monhost, NULL)) + noimage("Access denied"); + + upsname = hostname = NULL; + + if (upscli_splitname(monhost, &upsname, &hostname, &port) != 0) { + noimage("Invalid UPS definition (upsname[@hostname[:port]])\n"); + exit(EXIT_FAILURE); + } + + if (upscli_connect(&ups, hostname, port, 0) < 0) { + noimage("Can't connect to server:\n%s\n", + upscli_strerror(&ups)); + exit(EXIT_FAILURE); + } + + for (i = 0; imgvar[i].name; i++) + if (!strcmp(cmd, imgvar[i].name)) { + + /* sanity check whether we have draw function + registered with this variable */ + if (!imgvar[i].drawfunc) { + noimage("Draw function N/A"); + exit(EXIT_FAILURE); + } + + /* get the variable value */ + if (get_var(imgvar[i].name, str, sizeof(str)) == 1) { + var = strtod(str, NULL); + } else { + /* no value, no fun */ + snprintf(str, sizeof(str), "%s N/A", + imgvar[i].name); + noimage(str); + exit(EXIT_FAILURE); + } + + /* when getting minimum, nominal and maximum values, + we first look if the marginal value is supported + by the UPS driver, if not, we look it up in the + imgarg table under the SAME name */ + + /* get the minimum value */ + if (imgvar[i].minimum) { + if (get_var(imgvar[i].minimum, str, + sizeof(str)) == 1) { + min = atoi(str); + } else { + min = get_imgarg(imgvar[i].minimum); + } + + } else { + min = -1; + } + + /* get the nominal value */ + if (imgvar[i].nominal) { + if (get_var(imgvar[i].nominal, str, + sizeof(str)) == 1) { + nom = atoi(str); + } else { + nom = get_imgarg(imgvar[i].nominal); + } + + } else { + nom = -1; + } + + /* get the maximum value */ + if (imgvar[i].maximum) { + if (get_var(imgvar[i].maximum, str, + sizeof(str)) == 1) { + max = atoi(str); + } else { + max = get_imgarg(imgvar[i].maximum); + } + + } else { + max = -1; + } + + imgvar[i].drawfunc(var, min, nom, max, + imgvar[i].deviation, imgvar[i].format); + exit(EXIT_SUCCESS); + } + + noimage("Unknown display"); + exit(EXIT_FAILURE); +} + +struct imgvar_t imgvar[] = { + { "input.voltage", "input.transfer.low", "input.voltage.nominal", + "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "input.L1-N.voltage", "input.transfer.low", "input.voltage.nominal", + "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "input.L2-N.voltage", "input.transfer.low", "input.voltage.nominal", + "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "input.L3-N.voltage", "input.transfer.low", "input.voltage.nominal", + "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "input.L1-L2.voltage", "input.transfer.low", "input.voltage.nominal", + "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "input.L2-L3.voltage", "input.transfer.low", "input.voltage.nominal", + "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "input.L3-L1.voltage", "input.transfer.low", "input.voltage.nominal", + "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "battery.charge", "battery.charge.low", NULL, NULL, 0, + "%.1f %%", draw_battpct }, + + { "battery.voltage", "battery.voltage.low", "battery.voltage.nominal", + "battery.voltage.high", 0, + "%.1f VDC", draw_battvolt }, + + /* We use 'high' ASCII for the degrees symbol, since the gdImageString() + * function doesn't understand UTF-8 or HTML escape sequences. :-( */ + { "ups.temperature", "ups.temperature.low", NULL, + "ups.temperature.high", 0, + "%.1f \260C", draw_temperature }, + + /* Same here. */ + { "ambient.temperature", "ambient.temperature.low", NULL, + "ambient.temperature.high", 0, + "%.1f \260C", draw_temperature }, + + { "ambient.humidity", "ambient.humidity.low", NULL, + "ambient.humidity.high", 0, + "%.1f %%", draw_humidity }, + + { "input.frequency", NULL, "input.frequency.nominal", NULL, 2, + "%.1f Hz", drawgeneralbar }, + + { "ups.load", NULL, NULL, NULL, 0, + "%.1f %%", draw_upsload }, + + { "output.L1.power.percent", NULL, NULL, NULL, 0, + "%.1f %%", draw_upsload }, + + { "output.L2.power.percent", NULL, NULL, NULL, 0, + "%.1f %%", draw_upsload }, + + { "output.L3.power.percent", NULL, NULL, NULL, 0, + "%.1f %%", draw_upsload }, + + { "output.L1.realpower.percent", NULL, NULL, NULL, 0, + "%.1f %%", draw_upsload }, + + { "output.L2.realpower.percent", NULL, NULL, NULL, 0, + "%.1f %%", draw_upsload }, + + { "output.L3.realpower.percent", NULL, NULL, NULL, 0, + "%.1f %%", draw_upsload }, + + { "output.voltage", "input.transfer.low", "output.voltage.nominal", + "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "output.L1-N.voltage", "input.transfer.low", + "output.voltage.nominal", "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "output.L2-N.voltage", "input.transfer.low", + "output.voltage.nominal", "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "output.L3-N.voltage", "input.transfer.low", + "output.voltage.nominal", "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "output.L1-L2.voltage", "input.transfer.low", + "output.voltage.nominal", "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "output.L2-L3.voltage", "input.transfer.low", + "output.voltage.nominal", "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "output.L3-L1.voltage", "input.transfer.low", + "output.voltage.nominal", "input.transfer.high", 0, + "%.1f VAC", draw_utility }, + + { "output.frequency", NULL, "output.frequency.nominal", NULL, 2, + "%.1f Hz", drawgeneralbar }, + + { NULL, NULL, NULL, NULL, 0, + NULL, NULL } +}; diff --git a/clients/upsimagearg.h b/clients/upsimagearg.h new file mode 100644 index 0000000..4ecc85a --- /dev/null +++ b/clients/upsimagearg.h @@ -0,0 +1,60 @@ +/* upsimagearg.h - arguments passed between upsstats and upsimage + + Copyright (C) 2002 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct { + char *name; + int val; /* hex digits, ala HTML */ + int min; /* minimum reasonable value */ + int max; /* maximum reasonable value */ +} imgarg[] = +{ + { "width", 100, 50, 200 }, + { "height", 350, 100, 500 }, + { "scale_height", 300, 100, 500 }, + { "back_col", 0x000000, 0x000000, 0xffffff }, + { "scale_num_col", 0xffff00, 0x000000, 0xffffff }, + { "summary_col", 0xffff00, 0x000000, 0xffffff }, + { "ok_zone_maj_col", 0x00ff00, 0x000000, 0xffffff }, + { "ok_zone_min_col", 0x007800, 0x000000, 0xffffff }, + { "neutral_zone_maj_col", 0xffffff, 0x000000, 0xffffff }, + { "neutral_zone_min_col", 0x646464, 0x000000, 0xffffff }, + { "warn_zone_maj_col", 0xff0000, 0x000000, 0xffffff }, + { "warn_zone_min_col", 0x960000, 0x000000, 0xffffff }, + { "bar_col", 0x00ff00, 0x000000, 0xffffff }, + { "tempmin", 0, -100, 150 }, + { "tempmax", 40, -100, 150 }, + { "nom_in_freq", 50, 0, 100 }, + { "nom_out_freq", 50, 0, 100 }, + { NULL, 0, 0, 0 } +}; + +struct imgvar_t { + char *name; /* name of the UPS variable */ + char *minimum; /* name of minimum value UPS variable + or variable in imgarg table */ + char *nominal; /* as above, only for nominal value */ + char *maximum; /* as above, only for maximum value */ + int deviation; /* variable deviation - width of green zone */ + char *format; /* format string to generate summary text */ + + /* pointer to drawing function */ + void (*drawfunc)(double, int, int, int, int, const char*); +}; + +extern struct imgvar_t imgvar[]; diff --git a/clients/upslog.c b/clients/upslog.c new file mode 100644 index 0000000..49084b6 --- /dev/null +++ b/clients/upslog.c @@ -0,0 +1,532 @@ +/* upslog - log ups values to a file for later collection and analysis + + Copyright (C) 1998 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* Basic theory of operation: + * + * First we go through and parse as much of the status format string as + * possible. We used to do this parsing run every time, but that's a + * waste of CPU since it can't change during the program's run. + * + * This version does the parsing pass once, and creates a linked list of + * pointers to the functions that do the work and the arg they get. + * + * That means the main loop just has to run the linked list and call + * anything it finds in there. Everything happens from there, and we + * don't have to pointlessly reparse the string every time around. + */ + +#include "common.h" +#include "upsclient.h" + +#include "config.h" +#include "timehead.h" +#include "upslog.h" + + static int port, reopen_flag = 0, exit_flag = 0; + static char *upsname, *hostname; + static UPSCONN_t ups; + + static FILE *logfile; + static const char *logfn, *monhost; + static sigset_t nut_upslog_sigmask; + static char logbuffer[LARGEBUF], *logformat; + + static struct flist_t *fhead = NULL; + +#define DEFAULT_LOGFORMAT "%TIME @Y@m@d @H@M@S% %VAR battery.charge% " \ + "%VAR input.voltage% %VAR ups.load% [%VAR ups.status%] " \ + "%VAR ups.temperature% %VAR input.frequency%" + +static void reopen_log(void) +{ + if (logfile == stdout) { + upslogx(LOG_INFO, "logging to stdout"); + return; + } + + fclose(logfile); + logfile = fopen(logfn, "a"); + if (logfile == NULL) + fatal_with_errno(EXIT_FAILURE, "could not reopen logfile %s", logfn); +} + +static void set_reopen_flag(int sig) +{ + reopen_flag = sig; +} + +static void set_exit_flag(int sig) +{ + exit_flag = sig; +} + +/* handlers: reload on HUP, exit on INT/QUIT/TERM */ +static void setup_signals(void) +{ + struct sigaction sa; + + sigemptyset(&nut_upslog_sigmask); + sigaddset(&nut_upslog_sigmask, SIGHUP); + sa.sa_mask = nut_upslog_sigmask; + sa.sa_handler = set_reopen_flag; + sa.sa_flags = 0; + if (sigaction(SIGHUP, &sa, NULL) < 0) + fatal_with_errno(EXIT_FAILURE, "Can't install SIGHUP handler"); + + sa.sa_handler = set_exit_flag; + if (sigaction(SIGINT, &sa, NULL) < 0) + fatal_with_errno(EXIT_FAILURE, "Can't install SIGINT handler"); + if (sigaction(SIGQUIT, &sa, NULL) < 0) + fatal_with_errno(EXIT_FAILURE, "Can't install SIGQUIT handler"); + if (sigaction(SIGTERM, &sa, NULL) < 0) + fatal_with_errno(EXIT_FAILURE, "Can't install SIGTERM handler"); +} + +static void help(const char *prog) +{ + printf("UPS status logger.\n"); + + printf("\nusage: %s [OPTIONS]\n", prog); + printf("\n"); + + printf(" -f - Log format. See below for details.\n"); + printf(" - Use -f \"\" so your shell doesn't break it up.\n"); + printf(" -i - Time between updates, in seconds\n"); + printf(" -l - Log file name, or - for stdout\n"); + printf(" -p - Base name for PID file (defaults to \"upslog\")\n"); + printf(" -s - Monitor UPS - @[:]\n"); + printf(" - Example: -s myups@server\n"); + printf(" -u - Switch to if started as root\n"); + + printf("\n"); + printf("Some valid format string escapes:\n"); + printf("\t%%%% insert a single %%\n"); + printf("\t%%TIME format%% insert the time with strftime formatting\n"); + printf("\t%%HOST%% insert the local hostname\n"); + printf("\t%%UPSHOST%% insert the host of the ups being monitored\n"); + printf("\t%%PID%% insert the pid of upslog\n"); + printf("\t%%VAR varname%% insert the value of ups variable varname\n\n"); + printf("format string defaults to:\n"); + printf("%s\n", DEFAULT_LOGFORMAT); + + printf("\n"); + printf("See the upslog(8) man page for more information.\n"); + + exit(EXIT_SUCCESS); +} + +/* print current host name */ +static void do_host(const char *arg) +{ + int ret; + char hn[LARGEBUF]; + + ret = gethostname(hn, sizeof(hn)); + + if (ret != 0) { + upslog_with_errno(LOG_ERR, "gethostname failed"); + return; + } + + snprintfcat(logbuffer, sizeof(logbuffer), "%s", hn); +} + +static void do_upshost(const char *arg) +{ + snprintfcat(logbuffer, sizeof(logbuffer), "%s", monhost); +} + +static void do_pid(const char *arg) +{ + snprintfcat(logbuffer, sizeof(logbuffer), "%ld", (long)getpid()); +} + +static void do_time(const char *arg) +{ + unsigned int i; + char timebuf[SMALLBUF], *format; + time_t tod; + + format = xstrdup(arg); + + /* @s are used on the command line since % is taken */ + for (i = 0; i < strlen(format); i++) + if (format[i] == '@') + format[i] = '%'; + + time(&tod); + strftime(timebuf, sizeof(timebuf), format, localtime(&tod)); + + snprintfcat(logbuffer, sizeof(logbuffer), "%s", timebuf); + + free(format); +} + +static void getvar(const char *var) +{ + int ret; + unsigned int numq, numa; + const char *query[4]; + char **answer; + + query[0] = "VAR"; + query[1] = upsname; + query[2] = var; + numq = 3; + + ret = upscli_get(&ups, numq, query, &numa, &answer); + + if ((ret < 0) || (numa < numq)) { + snprintfcat(logbuffer, sizeof(logbuffer), "NA"); + return; + } + + snprintfcat(logbuffer, sizeof(logbuffer), "%s", answer[3]); +} + +static void do_var(const char *arg) +{ + if ((!arg) || (strlen(arg) < 1)) { + snprintfcat(logbuffer, sizeof(logbuffer), "INVALID"); + return; + } + + /* old variable names are no longer supported */ + if (!strchr(arg, '.')) { + snprintfcat(logbuffer, sizeof(logbuffer), "INVALID"); + return; + } + + /* a UPS name is now required */ + if (!upsname) { + snprintfcat(logbuffer, sizeof(logbuffer), "INVALID"); + return; + } + + getvar(arg); +} + +static void do_etime(const char *arg) +{ + time_t tod; + + time(&tod); + snprintfcat(logbuffer, sizeof(logbuffer), "%ld", (unsigned long) tod); +} + +static void print_literal(const char *arg) +{ + snprintfcat(logbuffer, sizeof(logbuffer), "%s", arg); +} + +/* register another parsing function to be called later */ +static void add_call(void (*fptr)(const char *arg), const char *arg) +{ + struct flist_t *tmp, *last; + + tmp = last = fhead; + + while (tmp) { + last = tmp; + tmp = tmp->next; + } + + tmp = xmalloc(sizeof(struct flist_t)); + + tmp->fptr = fptr; + + if (arg) + tmp->arg = xstrdup(arg); + else + tmp->arg = NULL; + + tmp->next = NULL; + + if (last) + last->next = tmp; + else + fhead = tmp; +} + +/* turn the format string into a list of function calls with args */ +static void compile_format(void) +{ + unsigned int i; + int j, found, ofs; + char *cmd, *arg, *ptr; + + for (i = 0; i < strlen(logformat); i++) { + + /* if not a % sequence, append character and start over */ + if (logformat[i] != '%') { + char buf[4]; + + /* we have to stuff it into a string first */ + snprintf(buf, sizeof(buf), "%c", logformat[i]); + add_call(print_literal, buf); + + continue; + } + + /* if a %%, append % and start over */ + if (logformat[i+1] == '%') { + add_call(print_literal, "%"); + + /* make sure we don't parse the second % next time */ + i++; + continue; + } + + /* it must start with a % now - %[ ]%*/ + + cmd = xstrdup(&logformat[i+1]); + ptr = strchr(cmd, '%'); + + /* no trailing % = broken */ + if (!ptr) { + add_call(print_literal, "INVALID"); + free(cmd); + continue; + } + + *ptr = '\0'; + + /* remember length (plus first %) so we can skip over it */ + ofs = strlen(cmd) + 1; + + /* jump out to argument (if any) */ + arg = strchr(cmd, ' '); + if (arg) + *arg++ = '\0'; + + found = 0; + + /* see if we know how to handle this command */ + + for (j = 0; logcmds[j].name != NULL; j++) { + if (strncasecmp(cmd, logcmds[j].name, + strlen(logcmds[j].name)) == 0) { + + add_call(logcmds[j].func, arg); + found = 1; + break; + } + } + + free(cmd); + + if (!found) + add_call(print_literal, "INVALID"); + + /* now do the skip ahead saved from before */ + i += ofs; + + } /* for (i = 0; i < strlen(logformat); i++) */ +} + +/* go through the list of functions and call them in order */ +static void run_flist(void) +{ + struct flist_t *tmp; + + tmp = fhead; + + memset(logbuffer, 0, sizeof(logbuffer)); + + while (tmp) { + tmp->fptr(tmp->arg); + + tmp = tmp->next; + } + + fprintf(logfile, "%s\n", logbuffer); + fflush(logfile); +} + + /* -s + * -l + * -i + * -f + * -u + */ + +int main(int argc, char **argv) +{ + int interval = 30, i; + char *prog = NULL; + time_t now, nextpoll = 0; + const char *user = NULL; + struct passwd *new_uid = NULL; + const char *pidfilebase = "upslog"; + + logformat = DEFAULT_LOGFORMAT; + user = RUN_AS_USER; + + printf("Network UPS Tools upslog %s\n", UPS_VERSION); + + prog = argv[0]; + + while ((i = getopt(argc, argv, "+hs:l:i:f:u:Vp:")) != -1) { + switch(i) { + case 'h': + help(prog); + break; + + case 's': + monhost = optarg; + break; + + case 'l': + logfn = optarg; + break; + + case 'i': + interval = atoi(optarg); + break; + + case 'f': + logformat = optarg; + break; + + case 'u': + user = optarg; + break; + + case 'V': + exit(EXIT_SUCCESS); + + case 'p': + pidfilebase = optarg; + break; + } + } + + argc -= optind; + argv += optind; + + /* not enough args for the old way? */ + if ((argc == 1) || (argc == 2)) + help(prog); + + /* see if it's being called in the old style - 3 or 4 args */ + + /* [] */ + + if (argc >= 3) { + monhost = argv[0]; + logfn = argv[1]; + interval = atoi(argv[2]); + } + + if (argc >= 4) { + /* read out the remaining argv entries to the format string */ + + logformat = xmalloc(LARGEBUF); + memset(logformat, '\0', LARGEBUF); + + for (i = 3; i < argc; i++) + snprintfcat(logformat, LARGEBUF, "%s ", argv[i]); + } + + if (!monhost) + fatalx(EXIT_FAILURE, "No UPS defined for monitoring - use -s "); + + if (!logfn) + fatalx(EXIT_FAILURE, "No filename defined for logging - use -l "); + + /* shouldn't happen */ + if (!logformat) + fatalx(EXIT_FAILURE, "No format defined - but this should be impossible"); + + printf("logging status of %s to %s (%is intervals)\n", + monhost, logfn, interval); + + if (upscli_splitname(monhost, &upsname, &hostname, &port) != 0) { + fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]\n"); + } + + if (upscli_connect(&ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0) + fprintf(stderr, "Warning: initial connect failed: %s\n", + upscli_strerror(&ups)); + + if (strcmp(logfn, "-") == 0) + logfile = stdout; + else + logfile = fopen(logfn, "a"); + + if (logfile == NULL) + fatal_with_errno(EXIT_FAILURE, "could not open logfile %s", logfn); + + /* now drop root if we have it */ + new_uid = get_user_pwent(user); + + openlog("upslog", LOG_PID, LOG_FACILITY); + + if (logfile != stdout) + background(); + + setup_signals(); + + writepid(pidfilebase); + + become_user(new_uid); + + compile_format(); + + while (exit_flag == 0) { + time(&now); + + if (nextpoll > now) { + /* there is still time left, so sleep it off */ + sleep(difftime(nextpoll, now)); + nextpoll += interval; + } else { + /* we spent more time in polling than the interval allows */ + nextpoll = now + interval; + } + + if (reopen_flag) { + upslogx(LOG_INFO, "Signal %d: reopening log file", + reopen_flag); + reopen_log(); + reopen_flag = 0; + } + + /* reconnect if necessary */ + if (upscli_fd(&ups) < 0) { + upscli_connect(&ups, hostname, port, 0); + } + + run_flist(); + + /* don't keep connection open if we don't intend to use it shortly */ + if (interval > 30) { + upscli_disconnect(&ups); + } + } + + upslogx(LOG_INFO, "Signal %d: exiting", exit_flag); + + if (logfile != stdout) + fclose(logfile); + + upscli_disconnect(&ups); + + exit(EXIT_SUCCESS); +} diff --git a/clients/upslog.h b/clients/upslog.h new file mode 100644 index 0000000..506cd15 --- /dev/null +++ b/clients/upslog.h @@ -0,0 +1,29 @@ +/* upslog.h - table of functions for handling various logging functions */ + +/* function list */ +struct flist_t { + void (*fptr)(const char *arg); + const char *arg; + struct flist_t *next; +}; + +static void do_host(const char *arg); +static void do_upshost(const char *arg); +static void do_pid(const char *arg); +static void do_time(const char *arg); +static void do_var(const char *arg); +static void do_etime(const char *arg); + +struct { + const char *name; + void (*func)(const char *arg); +} logcmds[] = +{ + { "HOST", do_host }, + { "UPSHOST", do_upshost }, + { "PID", do_pid }, + { "TIME", do_time }, + { "VAR", do_var }, + { "ETIME", do_etime }, + { NULL, (void(*)())(NULL) } +}; diff --git a/clients/upsmon.c b/clients/upsmon.c new file mode 100644 index 0000000..d5566a8 --- /dev/null +++ b/clients/upsmon.c @@ -0,0 +1,2046 @@ +/* upsmon - monitor power status over the 'net (talks to upsd via TCP) + + Copyright (C) 1998 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "common.h" + +#include +#include +#include + +#include "upsclient.h" +#include "upsmon.h" +#include "parseconf.h" +#include "timehead.h" + +#ifdef HAVE_STDARG_H +#include +#endif + +static char *shutdowncmd = NULL, *notifycmd = NULL; +static char *powerdownflag = NULL, *configfile = NULL; + +static int minsupplies = 1, sleepval = 5, deadtime = 15; + + /* default polling interval = 5 sec */ +static int pollfreq = 5, pollfreqalert = 5; + + /* slave hosts are given 15 sec by default to logout from upsd */ +static int hostsync = 15; + + /* sum of all power values from config file */ +static int totalpv = 0; + + /* default replace battery warning interval (seconds) */ +static int rbwarntime = 43200; + + /* default "all communications down" warning interval (seconds) */ +static int nocommwarntime = 300; + + /* default interval between the shutdown warning and the shutdown */ +static int finaldelay = 5; + + /* set by SIGHUP handler, cleared after reload finishes */ +static int reload_flag = 0; + + /* set after SIGINT, SIGQUIT, or SIGTERM */ +static int exit_flag = 0; + + /* userid for unprivileged process when using fork mode */ +static char *run_as_user = NULL; + + /* SSL details - where to find certs, whether to use them */ +static char *certpath = NULL; +static int certverify = 0; /* don't verify by default */ +static int forcessl = 0; /* don't require ssl by default */ + +static int userfsd = 0, use_pipe = 1, pipefd[2]; + +static utype_t *firstups = NULL; + +#ifdef HAVE_IPV6 +static int opt_af = AF_UNSPEC; +#endif + + /* signal handling things */ +static struct sigaction sa; +static sigset_t nut_upsmon_sigmask; + +#ifdef SHUT_RDWR +#define shutdown_how SHUT_RDWR +#else +#define shutdown_how 2 +#endif + +static void setflag(int *val, int flag) +{ + *val = (*val |= flag); +} + +static void clearflag(int *val, int flag) +{ + *val = (*val ^= (*val & flag)); +} + +static int flag_isset(int num, int flag) +{ + return ((num & flag) == flag); +} + +static void wall(const char *text) +{ + FILE *wf; + + wf = popen("wall", "w"); + + if (!wf) { + upslog_with_errno(LOG_NOTICE, "Can't invoke wall"); + return; + } + + fprintf(wf, "%s\n", text); + pclose(wf); +} + +static void notify(const char *notice, int flags, const char *ntype, + const char *upsname) +{ + char exec[LARGEBUF]; + int ret; + + if (flag_isset(flags, NOTIFY_IGNORE)) + return; + + if (flag_isset(flags, NOTIFY_SYSLOG)) + upslogx(LOG_NOTICE, "%s", notice); + + /* fork here so upsmon doesn't get wedged if the notifier is slow */ + ret = fork(); + + if (ret < 0) { + upslog_with_errno(LOG_ERR, "Can't fork to notify"); + return; + } + + if (ret != 0) /* parent */ + return; + + /* child continues and does all the work */ + + if (flag_isset(flags, NOTIFY_WALL)) + wall(notice); + + if (flag_isset(flags, NOTIFY_EXEC)) { + if (notifycmd != NULL) { + snprintf(exec, sizeof(exec), "%s \"%s\"", notifycmd, notice); + + if (upsname) + setenv("UPSNAME", upsname, 1); + else + setenv("UPSNAME", "", 1); + + setenv("NOTIFYTYPE", ntype, 1); + if (system(exec) == -1) { + upslog_with_errno(LOG_ERR, "%s", __func__); + } + } + } + + exit(EXIT_SUCCESS); +} + +static void do_notify(const utype_t *ups, int ntype) +{ + int i; + char msg[SMALLBUF], *upsname = NULL; + + /* grab this for later */ + if (ups) + upsname = ups->sys; + + for (i = 0; notifylist[i].name != NULL; i++) { + if (notifylist[i].type == ntype) { + upsdebugx(2, "%s: ntype 0x%04x (%s)", __func__, ntype, + notifylist[i].name); + snprintf(msg, sizeof(msg), notifylist[i].msg ? notifylist[i].msg : notifylist[i].stockmsg, + ups ? ups->sys : ""); + notify(msg, notifylist[i].flags, notifylist[i].name, + upsname); + return; + } + } + + /* not found ?! */ +} + +/* check for master permissions on the server for this ups */ +static int checkmaster(utype_t *ups) +{ + char buf[SMALLBUF]; + + /* don't bother if we're not configured as a master for this ups */ + if (!flag_isset(ups->status, ST_MASTER)) + return 1; + + /* this shouldn't happen (LOGIN checks it earlier) */ + if ((ups->upsname == NULL) || (strlen(ups->upsname) == 0)) { + upslogx(LOG_ERR, "Set master on UPS [%s] failed: empty upsname", + ups->sys); + return 0; + } + + snprintf(buf, sizeof(buf), "MASTER %s\n", ups->upsname); + + if (upscli_sendline(&ups->conn, buf, strlen(buf)) < 0) { + upslogx(LOG_ALERT, "Can't set master mode on UPS [%s] - %s", + ups->sys, upscli_strerror(&ups->conn)); + return 0; + } + + if (upscli_readline(&ups->conn, buf, sizeof(buf)) == 0) { + if (!strncmp(buf, "OK", 2)) + return 1; + + /* not ERR, but not caught by readline either? */ + + upslogx(LOG_ALERT, "Master privileges unavailable on UPS [%s]", + ups->sys); + upslogx(LOG_ALERT, "Response: [%s]", buf); + } + else { /* something caught by readraw's parsing call */ + upslogx(LOG_ALERT, "Master privileges unavailable on UPS [%s]", + ups->sys); + upslogx(LOG_ALERT, "Reason: %s", upscli_strerror(&ups->conn)); + } + + return 0; +} + +/* authenticate to upsd, plus do LOGIN and MASTER if applicable */ +static int do_upsd_auth(utype_t *ups) +{ + char buf[SMALLBUF]; + + if (!ups->un) { + upslogx(LOG_ERR, "UPS [%s]: no username defined!", ups->sys); + return 0; + } + + snprintf(buf, sizeof(buf), "USERNAME %s\n", ups->un); + if (upscli_sendline(&ups->conn, buf, strlen(buf)) < 0) { + upslogx(LOG_ERR, "Can't set username on [%s]: %s", + ups->sys, upscli_strerror(&ups->conn)); + return 0; + } + + if (upscli_readline(&ups->conn, buf, sizeof(buf)) < 0) { + upslogx(LOG_ERR, "Set username on [%s] failed: %s", + ups->sys, upscli_strerror(&ups->conn)); + return 0; + } + + /* authenticate first */ + snprintf(buf, sizeof(buf), "PASSWORD %s\n", ups->pw); + + if (upscli_sendline(&ups->conn, buf, strlen(buf)) < 0) { + upslogx(LOG_ERR, "Can't set password on [%s]: %s", + ups->sys, upscli_strerror(&ups->conn)); + return 0; + } + + if (upscli_readline(&ups->conn, buf, sizeof(buf)) < 0) { + upslogx(LOG_ERR, "Set password on [%s] failed: %s", + ups->sys, upscli_strerror(&ups->conn)); + return 0; + } + + /* catch insanity from the server - not ERR and not OK either */ + if (strncmp(buf, "OK", 2) != 0) { + upslogx(LOG_ERR, "Set password on [%s] failed - got [%s]", + ups->sys, buf); + return 0; + } + + /* we require a upsname now */ + if ((ups->upsname == NULL) || (strlen(ups->upsname) == 0)) { + upslogx(LOG_ERR, "Login to UPS [%s] failed: empty upsname", + ups->sys); + return 0; + } + + /* password is set, let's login */ + snprintf(buf, sizeof(buf), "LOGIN %s\n", ups->upsname); + + if (upscli_sendline(&ups->conn, buf, strlen(buf)) < 0) { + upslogx(LOG_ERR, "Login to UPS [%s] failed: %s", + ups->sys, upscli_strerror(&ups->conn)); + return 0; + } + + if (upscli_readline(&ups->conn, buf, sizeof(buf)) < 0) { + upslogx(LOG_ERR, "Can't login to UPS [%s]: %s", + ups->sys, upscli_strerror(&ups->conn)); + return 0; + } + + /* catch insanity from the server - not ERR and not OK either */ + if (strncmp(buf, "OK", 2) != 0) { + upslogx(LOG_ERR, "Login on UPS [%s] failed - got [%s]", + ups->sys, buf); + return 0; + } + + /* finally - everything is OK */ + upsdebugx(1, "Logged into UPS %s", ups->sys); + setflag(&ups->status, ST_LOGIN); + + /* now see if we also need to test master permissions */ + return checkmaster(ups); +} + +/* set flags and make announcements when a UPS has been checked successfully */ +static void ups_is_alive(utype_t *ups) +{ + time_t now; + + time(&now); + ups->lastpoll = now; + + if (ups->commstate == 1) /* already known */ + return; + + /* only notify for 0->1 transitions (to ignore the first connect) */ + if (ups->commstate == 0) + do_notify(ups, NOTIFY_COMMOK); + + ups->commstate = 1; +} + +/* handle all the notifications for a missing UPS in one place */ +static void ups_is_gone(utype_t *ups) +{ + time_t now; + + /* first time: clear the flag and throw the first notifier */ + if (ups->commstate != 0) { + ups->commstate = 0; + + /* COMMBAD is the initial loss of communications */ + do_notify(ups, NOTIFY_COMMBAD); + return; + } + + time(&now); + + /* first only act if we're seconds past the last poll */ + if ((now - ups->lastpoll) < nocommwarntime) + return; + + /* now only complain if we haven't lately */ + if ((now - ups->lastncwarn) > nocommwarntime) { + + /* NOCOMM indicates a persistent condition */ + do_notify(ups, NOTIFY_NOCOMM); + ups->lastncwarn = now; + } +} + +static void ups_on_batt(utype_t *ups) +{ + if (flag_isset(ups->status, ST_ONBATT)) { /* no change */ + upsdebugx(4, "%s: %s (no change)", __func__, ups->sys); + return; + } + + sleepval = pollfreqalert; /* bump up polling frequency */ + + ups->linestate = 0; + + upsdebugx(3, "%s: %s (first time)", __func__, ups->sys); + + /* must have changed from OL to OB, so notify */ + + do_notify(ups, NOTIFY_ONBATT); + setflag(&ups->status, ST_ONBATT); + clearflag(&ups->status, ST_ONLINE); +} + +static void ups_on_line(utype_t *ups) +{ + if (flag_isset(ups->status, ST_ONLINE)) { /* no change */ + upsdebugx(4, "%s: %s (no change)", __func__, ups->sys); + return; + } + + sleepval = pollfreq; + + upsdebugx(3, "%s: %s (first time)", __func__, ups->sys); + + /* ignore the first OL at startup, otherwise send the notifier */ + if (ups->linestate != -1) + do_notify(ups, NOTIFY_ONLINE); + + ups->linestate = 1; + + setflag(&ups->status, ST_ONLINE); + clearflag(&ups->status, ST_ONBATT); +} + +/* create the flag file if necessary */ +static void set_pdflag(void) +{ + FILE *pdf; + + if (!powerdownflag) + return; + + pdf = fopen(powerdownflag, "w"); + if (!pdf) { + upslogx(LOG_ERR, "Failed to create power down flag!"); + return; + } + + fprintf(pdf, "%s", SDMAGIC); + fclose(pdf); +} + +/* the actual shutdown procedure */ +static void doshutdown(void) +{ + int ret; + + /* this should probably go away at some point */ + upslogx(LOG_CRIT, "Executing automatic power-fail shutdown"); + wall("Executing automatic power-fail shutdown\n"); + + do_notify(NULL, NOTIFY_SHUTDOWN); + + sleep(finaldelay); + + /* in the pipe model, we let the parent do this for us */ + if (use_pipe) { + char ch; + + ch = 1; + ret = write(pipefd[1], &ch, 1); + } else { + /* one process model = we do all the work here */ + + if (geteuid() != 0) + upslogx(LOG_WARNING, "Not root, shutdown may fail"); + + set_pdflag(); + + ret = system(shutdowncmd); + + if (ret != 0) + upslogx(LOG_ERR, "Unable to call shutdown command: %s", + shutdowncmd); + } + + exit(EXIT_SUCCESS); +} + +/* set forced shutdown flag so other upsmons know what's going on here */ +static void setfsd(utype_t *ups) +{ + char buf[SMALLBUF]; + int ret; + + /* this shouldn't happen */ + if (!ups->upsname) { + upslogx(LOG_ERR, "setfsd: programming error: no UPS name set [%s]", + ups->sys); + return; + } + + upsdebugx(2, "Setting FSD on UPS %s", ups->sys); + + snprintf(buf, sizeof(buf), "FSD %s\n", ups->upsname); + + ret = upscli_sendline(&ups->conn, buf, strlen(buf)); + + if (ret < 0) { + upslogx(LOG_ERR, "FSD set on UPS %s failed: %s", ups->sys, + upscli_strerror(&ups->conn)); + return; + } + + ret = upscli_readline(&ups->conn, buf, sizeof(buf)); + + if (ret < 0) { + upslogx(LOG_ERR, "FSD set on UPS %s failed: %s", ups->sys, + upscli_strerror(&ups->conn)); + return; + } + + if (!strncmp(buf, "OK", 2)) + return; + + /* protocol error: upsd said something other than "OK" */ + upslogx(LOG_ERR, "FSD set on UPS %s failed: %s", ups->sys, buf); +} + +static void set_alarm(void) +{ + alarm(NET_TIMEOUT); +} + +static void clear_alarm(void) +{ + signal(SIGALRM, SIG_IGN); + alarm(0); +} + +static int get_var(utype_t *ups, const char *var, char *buf, size_t bufsize) +{ + int ret; + unsigned int numq, numa; + const char *query[4]; + char **answer; + + /* this shouldn't happen */ + if (!ups->upsname) { + upslogx(LOG_ERR, "get_var: programming error: no UPS name set [%s]", + ups->sys); + return -1; + } + + numq = 0; + + if (!strcmp(var, "numlogins")) { + query[0] = "NUMLOGINS"; + query[1] = ups->upsname; + numq = 2; + } + + if (!strcmp(var, "status")) { + query[0] = "VAR"; + query[1] = ups->upsname; + query[2] = "ups.status"; + numq = 3; + } + + if (numq == 0) { + upslogx(LOG_ERR, "get_var: programming error: var=%s", var); + return -1; + } + + upsdebugx(3, "%s: %s / %s", __func__, ups->sys, var); + + ret = upscli_get(&ups->conn, numq, query, &numa, &answer); + + if (ret < 0) { + + /* detect old upsd */ + if (upscli_upserror(&ups->conn) == UPSCLI_ERR_UNKCOMMAND) { + + upslogx(LOG_ERR, "UPS [%s]: Too old to monitor", + ups->sys); + return -1; + } + + /* some other error */ + return -1; + } + + if (numa < numq) { + upslogx(LOG_ERR, "%s: Error: insufficient data " + "(got %d args, need at least %d)", + var, numa, numq); + return -1; + } + + snprintf(buf, bufsize, "%s", answer[numq]); + return 0; +} + +static void slavesync(void) +{ + utype_t *ups; + char temp[SMALLBUF]; + time_t start, now; + int maxlogins, logins; + + time(&start); + + for (;;) { + maxlogins = 0; + + for (ups = firstups; ups != NULL; ups = ups->next) { + + /* only check login count on our master(s) */ + if (!flag_isset(ups->status, ST_MASTER)) + continue; + + set_alarm(); + + if (get_var(ups, "numlogins", temp, sizeof(temp)) >= 0) { + logins = strtol(temp, (char **)NULL, 10); + + if (logins > maxlogins) + maxlogins = logins; + } + + clear_alarm(); + } + + /* if no UPS has more than 1 login (us), then slaves are gone */ + if (maxlogins <= 1) + return; + + /* after HOSTSYNC seconds, assume slaves are stuck and bail */ + time(&now); + + if ((now - start) > hostsync) { + upslogx(LOG_INFO, "Host sync timer expired, forcing shutdown"); + return; + } + + usleep(250000); + } +} + +static void forceshutdown(void) +{ + utype_t *ups; + int isamaster = 0; + + upsdebugx(1, "Shutting down any UPSes in MASTER mode..."); + + /* set FSD on any "master" UPS entries (forced shutdown in progress) */ + for (ups = firstups; ups != NULL; ups = ups->next) + if (flag_isset(ups->status, ST_MASTER)) { + isamaster = 1; + setfsd(ups); + } + + /* if we're not a master on anything, we should shut down now */ + if (!isamaster) + doshutdown(); + + /* must be the master now */ + upsdebugx(1, "This system is a master... waiting for slave logout..."); + + /* wait up to HOSTSYNC seconds for slaves to logout */ + slavesync(); + + /* time expired or all the slaves are gone, so shutdown */ + doshutdown(); +} + +static int is_ups_critical(utype_t *ups) +{ + time_t now; + + /* FSD = the master is forcing a shutdown */ + if (flag_isset(ups->status, ST_FSD)) + return 1; + + /* not OB or not LB = not critical yet */ + if ((!flag_isset(ups->status, ST_ONBATT)) || + (!flag_isset(ups->status, ST_LOWBATT))) + return 0; + + /* must be OB+LB now */ + + /* if we're a master, declare it critical so we set FSD on it */ + if (flag_isset(ups->status, ST_MASTER)) + return 1; + + /* must be a slave now */ + + /* FSD isn't set, so the master hasn't seen it yet */ + + time(&now); + + /* give the master up to HOSTSYNC seconds before shutting down */ + if ((now - ups->lastnoncrit) > hostsync) { + upslogx(LOG_WARNING, "Giving up on the master for UPS [%s]", + ups->sys); + return 1; + } + + /* there's still time left */ + return 0; +} + +/* recalculate the online power value and see if things are still OK */ +static void recalc(void) +{ + utype_t *ups; + int val_ol = 0; + time_t now; + + time(&now); + ups = firstups; + while (ups != NULL) { + /* promote dead UPSes that were last known OB to OB+LB */ + if ((now - ups->lastpoll) > deadtime) + if (flag_isset(ups->status, ST_ONBATT)) { + upsdebugx(1, "Promoting dead UPS: %s", ups->sys); + setflag(&ups->status, ST_LOWBATT); + } + + /* note: we assume that a UPS that isn't critical must be OK * + * * + * this means a UPS we've never heard from is assumed OL * + * whether this is really the best thing to do is undecided */ + + /* crit = (FSD) || (OB & LB) > HOSTSYNC seconds */ + if (is_ups_critical(ups)) + upsdebugx(1, "Critical UPS: %s", ups->sys); + else + val_ol += ups->pv; + + ups = ups->next; + } + + /* upsdebugx(3, "Current power value: %d", val_ol); + upsdebugx(3, "Minimum power value: %d", minsupplies); */ + + if (val_ol < minsupplies) + forceshutdown(); +} + +static void ups_low_batt(utype_t *ups) +{ + if (flag_isset(ups->status, ST_LOWBATT)) { /* no change */ + upsdebugx(4, "%s: %s (no change)", __func__, ups->sys); + return; + } + + upsdebugx(3, "%s: %s (first time)", __func__, ups->sys); + + /* must have changed from !LB to LB, so notify */ + + do_notify(ups, NOTIFY_LOWBATT); + setflag(&ups->status, ST_LOWBATT); +} + +static void upsreplbatt(utype_t *ups) +{ + time_t now; + + time(&now); + + if ((now - ups->lastrbwarn) > rbwarntime) { + do_notify(ups, NOTIFY_REPLBATT); + ups->lastrbwarn = now; + } +} + +static void ups_fsd(utype_t *ups) +{ + if (flag_isset(ups->status, ST_FSD)) { /* no change */ + upsdebugx(4, "%s: %s (no change)", __func__, ups->sys); + return; + } + + upsdebugx(3, "%s: %s (first time)", __func__, ups->sys); + + /* must have changed from !FSD to FSD, so notify */ + + do_notify(ups, NOTIFY_FSD); + setflag(&ups->status, ST_FSD); +} + +/* cleanly close the connection to a given UPS */ +static void drop_connection(utype_t *ups) +{ + upsdebugx(2, "Dropping connection to UPS [%s]", ups->sys); + + ups->commstate = 0; + ups->linestate = 0; + clearflag(&ups->status, ST_LOGIN); + clearflag(&ups->status, ST_CONNECTED); + + upscli_disconnect(&ups->conn); +} + +/* change some UPS parameters during reloading */ +static void redefine_ups(utype_t *ups, int pv, const char *un, + const char *pw, const char *master) +{ + ups->retain = 1; + + if (ups->pv != pv) { + upslogx(LOG_INFO, "UPS [%s]: redefined power value to %d", + ups->sys, pv); + ups->pv = pv; + } + + totalpv += ups->pv; + + if (ups->un) { + if (strcmp(ups->un, un) != 0) { + upslogx(LOG_INFO, "UPS [%s]: redefined username", + ups->sys); + + free(ups->un); + + if (un) + ups->un = xstrdup(un); + else + ups->un = NULL; + + /* + * if not logged in force a reconnection since this + * may have been redefined to make a login work + */ + + if (!flag_isset(ups->status, ST_LOGIN)) { + upslogx(LOG_INFO, "UPS [%s]: retrying connection", + ups->sys); + + drop_connection(ups); + } + + } /* if (strcmp(ups->un, un) != 0) { */ + + } else { + + /* adding a username? (going to new style MONITOR line) */ + + if (un) { + upslogx(LOG_INFO, "UPS [%s]: defined username", + ups->sys); + + ups->un = xstrdup(un); + + /* possibly force reconnection - see above */ + + if (!flag_isset(ups->status, ST_LOGIN)) { + upslogx(LOG_INFO, "UPS [%s]: retrying connection", + ups->sys); + + drop_connection(ups); + } + + } /* if (un) */ + } + + /* paranoia */ + if (!ups->pw) + ups->pw = xstrdup(""); /* give it a bogus, but non-NULL one */ + + /* obviously don't put the new password in the syslog... */ + if (strcmp(ups->pw, pw) != 0) { + upslogx(LOG_INFO, "UPS [%s]: redefined password", ups->sys); + + free(ups->pw); + ups->pw = xstrdup(pw); + + /* possibly force reconnection - see above */ + + if (!flag_isset(ups->status, ST_LOGIN)) { + upslogx(LOG_INFO, "UPS [%s]: retrying connection", + ups->sys); + + drop_connection(ups); + } + } + + /* slave -> master */ + if ((!strcasecmp(master, "master")) && (!flag_isset(ups->status, ST_MASTER))) { + upslogx(LOG_INFO, "UPS [%s]: redefined as master", ups->sys); + setflag(&ups->status, ST_MASTER); + + /* reset connection to ensure master mode gets checked */ + drop_connection(ups); + return; + } + + /* master -> slave */ + if ((!strcasecmp(master, "slave")) && (flag_isset(ups->status, ST_MASTER))) { + upslogx(LOG_INFO, "UPS [%s]: redefined as slave", ups->sys); + clearflag(&ups->status, ST_MASTER); + return; + } +} + +static void addups(int reloading, const char *sys, const char *pvs, + const char *un, const char *pw, const char *master) +{ + int pv; + utype_t *tmp, *last; + + /* the username is now required - no more host-based auth */ + + if ((!sys) || (!pvs) || (!pw) || (!master) || (!un)) { + upslogx(LOG_WARNING, "Ignoring invalid MONITOR line in %s!", configfile); + upslogx(LOG_WARNING, "MONITOR configuration directives require five arguments."); + return; + } + + pv = strtol(pvs, (char **) NULL, 10); + + if (pv < 0) { + upslogx(LOG_WARNING, "UPS [%s]: ignoring invalid power value [%s]", + sys, pvs); + return; + } + + last = tmp = firstups; + + while (tmp) { + last = tmp; + + /* check for duplicates */ + if (!strcmp(tmp->sys, sys)) { + if (reloading) + redefine_ups(tmp, pv, un, pw, master); + else + upslogx(LOG_WARNING, "Warning: ignoring duplicate" + " UPS [%s]", sys); + return; + } + + tmp = tmp->next; + } + + tmp = xmalloc(sizeof(utype_t)); + tmp->sys = xstrdup(sys); + tmp->pv = pv; + + /* build this up so the user doesn't run with bad settings */ + totalpv += tmp->pv; + + if (un) + tmp->un = xstrdup(un); + else + tmp->un = NULL; + + tmp->pw = xstrdup(pw); + tmp->status = 0; + tmp->retain = 1; + + /* ignore initial COMMOK and ONLINE by default */ + tmp->commstate = -1; + tmp->linestate = -1; + + tmp->lastpoll = 0; + tmp->lastnoncrit = 0; + tmp->lastrbwarn = 0; + tmp->lastncwarn = 0; + + if (!strcasecmp(master, "master")) + setflag(&tmp->status, ST_MASTER); + + tmp->next = NULL; + + if (last) + last->next = tmp; + else + firstups = tmp; + + if (tmp->pv) + upslogx(LOG_INFO, "UPS: %s (%s) (power value %d)", tmp->sys, + flag_isset(tmp->status, ST_MASTER) ? "master" : "slave", + tmp->pv); + else + upslogx(LOG_INFO, "UPS: %s (monitoring only)", tmp->sys); + + tmp->upsname = tmp->hostname = NULL; + + if (upscli_splitname(tmp->sys, &tmp->upsname, &tmp->hostname, + &tmp->port) != 0) { + upslogx(LOG_ERR, "Error: unable to split UPS name [%s]", + tmp->sys); + } + + if (!tmp->upsname) + upslogx(LOG_WARNING, "Warning: UPS [%s]: no upsname set!", + tmp->sys); +} + +static void set_notifymsg(const char *name, const char *msg) +{ + int i; + + for (i = 0; notifylist[i].name != NULL; i++) { + if (!strcasecmp(notifylist[i].name, name)) { + free(notifylist[i].msg); + notifylist[i].msg = xstrdup(msg); + return; + } + } + + upslogx(LOG_WARNING, "'%s' is not a valid notify event name", name); +} + +static void set_notifyflag(const char *ntype, char *flags) +{ + int i, pos; + char *ptr, *tmp; + + /* find ntype */ + + pos = -1; + for (i = 0; notifylist[i].name != NULL; i++) { + if (!strcasecmp(notifylist[i].name, ntype)) { + pos = i; + break; + } + } + + if (pos == -1) { + upslogx(LOG_WARNING, "Warning: invalid notify type [%s]", ntype); + return; + } + + ptr = flags; + + /* zero existing flags */ + notifylist[pos].flags = 0; + + while (ptr) { + int newflag; + + tmp = strchr(ptr, '+'); + if (tmp) + *tmp++ = '\0'; + + newflag = 0; + + if (!strcmp(ptr, "SYSLOG")) + newflag = NOTIFY_SYSLOG; + if (!strcmp(ptr, "WALL")) + newflag = NOTIFY_WALL; + if (!strcmp(ptr, "EXEC")) + newflag = NOTIFY_EXEC; + if (!strcmp(ptr, "IGNORE")) + newflag = NOTIFY_IGNORE; + + if (newflag) + notifylist[pos].flags |= newflag; + else + upslogx(LOG_WARNING, "Invalid notify flag: [%s]", ptr); + + ptr = tmp; + } +} + +/* in split mode, the parent doesn't hear about reloads */ +static void checkmode(char *cfgentry, char *oldvalue, char *newvalue, + int reloading) +{ + /* nothing to do if in "all as root" mode */ + if (use_pipe == 0) + return; + + /* it's ok if we're not reloading yet */ + if (reloading == 0) + return; + + /* also nothing to do if it didn't change */ + if ((oldvalue) && (newvalue)) { + if (!strcmp(oldvalue, newvalue)) + return; + } + + /* otherwise, yell at them */ + upslogx(LOG_WARNING, "Warning: %s redefined in split-process mode!", + cfgentry); + upslogx(LOG_WARNING, "You must restart upsmon for this change to work"); +} + +/* returns 1 if used, 0 if not, so we can complain about bogus configs */ +static int parse_conf_arg(int numargs, char **arg) +{ + /* using up to arg[1] below */ + if (numargs < 2) + return 0; + + /* SHUTDOWNCMD */ + if (!strcmp(arg[0], "SHUTDOWNCMD")) { + checkmode(arg[0], shutdowncmd, arg[1], reload_flag); + + free(shutdowncmd); + shutdowncmd = xstrdup(arg[1]); + return 1; + } + + /* POWERDOWNFLAG */ + if (!strcmp(arg[0], "POWERDOWNFLAG")) { + checkmode(arg[0], powerdownflag, arg[1], reload_flag); + + free(powerdownflag); + powerdownflag = xstrdup(arg[1]); + + if (!reload_flag) + upslogx(LOG_INFO, "Using power down flag file %s", + arg[1]); + + return 1; + } + + /* NOTIFYCMD */ + if (!strcmp(arg[0], "NOTIFYCMD")) { + free(notifycmd); + notifycmd = xstrdup(arg[1]); + return 1; + } + + /* POLLFREQ */ + if (!strcmp(arg[0], "POLLFREQ")) { + pollfreq = atoi(arg[1]); + return 1; + } + + /* POLLFREQALERT */ + if (!strcmp(arg[0], "POLLFREQALERT")) { + pollfreqalert = atoi(arg[1]); + return 1; + } + + /* HOSTSYNC */ + if (!strcmp(arg[0], "HOSTSYNC")) { + hostsync = atoi(arg[1]); + return 1; + } + + /* DEADTIME */ + if (!strcmp(arg[0], "DEADTIME")) { + deadtime = atoi(arg[1]); + return 1; + } + + /* MINSUPPLIES */ + if (!strcmp(arg[0], "MINSUPPLIES")) { + minsupplies = atoi(arg[1]); + return 1; + } + + /* RBWARNTIME */ + if (!strcmp(arg[0], "RBWARNTIME")) { + rbwarntime = atoi(arg[1]); + return 1; + } + + /* NOCOMMWARNTIME */ + if (!strcmp(arg[0], "NOCOMMWARNTIME")) { + nocommwarntime = atoi(arg[1]); + return 1; + } + + /* FINALDELAY */ + if (!strcmp(arg[0], "FINALDELAY")) { + finaldelay = atoi(arg[1]); + return 1; + } + + /* RUN_AS_USER */ + if (!strcmp(arg[0], "RUN_AS_USER")) { + free(run_as_user); + run_as_user = xstrdup(arg[1]); + return 1; + } + + /* CERTPATH */ + if (!strcmp(arg[0], "CERTPATH")) { + free(certpath); + certpath = xstrdup(arg[1]); + return 1; + } + + /* CERTVERIFY (0|1) */ + if (!strcmp(arg[0], "CERTVERIFY")) { + certverify = atoi(arg[1]); + return 1; + } + + /* FORCESSL (0|1) */ + if (!strcmp(arg[0], "FORCESSL")) { + forcessl = atoi(arg[1]); + return 1; + } + + /* using up to arg[2] below */ + if (numargs < 3) + return 0; + + /* NOTIFYMSG */ + if (!strcmp(arg[0], "NOTIFYMSG")) { + set_notifymsg(arg[1], arg[2]); + return 1; + } + + /* NOTIFYFLAG */ + if (!strcmp(arg[0], "NOTIFYFLAG")) { + set_notifyflag(arg[1], arg[2]); + return 1; + } + + /* using up to arg[4] below */ + if (numargs < 5) + return 0; + + if (!strcmp(arg[0], "MONITOR")) { + + /* original style: no username (only 5 args) */ + if (numargs == 5) { + upslogx(LOG_ERR, "Unable to use old-style MONITOR line without a username"); + upslogx(LOG_ERR, "Convert it and add a username to upsd.users - see the documentation"); + + fatalx(EXIT_FAILURE, "Fatal error: unusable configuration"); + } + + /* ("master" | "slave") */ + addups(reload_flag, arg[1], arg[2], arg[3], arg[4], arg[5]); + return 1; + } + + /* didn't parse it at all */ + return 0; +} + +/* called for fatal errors in parseconf like malloc failures */ +static void upsmon_err(const char *errmsg) +{ + upslogx(LOG_ERR, "Fatal error in parseconf(%s): %s", configfile, errmsg); +} + +static void loadconfig(void) +{ + PCONF_CTX_t ctx; + + pconf_init(&ctx, upsmon_err); + + if (!pconf_file_begin(&ctx, configfile)) { + pconf_finish(&ctx); + + if (reload_flag == 1) { + upslog_with_errno(LOG_ERR, "Reload failed: %s", ctx.errmsg); + return; + } + + fatalx(EXIT_FAILURE, "%s", ctx.errmsg); + } + + while (pconf_file_next(&ctx)) { + if (pconf_parse_error(&ctx)) { + upslogx(LOG_ERR, "Parse error: %s:%d: %s", + configfile, ctx.linenum, ctx.errmsg); + continue; + } + + if (ctx.numargs < 1) + continue; + + if (!parse_conf_arg(ctx.numargs, ctx.arglist)) { + unsigned int i; + char errmsg[SMALLBUF]; + + snprintf(errmsg, sizeof(errmsg), + "%s line %d: invalid directive", + configfile, ctx.linenum); + + for (i = 0; i < ctx.numargs; i++) + snprintfcat(errmsg, sizeof(errmsg), " %s", + ctx.arglist[i]); + + upslogx(LOG_WARNING, "%s", errmsg); + } + } + + pconf_finish(&ctx); +} + +/* SIGPIPE handler */ +static void sigpipe(int sig) +{ + upsdebugx(1, "SIGPIPE: dazed and confused, but continuing..."); +} + +/* SIGQUIT, SIGTERM handler */ +static void set_exit_flag(int sig) +{ + exit_flag = sig; +} + +static void ups_free(utype_t *ups) +{ + free(ups->sys); + free(ups->upsname); + free(ups->hostname); + free(ups->un); + free(ups->pw); + free(ups); +} + +static void upsmon_cleanup(void) +{ + int i; + utype_t *utmp, *unext; + + /* close all fds */ + utmp = firstups; + + while (utmp) { + unext = utmp->next; + + drop_connection(utmp); + ups_free(utmp); + + utmp = unext; + } + + free(run_as_user); + free(shutdowncmd); + free(notifycmd); + free(powerdownflag); + + for (i = 0; notifylist[i].name != NULL; i++) { + free(notifylist[i].msg); + } +} + +static void user_fsd(int sig) +{ + upslogx(LOG_INFO, "Signal %d: User requested FSD", sig); + userfsd = 1; +} + +static void set_reload_flag(int sig) +{ + reload_flag = 1; +} + +/* handler for alarm when getupsvarfd times out */ +static void read_timeout(int sig) +{ + /* don't do anything here, just return */ +} + +/* install handlers for a few signals */ +static void setup_signals(void) +{ + sigemptyset(&nut_upsmon_sigmask); + sa.sa_mask = nut_upsmon_sigmask; + sa.sa_flags = 0; + + sa.sa_handler = sigpipe; + sigaction(SIGPIPE, &sa, NULL); + + sa.sa_handler = set_exit_flag; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + /* handle timeouts */ + + sa.sa_handler = read_timeout; + sigaction(SIGALRM, &sa, NULL); + + /* deal with the ones from userspace as well */ + + sa.sa_handler = user_fsd; + sigaction(SIGCMD_FSD, &sa, NULL); + + sa.sa_handler = set_reload_flag; + sigaction(SIGCMD_RELOAD, &sa, NULL); +} + +/* remember the last time the ups was not critical (OB + LB) */ +static void update_crittimer(utype_t *ups) +{ + /* if !OB or !LB, then it's not critical, so log the time */ + if ((!flag_isset(ups->status, ST_ONBATT)) || + (!flag_isset(ups->status, ST_LOWBATT))) { + + time(&ups->lastnoncrit); + return; + } + + /* fallthrough: let the timer age */ +} + +static int try_ssl(utype_t *ups) +{ + int ret; + + /* if not doing SSL, we're done */ + if (!upscli_ssl(&ups->conn)) + return 1; + + if (!certpath) { + if (certverify == 1) { + upslogx(LOG_ERR, "Configuration error: " + "CERTVERIFY is set, but CERTPATH isn't"); + upslogx(LOG_ERR, "UPS [%s]: Connection impossible, " + "dropping link", ups->sys); + + ups_is_gone(ups); + drop_connection(ups); + + return 0; /* failed */ + } + + /* certverify is 0, so just warn them and return */ + upslogx(LOG_WARNING, "Certificate verification is disabled"); + return 1; + } + + /* you REALLY should set CERTVERIFY to 1 if using SSL... */ + if (certverify == 0) + upslogx(LOG_WARNING, "Certificate verification is disabled"); + + ret = upscli_sslcert(&ups->conn, NULL, certpath, certverify); + + if (ret < 0) { + upslogx(LOG_ERR, "UPS [%s]: SSL certificate set failed: %s", + ups->sys, upscli_strerror(&ups->conn)); + + ups_is_gone(ups); + drop_connection(ups); + + return 0; + } + + return 1; +} + +/* handle connecting to upsd, plus get SSL going too if possible */ +static int try_connect(utype_t *ups) +{ + int flags = 0, ret; + + upsdebugx(1, "Trying to connect to UPS [%s]", ups->sys); + + clearflag(&ups->status, ST_CONNECTED); + + /* force it if configured that way, just try it otherwise */ + if (forcessl == 1) + flags |= UPSCLI_CONN_REQSSL; + else + flags |= UPSCLI_CONN_TRYSSL; + +#ifdef HAVE_IPV6 + if (opt_af == AF_INET) + flags |= UPSCLI_CONN_INET; + + if (opt_af == AF_INET6) + flags |= UPSCLI_CONN_INET6; +#endif + + ret = upscli_connect(&ups->conn, ups->hostname, ups->port, flags); + + if (ret < 0) { + upslogx(LOG_ERR, "UPS [%s]: connect failed: %s", + ups->sys, upscli_strerror(&ups->conn)); + + ups_is_gone(ups); + return 0; + } + + ret = try_ssl(ups); + + if (ret == 0) + return 0; /* something broke while trying SSL */ + + /* we're definitely connected now */ + setflag(&ups->status, ST_CONNECTED); + + /* now try to authenticate to upsd */ + + ret = do_upsd_auth(ups); + + if (ret == 1) + return 1; /* everything is happy */ + + /* something failed in the auth so we may not be completely logged in */ + + /* FUTURE: do something beyond the error msgs from do_upsd_auth? */ + + return 0; +} + +/* deal with the contents of STATUS or ups.status for this ups */ +static void parse_status(utype_t *ups, char *status) +{ + char *statword, *ptr; + + clear_alarm(); + + upsdebugx(2, "%s: [%s]", __func__, status); + + /* empty response is the same as a dead ups */ + if (!strcmp(status, "")) { + ups_is_gone(ups); + return; + } + + ups_is_alive(ups); + + /* clear these out early if they disappear */ + if (!strstr(status, "LB")) + clearflag(&ups->status, ST_LOWBATT); + if (!strstr(status, "FSD")) + clearflag(&ups->status, ST_FSD); + + statword = status; + + /* split up the status words and parse each one separately */ + while (statword != NULL) { + ptr = strchr(statword, ' '); + if (ptr) + *ptr++ = '\0'; + + upsdebugx(3, "parsing: [%s]", statword); + + if (!strcasecmp(statword, "OL")) + ups_on_line(ups); + if (!strcasecmp(statword, "OB")) + ups_on_batt(ups); + if (!strcasecmp(statword, "LB")) + ups_low_batt(ups); + if (!strcasecmp(statword, "RB")) + upsreplbatt(ups); + + /* do it last to override any possible OL */ + if (!strcasecmp(statword, "FSD")) + ups_fsd(ups); + + update_crittimer(ups); + + statword = ptr; + } +} + +/* see what the status of the UPS is and handle any changes */ +static void pollups(utype_t *ups) +{ + char status[SMALLBUF]; + + /* try a reconnect here */ + if (!flag_isset(ups->status, ST_CONNECTED)) + if (try_connect(ups) != 1) + return; + + if (upscli_ssl(&ups->conn) == 1) + upsdebugx(2, "%s: %s [SSL]", __func__, ups->sys); + else + upsdebugx(2, "%s: %s", __func__, ups->sys); + + set_alarm(); + + if (get_var(ups, "status", status, sizeof(status)) == 0) { + clear_alarm(); + parse_status(ups, status); + return; + } + + /* fallthrough: no communications */ + clear_alarm(); + + /* try to make some of these a little friendlier */ + + switch (upscli_upserror(&ups->conn)) { + + case UPSCLI_ERR_UNKNOWNUPS: + upslogx(LOG_ERR, "Poll UPS [%s] failed - [%s] " + "does not exist on server %s", + ups->sys, ups->upsname, ups->hostname); + + break; + default: + upslogx(LOG_ERR, "Poll UPS [%s] failed - %s", + ups->sys, upscli_strerror(&ups->conn)); + break; + } + + /* throw COMMBAD or NOCOMM as conditions may warrant */ + ups_is_gone(ups); + + /* if upsclient lost the connection, clean up things on our side */ + if (upscli_fd(&ups->conn) == -1) { + drop_connection(ups); + return; + } +} + +/* see if the powerdownflag file is there and proper */ +static int pdflag_status(void) +{ + FILE *pdf; + char buf[SMALLBUF]; + + if (!powerdownflag) + return 0; /* unusable */ + + pdf = fopen(powerdownflag, "r"); + + if (pdf == NULL) + return 0; /* not there */ + + /* if it exists, see if it has the right text in it */ + + if (fgets(buf, sizeof(buf), pdf) == NULL) { + upslog_with_errno(LOG_ERR, "'%s' exists, but we can't read from it", powerdownflag); + } + fclose(pdf); + + /* reasoning: say upsmon.conf is world-writable (!) and some nasty + * user puts something "important" as the power flag file. This + * keeps upsmon from utterly trashing it when starting up or powering + * down at the expense of not shutting down the UPS. + * + * solution: don't let mere mortals edit that configuration file. + */ + + if (!strncmp(buf, SDMAGIC, strlen(SDMAGIC))) + return 1; /* exists and looks good */ + + return -1; /* error: something else is in there */ +} + +/* only remove the flag file if it's actually from us */ +static void clear_pdflag(void) +{ + int ret; + + ret = pdflag_status(); + + if (ret == -1) { + upslogx(LOG_ERR, "POWERDOWNFLAG (%s) does not contain" + "the upsmon magic string - disabling!", powerdownflag); + powerdownflag = NULL; + return; + } + + /* it's from us, so we can remove it */ + if (ret == 1) + unlink(powerdownflag); +} + +/* exit with success only if it exists and is proper */ +static int check_pdflag(void) +{ + int ret; + + ret = pdflag_status(); + + if (ret == -1) { + upslogx(LOG_ERR, "POWERDOWNFLAG (%s) does not contain " + "the upsmon magic string", powerdownflag); + return EXIT_FAILURE; + } + + if (ret == 0) { + /* not there - this is not a shutdown event */ + upslogx(LOG_ERR, "Power down flag is not set"); + return EXIT_FAILURE; + } + + if (ret != 1) { + upslogx(LOG_ERR, "Programming error: pdflag_status returned %d", + ret); + return EXIT_FAILURE; + } + + /* only thing left - must be time for a shutdown */ + upslogx(LOG_INFO, "Power down flag is set"); + return EXIT_SUCCESS; +} + +static void help(const char *progname) +{ + printf("Monitors UPS servers and may initiate shutdown if necessary.\n\n"); + + printf("usage: %s [OPTIONS]\n\n", progname); + printf(" -c send command to running process\n"); + printf(" commands:\n"); + printf(" - fsd: shutdown all master UPSes (use with caution)\n"); + printf(" - reload: reread configuration\n"); + printf(" - stop: stop monitoring and exit\n"); + printf(" -D raise debugging level\n"); + printf(" -h display this help\n"); + printf(" -K checks POWERDOWNFLAG, sets exit code to 0 if set\n"); + printf(" -p always run privileged (disable privileged parent)\n"); + printf(" -u run child as user (ignored when using -p)\n"); +#ifdef HAVE_IPV6 + printf(" -4 IPv4 only\n"); + printf(" -6 IPv6 only\n"); +#endif + + exit(EXIT_SUCCESS); +} + +static void runparent(int fd) +{ + int ret; + char ch; + + /* handling signals is the child's job */ + signal(SIGHUP, SIG_IGN); + signal(SIGUSR1, SIG_IGN); + signal(SIGUSR2, SIG_IGN); + + ret = read(fd, &ch, 1); + + if (ret < 1) { + if (errno == ENOENT) + fatalx(EXIT_FAILURE, "upsmon parent: exiting (child exited)"); + + fatal_with_errno(EXIT_FAILURE, "upsmon parent: read"); + } + + if (ch != 1) + fatalx(EXIT_FAILURE, "upsmon parent: got bogus pipe command %c", ch); + + /* have to do this here - child is unprivileged */ + set_pdflag(); + + ret = system(shutdowncmd); + + if (ret != 0) + upslogx(LOG_ERR, "parent: Unable to call shutdown command: %s", + shutdowncmd); + + close(fd); + exit(EXIT_SUCCESS); +} + +/* fire up the split parent/child scheme */ +static void start_pipe(const char *user) +{ + int ret; + struct passwd *new_uid = NULL; + + /* default user = the --with-user value from configure */ + if (user) + new_uid = get_user_pwent(user); + else + new_uid = get_user_pwent(RUN_AS_USER); + + ret = pipe(pipefd); + + if (ret) + fatal_with_errno(EXIT_FAILURE, "pipe creation failed"); + + ret = fork(); + + if (ret < 0) + fatal_with_errno(EXIT_FAILURE, "fork failed"); + + /* start the privileged parent */ + if (ret != 0) { + close(pipefd[1]); + runparent(pipefd[0]); + + exit(EXIT_FAILURE); /* NOTREACHED */ + } + + close(pipefd[0]); + + /* write the pid file now, as we will soon lose root */ + writepid("upsmon"); + + become_user(new_uid); +} + +static void delete_ups(utype_t *target) +{ + utype_t *ptr, *last; + + if (!target) + return; + + ptr = last = firstups; + + while (ptr) { + if (ptr == target) { + upslogx(LOG_NOTICE, "No longer monitoring UPS [%s]", + target->sys); + + /* disconnect cleanly */ + drop_connection(ptr); + + /* about to delete the first ups? */ + if (ptr == last) + firstups = ptr->next; + else + last->next = ptr->next; + + /* release memory */ + + ups_free(ptr); + + return; + } + + last = ptr; + ptr = ptr->next; + } + + /* shouldn't happen */ + upslogx(LOG_ERR, "delete_ups: UPS not found"); +} + +/* see if we can open a file */ +static int check_file(const char *fn) +{ + FILE *f; + + f = fopen(fn, "r"); + + if (!f) { + upslog_with_errno(LOG_ERR, "Reload failed: can't open %s", fn); + return 0; /* failed */ + } + + fclose(f); + return 1; /* OK */ +} + +static void reload_conf(void) +{ + utype_t *tmp, *next; + + upslogx(LOG_INFO, "Reloading configuration"); + + /* sanity check */ + if (!check_file(configfile)) { + reload_flag = 0; + return; + } + + /* flip through ups list, clear retain value */ + tmp = firstups; + + while (tmp) { + tmp->retain = 0; + tmp = tmp->next; + } + + /* reset paranoia checker */ + totalpv = 0; + + /* reread upsmon.conf */ + loadconfig(); + + /* go through the utype_t struct again */ + tmp = firstups; + + while (tmp) { + next = tmp->next; + + /* !retain means it wasn't in the .conf this time around */ + if (tmp->retain == 0) + delete_ups(tmp); + + tmp = next; + } + + /* see if the user just blew off a foot */ + if (totalpv < minsupplies) { + upslogx(LOG_CRIT, "Fatal error: total power value (%d) less " + "than MINSUPPLIES (%d)", totalpv, minsupplies); + + fatalx(EXIT_FAILURE, "Impossible power configuation, unable to continue"); + } + + /* finally clear the flag */ + reload_flag = 0; +} + +/* make sure the parent is still alive */ +static void check_parent(void) +{ + int ret; + fd_set rfds; + struct timeval tv; + time_t now; + static time_t lastwarn = 0; + + FD_ZERO(&rfds); + FD_SET(pipefd[1], &rfds); + + tv.tv_sec = 0; + tv.tv_usec = 0; + + ret = select(pipefd[1] + 1, &rfds, NULL, NULL, &tv); + + if (ret == 0) + return; + + /* this should never happen, but we MUST KNOW if it ever does */ + + time(&now); + + /* complain every 2 minutes */ + if ((now - lastwarn) < 120) + return; + + lastwarn = now; + do_notify(NULL, NOTIFY_NOPARENT); + + /* also do this in case the notifier isn't being effective */ + upslogx(LOG_ALERT, "Parent died - shutdown impossible"); +} + +int main(int argc, char *argv[]) +{ + int i, cmd, checking_flag = 0; + + cmd = 0; + + printf("Network UPS Tools upsmon %s\n", UPS_VERSION); + + while ((i = getopt(argc, argv, "+Dhic:f:pu:VK46")) != -1) { + switch (i) { + case 'c': + if (!strncmp(optarg, "fsd", strlen(optarg))) + cmd = SIGCMD_FSD; + if (!strncmp(optarg, "stop", strlen(optarg))) + cmd = SIGCMD_STOP; + if (!strncmp(optarg, "reload", strlen(optarg))) + cmd = SIGCMD_RELOAD; + + /* bad command name given */ + if (cmd == 0) + help(argv[0]); + break; + case 'D': + nut_debug_level++; + break; + case 'f': + configfile = xstrdup(optarg); + break; + case 'h': + help(argv[0]); + break; + case 'K': + checking_flag = 1; + break; + case 'p': + use_pipe = 0; + break; + case 'u': + run_as_user = xstrdup(optarg); + break; + case 'V': + /* just show the banner */ + exit(EXIT_SUCCESS); +#ifdef HAVE_IPV6 + case '4': + opt_af = AF_INET; + break; + case '6': + opt_af = AF_INET6; + break; +#endif + default: + help(argv[0]); + break; + } + } + + if (cmd) { + sendsignal("upsmon", cmd); + exit(EXIT_SUCCESS); + } + + argc -= optind; + argv += optind; + + openlog("upsmon", LOG_PID, LOG_FACILITY); + + /* if no configuration file was specified on the command line, use default */ + if (!configfile) { + configfile = xmalloc(SMALLBUF); + snprintf(configfile, SMALLBUF, "%s/upsmon.conf", confpath()); + configfile = xrealloc(configfile, strlen(configfile) + 1); + } + + loadconfig(); + + if (checking_flag) + exit(check_pdflag()); + + if (shutdowncmd == NULL) + printf("Warning: no shutdown command defined!\n"); + + /* we may need to get rid of a flag from a previous shutdown */ + if (powerdownflag != NULL) + clear_pdflag(); + + if (totalpv < minsupplies) { + printf("\nFatal error: insufficient power configured!\n\n"); + + printf("Sum of power values........: %d\n", totalpv); + printf("Minimum value (MINSUPPLIES): %d\n", minsupplies); + + printf("\nEdit your upsmon.conf and change the values.\n"); + exit(EXIT_FAILURE); + } + + if (nut_debug_level < 1) { + background(); + } else { + upsdebugx(1, "debug level is '%d'", nut_debug_level); + } + + /* === root parent and unprivileged child split here === */ + + /* only do the pipe stuff if the user hasn't disabled it */ + if (use_pipe) + start_pipe(run_as_user); + else { + upslogx(LOG_INFO, "Warning: running as one big root process by request (upsmon -p)"); + writepid("upsmon"); + } + + /* prep our signal handlers */ + setup_signals(); + + /* reopen the log for the child process */ + closelog(); + openlog("upsmon", LOG_PID, LOG_FACILITY); + + while (exit_flag == 0) { + utype_t *ups; + + /* check flags from signal handlers */ + if (userfsd) + forceshutdown(); + + if (reload_flag) + reload_conf(); + + for (ups = firstups; ups != NULL; ups = ups->next) + pollups(ups); + + recalc(); + + /* make sure the parent hasn't died */ + if (use_pipe) + check_parent(); + + /* reap children that have exited */ + waitpid(-1, NULL, WNOHANG); + + sleep(sleepval); + } + + upslogx(LOG_INFO, "Signal %d: exiting", exit_flag); + upsmon_cleanup(); + + exit(EXIT_SUCCESS); +} diff --git a/clients/upsmon.h b/clients/upsmon.h new file mode 100644 index 0000000..92634bc --- /dev/null +++ b/clients/upsmon.h @@ -0,0 +1,114 @@ +/* upsmon.h - headers and other useful things for upsmon.h + + Copyright (C) 2000 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* flags for ups->status */ + +#define ST_ONLINE 0x001 /* UPS is on line (OL) */ +#define ST_ONBATT 0x002 /* UPS is on battery (OB) */ +#define ST_LOWBATT 0x004 /* UPS has a low battery (LB) */ +#define ST_FSD 0x008 /* master has set forced shutdown flag */ +#define ST_MASTER 0x010 /* we are the master on this UPS */ +/* was ST_ALIVE 0x020 */ +#define ST_LOGIN 0x040 /* we are logged into this UPS */ +/* was ST_FIRST 0x080 */ +#define ST_CONNECTED 0x100 /* upscli_connect returned OK */ + +/* required contents of flag file */ +#define SDMAGIC "upsmon-shutdown-file" + +/* UPS tracking structure */ + +typedef struct { + UPSCONN_t conn; /* upsclient state descriptor */ + + char *sys; /* raw system name from .conf */ + char *upsname; /* just upsname */ + char *hostname; /* just hostname */ + int port; /* just the port */ + + int pv; /* power value from conf */ + char *un; /* username (optional for now) */ + char *pw; /* password from conf */ + int status; /* status (see flags above) */ + int retain; /* tracks deletions at reload */ + + /* handle suppression of COMMOK and ONLINE at startup */ + int commstate; /* these start at -1, and only */ + int linestate; /* fire on a 0->1 transition */ + + time_t lastpoll; /* time of last successful poll */ + time_t lastnoncrit; /* time of last non-crit poll */ + time_t lastrbwarn; /* time of last REPLBATT warning*/ + time_t lastncwarn; /* time of last NOCOMM warning */ + void *next; +} utype_t; + +/* notify identifiers */ + +#define NOTIFY_ONLINE 0 /* UPS went on-line */ +#define NOTIFY_ONBATT 1 /* UPS went on battery */ +#define NOTIFY_LOWBATT 2 /* UPS went to low battery */ +#define NOTIFY_FSD 3 /* Master upsmon set FSD flag */ +#define NOTIFY_COMMOK 4 /* Communication established */ +#define NOTIFY_COMMBAD 5 /* Communication lost */ +#define NOTIFY_SHUTDOWN 6 /* System shutdown in progress */ +#define NOTIFY_REPLBATT 7 /* UPS battery needs to be replaced */ +#define NOTIFY_NOCOMM 8 /* UPS hasn't been contacted in awhile */ +#define NOTIFY_NOPARENT 9 /* privileged parent process died */ + +/* notify flag values */ + +#define NOTIFY_IGNORE 1 /* don't do anything */ +#define NOTIFY_SYSLOG 2 /* send the msg to the syslog */ +#define NOTIFY_WALL 4 /* send the msg to all users */ +#define NOTIFY_EXEC 8 /* send the msg to NOTIFYCMD script */ + +/* flags are set to NOTIFY_SYSLOG | NOTIFY_WALL at program init */ +/* the user can override with NOTIFYFLAGS in the upsmon.conf */ + +struct { + int type; + const char *name; + char *msg; /* NULL until overridden */ + const char *stockmsg; + int flags; +} notifylist[] = +{ + { NOTIFY_ONLINE, "ONLINE", NULL, "UPS %s on line power", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_ONBATT, "ONBATT", NULL, "UPS %s on battery", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_LOWBATT, "LOWBATT", NULL, "UPS %s battery is low", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_FSD, "FSD", NULL, "UPS %s: forced shutdown in progress", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_COMMOK, "COMMOK", NULL, "Communications with UPS %s established", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_COMMBAD, "COMMBAD", NULL, "Communications with UPS %s lost", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_SHUTDOWN, "SHUTDOWN", NULL, "Auto logout and shutdown proceeding", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_REPLBATT, "REPLBATT", NULL, "UPS %s battery needs to be replaced", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_NOCOMM, "NOCOMM", NULL, "UPS %s is unavailable", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_NOPARENT, "NOPARENT", NULL, "upsmon parent process died - shutdown impossible", NOTIFY_SYSLOG | NOTIFY_WALL }, + { 0, NULL, NULL, NULL, 0 } +}; + +/* values for signals passed between processes */ + +#define SIGCMD_FSD SIGUSR1 +#define SIGCMD_STOP SIGTERM +#define SIGCMD_RELOAD SIGHUP + +/* various constants */ + +#define NET_TIMEOUT 10 /* wait 10 seconds max for upsd to respond */ diff --git a/clients/upsrw.c b/clients/upsrw.c new file mode 100644 index 0000000..cdc16b9 --- /dev/null +++ b/clients/upsrw.c @@ -0,0 +1,508 @@ +/* upsrw - simple client for read/write variable access (formerly upsct2) + + Copyright (C) 1999 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common.h" + +#include +#include +#include +#include + +#include "upsclient.h" + +struct list_t { + char *name; + struct list_t *next; +}; + +static void usage(const char *prog) +{ + printf("Network UPS Tools upsrw %s\n\n", UPS_VERSION); + printf("usage: %s [-h]\n", prog); + printf(" %s [-s ] [-u ] [-p ] \n\n", prog); + printf("Demo program to set variables within UPS hardware.\n"); + printf("\n"); + printf(" -h display this help text\n"); + printf(" -s specify variable to be changed\n"); + printf(" use -s VAR=VALUE to avoid prompting for value\n"); + printf(" -u set username for command authentication\n"); + printf(" -p set password for command authentication\n"); + printf("\n"); + printf(" UPS identifier - [@[:]]\n"); + printf("\n"); + printf("Call without -s to show all possible read/write variables.\n"); + + exit(EXIT_SUCCESS); +} + +static void clean_exit(UPSCONN_t *ups, char *upsname, char *hostname, int code) +{ + free(upsname); + free(hostname); + + upscli_disconnect(ups); + + exit(code); +} + +static int do_set(UPSCONN_t *ups, const char *upsname, const char *varname, + const char *newval) +{ + char buf[SMALLBUF], enc[SMALLBUF]; + + snprintf(buf, sizeof(buf), "SET VAR %s %s \"%s\"\n", + upsname, varname, pconf_encode(newval, enc, sizeof(enc))); + + if (upscli_sendline(ups, buf, strlen(buf)) < 0) { + fprintf(stderr, "Can't set variable: %s\n", + upscli_strerror(ups)); + + return EXIT_FAILURE; + } + + if (upscli_readline(ups, buf, sizeof(buf)) < 0) { + fprintf(stderr, "Set variable failed: %s\n", + upscli_strerror(ups)); + + return EXIT_FAILURE; + } + + /* FUTURE: status cookies will tie in here */ + if (strncmp(buf, "OK", 2) != 0) { + printf("Unexpected response from upsd: %s\n", buf); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int do_setvar(UPSCONN_t *ups, const char *varname, char *uin, + const char *pass, char *upsname, char *hostname) +{ + char newval[SMALLBUF], temp[SMALLBUF], user[SMALLBUF], *ptr; + struct passwd *pw; + + if (uin) { + snprintf(user, sizeof(user), "%s", uin); + } else { + memset(user, '\0', sizeof(user)); + + pw = getpwuid(getuid()); + + if (pw) + printf("Username (%s): ", pw->pw_name); + else + printf("Username: "); + + if (fgets(user, sizeof(user), stdin) == NULL) { + upsdebug_with_errno(LOG_INFO, "%s", __func__); + } + + /* deal with that pesky newline */ + if (strlen(user) > 1) + user[strlen(user) - 1] = '\0'; + else { + if (!pw) + fatalx(EXIT_FAILURE, "No username available - even tried getpwuid"); + + snprintf(user, sizeof(user), "%s", pw->pw_name); + } + } + + /* leaks - use -p when running in valgrind */ + if (!pass) { + pass = GETPASS("Password: " ); + + if (!pass) { + fprintf(stderr, "getpass failed: %s\n", + strerror(errno)); + + return EXIT_FAILURE; + } + } + + /* Check if varname is in VAR=VALUE form */ + if ((ptr = strchr(varname, '=')) != NULL) { + *ptr++ = 0; + snprintf(newval, sizeof(newval), "%s", ptr); + } else { + printf("Enter new value for %s: ", varname); + fflush(stdout); + if (fgets(newval, sizeof(newval), stdin) == NULL) { + upsdebug_with_errno(LOG_INFO, "%s", __func__); + } + newval[strlen(newval) - 1] = '\0'; + } + + snprintf(temp, sizeof(temp), "USERNAME %s\n", user); + + if (upscli_sendline(ups, temp, strlen(temp)) < 0) { + fprintf(stderr, "Can't set username: %s\n", + upscli_strerror(ups)); + + return EXIT_FAILURE; + } + + if (upscli_readline(ups, temp, sizeof(temp)) < 0) { + + if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) { + fprintf(stderr, "Set username failed due to an " + "unknown command.\n"); + + fprintf(stderr, "You probably need to upgrade upsd.\n"); + + clean_exit(ups, upsname, hostname, EXIT_FAILURE); + } + + fprintf(stderr, "Set username failed: %s\n", + upscli_strerror(ups)); + + return EXIT_FAILURE; + } + + snprintf(temp, sizeof(temp), "PASSWORD %s\n", pass); + + if (upscli_sendline(ups, temp, strlen(temp)) < 0) { + fprintf(stderr, "Can't set password: %s\n", + upscli_strerror(ups)); + + return EXIT_FAILURE; + } + + if (upscli_readline(ups, temp, sizeof(temp)) < 0) { + fprintf(stderr, "Set password failed: %s\n", + upscli_strerror(ups)); + + return EXIT_FAILURE; + } + + /* no upsname means die */ + if (!upsname) { + fprintf(stderr, "Error: a UPS name must be specified (upsname[@hostname[:port]])\n"); + return EXIT_FAILURE; + } + + /* old variable names are no longer supported */ + if (!strchr(varname, '.')) { + fprintf(stderr, "Error: old variable names are not supported\n"); + return EXIT_FAILURE; + } + + return do_set(ups, upsname, varname, newval); +} + +static const char *get_data(const char *type, UPSCONN_t *ups, + const char *upsname, const char *varname) +{ + int ret; + unsigned int numq, numa; + char **answer; + const char *query[4]; + + query[0] = type; + query[1] = upsname; + query[2] = varname; + numq = 3; + + ret = upscli_get(ups, numq, query, &numa, &answer); + + if ((ret < 0) || (numa < numq)) + return NULL; + + /* */ + return answer[3]; +} + +static void do_string(UPSCONN_t *ups, const char *upsname, const char *varname) +{ + const char *val; + + val = get_data("VAR", ups, upsname, varname); + + if (!val) { + fprintf(stderr, "do_string: can't get current value of %s\n", + varname); + return; + } + + printf("Type: STRING\n"); + printf("Value: %s\n", val); +} + +static void do_enum(UPSCONN_t *ups, const char *upsname, const char *varname) +{ + int ret; + unsigned int numq, numa; + char **answer, *val; + const char *query[4], *tmp; + + /* get current value */ + tmp = get_data("VAR", ups, upsname, varname); + + if (!tmp) { + fprintf(stderr, "do_enum: can't get current value of %s\n", + varname); + return; + } + + /* tmp is a pointer into answer - have to save it somewhere else */ + val = xstrdup(tmp); + + query[0] = "ENUM"; + query[1] = upsname; + query[2] = varname; + numq = 3; + + ret = upscli_list_start(ups, numq, query); + + if (ret < 0) { + fprintf(stderr, "Error: %s\n", upscli_strerror(ups)); + return; + } + + ret = upscli_list_next(ups, numq, query, &numa, &answer); + + printf("Type: ENUM\n"); + + while (ret == 1) { + + /* ENUM */ + + if (numa < 4) { + fprintf(stderr, "Error: insufficient data " + "(got %d args, need at least 4)\n", numa); + + free(val); + return; + } + + printf("Option: \"%s\"", answer[3]); + + if (!strcmp(answer[3], val)) + printf(" SELECTED"); + + printf("\n"); + + ret = upscli_list_next(ups, numq, query, &numa, &answer); + } + + free(val); +} + +static void do_type(UPSCONN_t *ups, const char *upsname, const char *varname) +{ + int ret; + unsigned int i, numq, numa; + char **answer; + const char *query[4]; + + query[0] = "TYPE"; + query[1] = upsname; + query[2] = varname; + numq = 3; + + ret = upscli_get(ups, numq, query, &numa, &answer); + + if ((ret < 0) || (numa < numq)) { + printf("Unknown type\n"); + return; + } + + /* TYPE ... */ + for (i = 3; i < numa; i++) { + + if (!strcasecmp(answer[i], "ENUM")) { + do_enum(ups, upsname, varname); + return; + } + + if (!strncasecmp(answer[i], "STRING:", 7)) { + do_string(ups, upsname, varname); + return; + } + + /* ignore this one */ + if (!strcasecmp(answer[i], "RW")) + continue; + + printf("Type: %s (unrecognized)\n", answer[i]); + } + +} + +static void print_rw(UPSCONN_t *ups, const char *upsname, const char *varname) +{ + const char *tmp; + + printf("[%s]\n", varname); + + tmp = get_data("DESC", ups, upsname, varname); + + if (tmp) + printf("%s\n", tmp); + else + printf("Description unavailable\n"); + + do_type(ups, upsname, varname); + + printf("\n"); +} + +static int print_rwlist(UPSCONN_t *ups, const char *upsname) +{ + int ret; + unsigned int numq, numa; + const char *query[2]; + char **answer; + struct list_t *lhead, *llast, *ltmp, *lnext; + + /* the upsname is now required */ + if (!upsname) { + fprintf(stderr, "Error: a UPS name must be specified (upsname[@hostname[:port]])\n"); + return EXIT_FAILURE; + } + + llast = lhead = NULL; + + query[0] = "RW"; + query[1] = upsname; + numq = 2; + + ret = upscli_list_start(ups, numq, query); + + if (ret < 0) { + + /* old upsd --> fall back on old LISTRW technique */ + if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) { + fprintf(stderr, "Error: upsd is too old to support this query\n"); + return EXIT_FAILURE; + } + + fprintf(stderr, "Error: %s\n", upscli_strerror(ups)); + return EXIT_FAILURE; + } + + ret = upscli_list_next(ups, numq, query, &numa, &answer); + + while (ret == 1) { + + /* RW */ + if (numa < 4) { + fprintf(stderr, "Error: insufficient data " + "(got %d args, need at least 4)\n", numa); + return EXIT_FAILURE; + } + + /* sock this entry away for later */ + + ltmp = xmalloc(sizeof(struct list_t)); + ltmp->name = xstrdup(answer[2]); + ltmp->next = NULL; + + if (llast) + llast->next = ltmp; + else + lhead = ltmp; + + llast = ltmp; + + ret = upscli_list_next(ups, numq, query, &numa, &answer); + } + + /* use the list to get descriptions and types */ + + ltmp = lhead; + + while (ltmp) { + lnext = ltmp->next; + + print_rw(ups, upsname, ltmp->name); + + free(ltmp->name); + free(ltmp); + ltmp = lnext; + } + + return EXIT_SUCCESS; +} + +int main(int argc, char **argv) +{ + int i, port, ret; + char *upsname, *hostname, *setvar, *prog; + char *password = NULL, *username = NULL; + UPSCONN_t ups; + + setvar = username = NULL; + prog = argv[0]; + + while ((i = getopt(argc, argv, "+s:p:u:V")) != -1) { + switch (i) { + case 's': + setvar = optarg; + break; + case 'p': + password = optarg; + break; + case 'u': + username = optarg; + break; + case 'V': + printf("Network UPS Tools upsrw %s\n", UPS_VERSION); + exit(EXIT_SUCCESS); + default: + usage(prog); + break; + } + } + + argc -= optind; + argv += optind; + + if (argc < 1) + usage(prog); + + upsname = hostname = NULL; + + if (upscli_splitname(argv[0], &upsname, &hostname, &port) != 0) { + fprintf(stderr, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]\n"); + clean_exit(&ups, upsname, hostname, EXIT_FAILURE); + } + + if (upscli_connect(&ups, hostname, port, 0) < 0) { + fprintf(stderr, "Can't connect: %s\n", upscli_strerror(&ups)); + clean_exit(&ups, upsname, hostname, EXIT_FAILURE); + } + + /* setting a variable? */ + if (setvar) { + ret = do_setvar(&ups, setvar, username, password, upsname, + hostname); + + clean_exit(&ups, upsname, hostname, ret); + } + + /* if not, get the list of supported read/write variables */ + ret = print_rwlist(&ups, upsname); + + clean_exit(&ups, upsname, hostname, ret); + + /* NOTREACHED */ + exit(EXIT_FAILURE); +} diff --git a/clients/upssched-cmd b/clients/upssched-cmd new file mode 100755 index 0000000..63255df --- /dev/null +++ b/clients/upssched-cmd @@ -0,0 +1,21 @@ +#! /bin/sh +# +# This script should be called by upssched via the CMDSCRIPT directive. +# +# Here is a quick example to show how to handle a bunch of possible +# timer names with the help of the case structure. +# +# This script may be replaced with another program without harm. +# +# The first argument passed to your CMDSCRIPT is the name of the timer +# from your AT lines. + +case $1 in + upsgone) + logger -t upssched-cmd "The UPS has been gone for awhile" + ;; + *) + logger -t upssched-cmd "Unrecognized command: $1" + ;; +esac + diff --git a/clients/upssched.c b/clients/upssched.c new file mode 100644 index 0000000..e00ae17 --- /dev/null +++ b/clients/upssched.c @@ -0,0 +1,921 @@ +/* upssched.c - upsmon's scheduling helper for offset timers + + Copyright (C) 2000 Russell Kroll + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* design notes for the curious: + * + * 1. we get called with a upsname and notifytype from upsmon + * 2. the config file is searched for an AT condition that matches + * 3. the conditions on any matching lines are parsed + * + * starting a timer: the timer is added to the daemon's timer queue + * cancelling a timer: the timer is removed from that queue + * execute a command: the command is passed straight to the cmdscript + * + * if the daemon is not already running and is required (to start a timer) + * it will be started automatically + * + * when the time arrives, the command associated with a timer will be + * executed by the daemon (via the cmdscript) + * + * timers can be cancelled at any time before they trigger + * + * the daemon will shut down automatically when no more timers are active + * + */ + +#include "common.h" + +#include +#include +#include +#include +#include + +#include "upssched.h" +#include "timehead.h" + +typedef struct { + char *name; + time_t etime; + void *next; +} ttype_t; + + ttype_t *thead = NULL; + static struct conn_t *connhead = NULL; + char *cmdscript = NULL, *pipefn = NULL, *lockfn = NULL; + int verbose = 0; /* use for debugging */ + + + /* ups name and notify type (string) as received from upsmon */ + const char *upsname, *notify_type; + +#define PARENT_STARTED -2 +#define PARENT_UNNECESSARY -3 +#define MAX_TRIES 30 +#define EMPTY_WAIT 15 /* min passes with no timers to exit */ +#define US_LISTEN_BACKLOG 16 +#define US_SOCK_BUF_LEN 256 +#define US_MAX_READ 128 + +/* --- server functions --- */ + +static void exec_cmd(const char *cmd) +{ + int err; + char buf[LARGEBUF]; + + snprintf(buf, sizeof(buf), "%s %s", cmdscript, cmd); + + err = system(buf); + if (WIFEXITED(err)) { + if (WEXITSTATUS(err)) { + upslogx(LOG_INFO, "exec_cmd(%s) returned %d", buf, WEXITSTATUS(err)); + } + } else { + if (WIFSIGNALED(err)) { + upslogx(LOG_WARNING, "exec_cmd(%s) terminated with signal %d", buf, WTERMSIG(err)); + } else { + upslogx(LOG_ERR, "Execute command failure: %s", buf); + } + } + + return; +} + +static void removetimer(ttype_t *tfind) +{ + ttype_t *tmp, *last; + + last = NULL; + tmp = thead; + + while (tmp) { + if (tmp == tfind) { /* found it */ + if (last == NULL) /* deleting first */ + thead = tmp->next; + else + last->next = tmp->next; + + free(tmp->name); + free(tmp); + return; + } + + last = tmp; + tmp = tmp->next; + } + + /* this one should never happen */ + + upslogx(LOG_ERR, "removetimer: failed to locate target at %p", (void *)tfind); +} + +static void checktimers(void) +{ + ttype_t *tmp, *tmpnext; + time_t now; + static int emptyctr = 0; + + /* if the queue is empty we might be ready to exit */ + if (!thead) { + + emptyctr++; + + /* wait a little while in case someone wants us again */ + if (emptyctr < EMPTY_WAIT) + return; + + if (verbose) + upslogx(LOG_INFO, "Timer queue empty, exiting"); + +#ifdef UPSSCHED_RACE_TEST + upslogx(LOG_INFO, "triggering race: sleeping 15 sec before exit"); + sleep(15); +#endif + + unlink(pipefn); + exit(EXIT_SUCCESS); + } + + emptyctr = 0; + + /* flip through LL, look for activity */ + tmp = thead; + + time(&now); + while (tmp) { + tmpnext = tmp->next; + + if (now >= tmp->etime) { + if (verbose) + upslogx(LOG_INFO, "Event: %s ", tmp->name); + + exec_cmd(tmp->name); + + /* delete from queue */ + removetimer(tmp); + } + + tmp = tmpnext; + } +} + +static void start_timer(const char *name, const char *ofsstr) +{ + time_t now; + int ofs; + ttype_t *tmp, *last; + + /* get the time */ + time(&now); + + /* add an event for +