From 26fb71b5045cd198c1791fe927a6e6098007f555 Mon Sep 17 00:00:00 2001 From: "arnaud.quette@free.fr" Date: Fri, 26 Mar 2010 00:20:59 +0100 Subject: [PATCH] Imported Upstream version 2.4.3 --- AUTHORS | 177 + COPYING | 12 + ChangeLog | 1091 ++ INSTALL | 522 + MAINTAINERS | 66 + Makefile.am | 87 + Makefile.in | 839 + NEWS | 979 ++ README | 659 + UPGRADING | 373 + aclocal.m4 | 1155 ++ clients/Makefile.am | 53 + clients/Makefile.in | 912 ++ clients/cgilib.c | 202 + clients/cgilib.h | 31 + clients/status.h | 37 + clients/upsc.c | 229 + clients/upsclient.c | 1108 ++ clients/upsclient.h | 166 + clients/upscmd.c | 311 + clients/upsimage.c | 731 + clients/upsimagearg.h | 60 + clients/upslog.c | 532 + clients/upslog.h | 29 + clients/upsmon.c | 2046 +++ clients/upsmon.h | 114 + clients/upsrw.c | 508 + clients/upssched-cmd | 21 + clients/upssched.c | 921 ++ clients/upssched.h | 14 + clients/upsset.c | 1079 ++ clients/upsstats.c | 1067 ++ clients/upsstats.h | 24 + common/Makefile.am | 15 + common/Makefile.in | 555 + common/common.c | 540 + common/parseconf.c | 616 + common/state.c | 492 + common/upsconf.c | 107 + compile | 142 + conf/Makefile.am | 17 + conf/Makefile.in | 497 + conf/hosts.conf.sample | 29 + conf/nut.conf.sample | 28 + conf/ups.conf.sample | 104 + conf/upsd.conf.sample | 41 + conf/upsd.users.sample | 64 + conf/upsmon.conf.sample | 299 + conf/upssched.conf.sample.in | 113 + conf/upsset.conf.sample | 36 + conf/upsstats-single.html.sample | 294 + conf/upsstats.html.sample | 190 + config.guess | 1561 ++ config.sub | 1686 ++ configure | 18664 ++++++++++++++++++++++ configure.in | 812 + data/Makefile.am | 8 + data/Makefile.in | 666 + data/cmdvartab | 189 + data/driver.list | 725 + data/evolution500.dev | 53 + data/html/Makefile.am | 7 + data/html/Makefile.in | 488 + data/html/README | 97 + data/html/bottom.html | 8 + data/html/header.html.in | 39 + data/html/index.html | 14 + data/html/nut-banner.png | Bin 0 -> 2750 bytes depcomp | 630 + docs/FAQ | 822 + docs/Makefile.am | 13 + docs/Makefile.in | 423 + docs/README | 9 + docs/acpi.txt | 32 + docs/big-servers.txt | 68 + docs/cables/apc-rs500-serial.txt | 34 + docs/cables/apc.txt | 233 + docs/cables/ge-imv-victron.txt | 59 + docs/cables/imv.txt | 12 + docs/cables/mgeups.txt | 52 + docs/cables/powerware.txt | 26 + docs/cables/repotec.txt | 26 + docs/cables/sms.txt | 16 + docs/chroot.txt | 110 + docs/commands.txt | 62 + docs/config-files.txt | 64 + docs/configure.txt | 327 + docs/contact-closure.txt | 108 + docs/data-room.txt | 54 + docs/design.txt | 219 + docs/developers.txt | 374 + docs/hid-subdrivers.txt | 221 + docs/ideas.txt | 85 + docs/macros.txt | 66 + docs/megatec.txt | 69 + docs/new-drivers.txt | 620 + docs/new-names.txt | 574 + docs/nut-hal.txt | 118 + docs/osd-notify.txt | 86 + docs/pager.txt | 68 + docs/powersaving.txt | 135 + docs/protocol.txt | 518 + docs/shutdown.txt | 230 + docs/snmp.txt | 50 + docs/sock-protocol.txt | 225 + docs/ssl.txt | 251 + docs/upssched.txt | 190 + drivers/Makefile.am | 235 + drivers/Makefile.in | 1570 ++ drivers/apc-hid.c | 401 + drivers/apc-hid.h | 34 + drivers/apc-mib.c | 245 + drivers/apc-mib.h | 18 + drivers/apcsmart.c | 1313 ++ drivers/apcsmart.h | 285 + drivers/baytech-mib.c | 91 + drivers/baytech-mib.h | 9 + drivers/bcmxcp.c | 1665 ++ drivers/bcmxcp.h | 364 + drivers/bcmxcp_io.h | 22 + drivers/bcmxcp_ser.c | 322 + drivers/bcmxcp_usb.c | 495 + drivers/belkin-hid.c | 480 + drivers/belkin-hid.h | 33 + drivers/belkin.c | 446 + drivers/belkin.h | 53 + drivers/belkinunv.c | 1325 ++ drivers/bestfcom.c | 766 + drivers/bestfortress.c | 444 + drivers/bestuferrups.c | 497 + drivers/bestups.c | 437 + drivers/blazer.c | 749 + drivers/blazer.h | 49 + drivers/blazer_ser.c | 200 + drivers/blazer_usb.c | 558 + drivers/clone-outlet.c | 418 + drivers/clone.c | 557 + drivers/compaq-mib.c | 208 + drivers/compaq-mib.h | 9 + drivers/cps-hid.c | 210 + drivers/cps-hid.h | 30 + drivers/dstate-hal.c | 700 + drivers/dstate-hal.h | 92 + drivers/dstate.c | 845 + drivers/dstate.h | 77 + drivers/dummy-ups.c | 484 + drivers/dummy-ups.h | 224 + drivers/eaton-mib.c | 204 + drivers/eaton-mib.h | 10 + drivers/etapro.c | 368 + drivers/everups.c | 201 + drivers/explore-hid.c | 75 + drivers/explore-hid.h | 28 + drivers/gamatronic.c | 409 + drivers/gamatronic.h | 201 + drivers/genericups.c | 338 + drivers/genericups.h | 272 + drivers/hidparser.c | 618 + drivers/hidparser.h | 69 + drivers/hidtypes.h | 149 + drivers/ietf-mib.c | 258 + drivers/ietf-mib.h | 9 + drivers/isbmex.c | 353 + drivers/ivtscd.c | 259 + drivers/libhid.c | 949 ++ drivers/libhid.h | 148 + drivers/libshut.c | 981 ++ drivers/libshut.h | 87 + drivers/libusb.c | 492 + drivers/libusb.h | 66 + drivers/liebert-hid.c | 141 + drivers/liebert-hid.h | 30 + drivers/liebert.c | 191 + drivers/liebertgxt2.c | 292 + drivers/main-hal.c | 571 + drivers/main-hal.h | 51 + drivers/main.c | 636 + drivers/main.h | 83 + drivers/masterguard.c | 628 + drivers/megatec.c | 1036 ++ drivers/megatec.h | 42 + drivers/megatec_usb.c | 656 + drivers/metasys.c | 1053 ++ drivers/mge-hid.c | 1018 ++ drivers/mge-hid.h | 32 + drivers/mge-mib.c | 159 + drivers/mge-mib.h | 9 + drivers/mge-shut.c | 1455 ++ drivers/mge-shut.h | 523 + drivers/mge-utalk.c | 924 ++ drivers/mge-utalk.h | 235 + drivers/mge-xml.c | 1118 ++ drivers/mge-xml.h | 28 + drivers/microdowell.c | 982 ++ drivers/microdowell.h | 327 + drivers/netvision-mib.c | 120 + drivers/netvision-mib.h | 9 + drivers/netxml-ups.c | 686 + drivers/netxml-ups.h | 77 + drivers/oneac.c | 321 + drivers/oneac.h | 92 + drivers/optiups.c | 631 + drivers/powercom-hid.c | 306 + drivers/powercom-hid.h | 30 + drivers/powercom.c | 985 ++ drivers/powercom.h | 101 + drivers/powerman-pdu.c | 279 + drivers/powerp-bin.c | 605 + drivers/powerp-bin.h | 31 + drivers/powerp-txt.c | 544 + drivers/powerp-txt.h | 31 + drivers/powerpanel.c | 201 + drivers/powerpanel.h | 44 + drivers/powerware-mib.c | 316 + drivers/powerware-mib.h | 9 + drivers/raritan-pdu-mib.c | 122 + drivers/raritan-pdu-mib.h | 9 + drivers/rhino.c | 812 + drivers/richcomm_usb.c | 510 + drivers/safenet.c | 530 + drivers/safenet.h | 60 + drivers/serial.c | 456 + drivers/serial.h | 77 + drivers/skel.c | 193 + drivers/snmp-ups.c | 1377 ++ drivers/snmp-ups.h | 236 + drivers/solis.c | 1145 ++ drivers/solis.h | 356 + drivers/tripplite-hid.c | 398 + drivers/tripplite-hid.h | 33 + drivers/tripplite.c | 588 + drivers/tripplite.h | 58 + drivers/tripplite_usb.c | 1542 ++ drivers/tripplitesu.c | 858 + drivers/upscode2.c | 1424 ++ drivers/upsdrvctl.c | 502 + drivers/upshandler.h | 46 + drivers/usb-common.c | 389 + drivers/usb-common.h | 93 + drivers/usbhid-ups.c | 1506 ++ drivers/usbhid-ups.h | 179 + drivers/victronups.c | 559 + include/Makefile.am | 25 + include/Makefile.in | 460 + include/attribute.h | 12 + include/common.h | 145 + include/config.h.in | 389 + include/extstate.h | 26 + include/nut_version.h | 3 + include/parseconf.h | 75 + include/proto.h | 82 + include/state.h | 57 + include/timehead.h | 13 + include/upsconf.h | 7 + install-sh | 519 + lib/Makefile.am | 9 + lib/Makefile.in | 503 + lib/README | 116 + lib/libupsclient-config.in | 31 + lib/libupsclient.pc.in | 13 + ltmain.sh | 8413 ++++++++++ m4/ax_create_stdint_h.m4 | 725 + m4/libtool.m4 | 7376 +++++++++ m4/ltoptions.m4 | 368 + m4/ltsugar.m4 | 123 + m4/ltversion.m4 | 23 + m4/lt~obsolete.m4 | 92 + m4/nut_arg_with.m4 | 9 + m4/nut_check_ipv6.m4 | 27 + m4/nut_check_libgd.m4 | 73 + m4/nut_check_libhal.m4 | 138 + m4/nut_check_libneon.m4 | 51 + m4/nut_check_libnetsnmp.m4 | 50 + m4/nut_check_libpowerman.m4 | 41 + m4/nut_check_libssl.m4 | 54 + m4/nut_check_libusb.m4 | 62 + m4/nut_check_libwrap.m4 | 48 + m4/nut_check_os.m4 | 149 + m4/nut_report_feature.m4 | 23 + m4/nut_type_socklen_t.m4 | 43 + man/Makefile.am | 99 + man/Makefile.in | 691 + man/apcsmart.8 | 79 + man/bcmxcp.8 | 69 + man/bcmxcp_usb.8 | 90 + man/belkin.8 | 36 + man/belkinunv.8 | 327 + man/bestfcom.8 | 33 + man/bestfortress.8 | 35 + man/bestuferrups.8 | 30 + man/bestups.8 | 103 + man/blazer.8 | 267 + man/clone.8 | 107 + man/dummy-ups.8 | 133 + man/etapro.8 | 26 + man/everups.8 | 32 + man/gamatronic.8 | 27 + man/genericups.8 | 343 + man/hosts.conf.5 | 30 + man/isbmex.8 | 26 + man/ivtscd.8 | 27 + man/libupsclient-config.1 | 35 + man/liebert.8 | 42 + man/liebertgxt2.8 | 40 + man/masterguard.8 | 26 + man/megatec.8 | 169 + man/megatec_usb.8 | 187 + man/metasys.8 | 48 + man/mge-shut.8 | 70 + man/mge-utalk.8 | 103 + man/microdowell.8 | 26 + man/netxml-ups.8 | 81 + man/nut.conf.5 | 91 + man/nutupsdrv.8 | 181 + man/oneac.8 | 48 + man/optiups.8 | 81 + man/powercom.8 | 191 + man/powerman-pdu.8 | 62 + man/powerpanel.8 | 122 + man/rhino.8 | 53 + man/richcomm_usb.8 | 35 + man/safenet.8 | 88 + man/skel.8 | 82 + man/snmp-ups.8 | 106 + man/solis.8 | 49 + man/tripplite.8 | 47 + man/tripplite_usb.8 | 272 + man/tripplitesu.8 | 31 + man/ups.conf.5 | 134 + man/upsc.8 | 86 + man/upscli_connect.3 | 33 + man/upscli_disconnect.3 | 23 + man/upscli_fd.3 | 22 + man/upscli_get.3 | 91 + man/upscli_list_next.3 | 52 + man/upscli_list_start.3 | 65 + man/upscli_readline.3 | 26 + man/upscli_sendline.3 | 24 + man/upscli_splitaddr.3 | 33 + man/upscli_splitname.3 | 36 + man/upscli_ssl.3 | 23 + man/upscli_strerror.3 | 22 + man/upscli_upserror.3 | 27 + man/upsclient.3 | 53 + man/upscmd.8 | 84 + man/upscode2.8 | 87 + man/upsd.8 | 158 + man/upsd.conf.5 | 67 + man/upsd.users.5 | 89 + man/upsdrvctl.8 | 86 + man/upsimage.cgi.8 | 36 + man/upslog.8 | 96 + man/upsmon.8 | 422 + man/upsmon.conf.5 | 327 + man/upsrw.8 | 83 + man/upssched.8 | 105 + man/upssched.conf.5 | 127 + man/upsset.cgi.8 | 78 + man/upsset.conf.5 | 58 + man/upsstats.cgi.8 | 46 + man/upsstats.html.5 | 234 + man/usbhid-ups.8 | 189 + man/victronups.8 | 47 + missing | 376 + scripts/HP-UX/Makefile | 51 + scripts/HP-UX/nut-drvctl | 8 + scripts/HP-UX/nut-drvctl.sh | 114 + scripts/HP-UX/nut-upsd | 8 + scripts/HP-UX/nut-upsd.sh | 113 + scripts/HP-UX/nut-upsmon | 7 + scripts/HP-UX/nut-upsmon.sh | 92 + scripts/Makefile.am | 23 + scripts/Makefile.in | 634 + scripts/README | 11 + scripts/RedHat/README | 4 + scripts/RedHat/halt.patch | 40 + scripts/RedHat/ups | 3 + scripts/RedHat/upsd | 110 + scripts/RedHat/upsd.in | 110 + scripts/RedHat/upsmon | 56 + scripts/RedHat/upsmon.in | 56 + scripts/Solaris8/S99upsmon | 37 + scripts/Windows/Makefile | 2 + scripts/Windows/halt.c | 84 + scripts/hal/Makefile.am | 16 + scripts/hal/Makefile.in | 473 + scripts/hal/ups-nut-device.fdi.in | 392 + scripts/hotplug/Makefile.am | 11 + scripts/hotplug/Makefile.in | 509 + scripts/hotplug/README | 37 + scripts/hotplug/libhid.usermap | 122 + scripts/hotplug/libhidups.in | 17 + scripts/misc/nut.bash_completion | 208 + scripts/misc/osd-notify | 35 + scripts/python/Makefile.am | 11 + scripts/python/Makefile.in | 420 + scripts/python/README | 32 + scripts/python/app/NUT-Monitor | 423 + scripts/python/app/README | 7 + scripts/python/app/gui.glade | 658 + scripts/python/app/nut-monitor.desktop | 11 + scripts/python/app/nut-monitor.png | Bin 0 -> 1732 bytes scripts/python/module/PyNUT.py | 238 + scripts/python/module/test_nutclient.py | 43 + scripts/subdriver/path-to-subdriver.sh | 307 + scripts/udev/Makefile.am | 15 + scripts/udev/Makefile.in | 472 + scripts/udev/README | 41 + scripts/udev/nut-usbups.rules.in | 126 + server/Makefile.am | 30 + server/Makefile.in | 615 + server/conf.c | 489 + server/conf.h | 43 + server/ctype.h | 55 + server/desc.c | 165 + server/desc.h | 4 + server/netcmds.h | 60 + server/neterr.h | 35 + server/netget.c | 266 + server/netget.h | 1 + server/netinstcmd.c | 98 + server/netinstcmd.h | 1 + server/netlist.c | 268 + server/netlist.h | 1 + server/netmisc.c | 80 + server/netmisc.h | 3 + server/netset.c | 143 + server/netset.h | 1 + server/netuser.c | 154 + server/netuser.h | 5 + server/sockdebug.c | 171 + server/ssl.c | 248 + server/ssl.h | 40 + server/sstate.c | 382 + server/sstate.h | 43 + server/stype.h | 41 + server/upsd.c | 1091 ++ server/upsd.h | 87 + server/upstype.h | 55 + server/user-data.h | 36 + server/user.c | 491 + server/user.h | 28 + tools/Makefile.am | 14 + tools/Makefile.in | 426 + tools/device-recorder.sh | 96 + tools/nut-usbinfo.pl | 274 + 446 files changed, 148951 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 MAINTAINERS create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 NEWS create mode 100644 README create mode 100644 UPGRADING create mode 100644 aclocal.m4 create mode 100644 clients/Makefile.am create mode 100644 clients/Makefile.in create mode 100644 clients/cgilib.c create mode 100644 clients/cgilib.h create mode 100644 clients/status.h create mode 100644 clients/upsc.c create mode 100644 clients/upsclient.c create mode 100644 clients/upsclient.h create mode 100644 clients/upscmd.c create mode 100644 clients/upsimage.c create mode 100644 clients/upsimagearg.h create mode 100644 clients/upslog.c create mode 100644 clients/upslog.h create mode 100644 clients/upsmon.c create mode 100644 clients/upsmon.h create mode 100644 clients/upsrw.c create mode 100755 clients/upssched-cmd create mode 100644 clients/upssched.c create mode 100644 clients/upssched.h create mode 100644 clients/upsset.c create mode 100644 clients/upsstats.c create mode 100644 clients/upsstats.h create mode 100644 common/Makefile.am create mode 100644 common/Makefile.in create mode 100644 common/common.c create mode 100644 common/parseconf.c create mode 100644 common/state.c create mode 100644 common/upsconf.c create mode 100755 compile create mode 100644 conf/Makefile.am create mode 100644 conf/Makefile.in create mode 100644 conf/hosts.conf.sample create mode 100644 conf/nut.conf.sample create mode 100644 conf/ups.conf.sample create mode 100644 conf/upsd.conf.sample create mode 100644 conf/upsd.users.sample create mode 100644 conf/upsmon.conf.sample create mode 100644 conf/upssched.conf.sample.in create mode 100644 conf/upsset.conf.sample create mode 100644 conf/upsstats-single.html.sample create mode 100644 conf/upsstats.html.sample create mode 100755 config.guess create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100644 data/Makefile.am create mode 100644 data/Makefile.in create mode 100644 data/cmdvartab create mode 100644 data/driver.list create mode 100644 data/evolution500.dev create mode 100644 data/html/Makefile.am create mode 100644 data/html/Makefile.in create mode 100644 data/html/README create mode 100644 data/html/bottom.html create mode 100644 data/html/header.html.in create mode 100644 data/html/index.html create mode 100644 data/html/nut-banner.png create mode 100755 depcomp create mode 100644 docs/FAQ create mode 100644 docs/Makefile.am create mode 100644 docs/Makefile.in create mode 100644 docs/README create mode 100644 docs/acpi.txt create mode 100644 docs/big-servers.txt create mode 100644 docs/cables/apc-rs500-serial.txt create mode 100644 docs/cables/apc.txt create mode 100644 docs/cables/ge-imv-victron.txt create mode 100644 docs/cables/imv.txt create mode 100644 docs/cables/mgeups.txt create mode 100644 docs/cables/powerware.txt create mode 100644 docs/cables/repotec.txt create mode 100644 docs/cables/sms.txt create mode 100644 docs/chroot.txt create mode 100644 docs/commands.txt create mode 100644 docs/config-files.txt create mode 100644 docs/configure.txt create mode 100644 docs/contact-closure.txt create mode 100644 docs/data-room.txt create mode 100644 docs/design.txt create mode 100644 docs/developers.txt create mode 100644 docs/hid-subdrivers.txt create mode 100644 docs/ideas.txt create mode 100644 docs/macros.txt create mode 100644 docs/megatec.txt create mode 100644 docs/new-drivers.txt create mode 100644 docs/new-names.txt create mode 100644 docs/nut-hal.txt create mode 100644 docs/osd-notify.txt create mode 100644 docs/pager.txt create mode 100644 docs/powersaving.txt create mode 100644 docs/protocol.txt create mode 100644 docs/shutdown.txt create mode 100644 docs/snmp.txt create mode 100644 docs/sock-protocol.txt create mode 100644 docs/ssl.txt create mode 100644 docs/upssched.txt create mode 100644 drivers/Makefile.am create mode 100644 drivers/Makefile.in create mode 100644 drivers/apc-hid.c create mode 100644 drivers/apc-hid.h create mode 100644 drivers/apc-mib.c create mode 100644 drivers/apc-mib.h create mode 100644 drivers/apcsmart.c create mode 100644 drivers/apcsmart.h create mode 100644 drivers/baytech-mib.c create mode 100644 drivers/baytech-mib.h create mode 100644 drivers/bcmxcp.c create mode 100644 drivers/bcmxcp.h create mode 100644 drivers/bcmxcp_io.h create mode 100644 drivers/bcmxcp_ser.c create mode 100644 drivers/bcmxcp_usb.c create mode 100644 drivers/belkin-hid.c create mode 100644 drivers/belkin-hid.h create mode 100644 drivers/belkin.c create mode 100644 drivers/belkin.h create mode 100644 drivers/belkinunv.c create mode 100644 drivers/bestfcom.c create mode 100644 drivers/bestfortress.c create mode 100644 drivers/bestuferrups.c create mode 100644 drivers/bestups.c create mode 100644 drivers/blazer.c create mode 100644 drivers/blazer.h create mode 100644 drivers/blazer_ser.c create mode 100644 drivers/blazer_usb.c create mode 100644 drivers/clone-outlet.c create mode 100644 drivers/clone.c create mode 100644 drivers/compaq-mib.c create mode 100644 drivers/compaq-mib.h create mode 100644 drivers/cps-hid.c create mode 100644 drivers/cps-hid.h create mode 100644 drivers/dstate-hal.c create mode 100644 drivers/dstate-hal.h create mode 100644 drivers/dstate.c create mode 100644 drivers/dstate.h create mode 100644 drivers/dummy-ups.c create mode 100644 drivers/dummy-ups.h create mode 100644 drivers/eaton-mib.c create mode 100644 drivers/eaton-mib.h create mode 100644 drivers/etapro.c create mode 100644 drivers/everups.c create mode 100644 drivers/explore-hid.c create mode 100644 drivers/explore-hid.h create mode 100644 drivers/gamatronic.c create mode 100644 drivers/gamatronic.h create mode 100644 drivers/genericups.c create mode 100644 drivers/genericups.h create mode 100644 drivers/hidparser.c create mode 100644 drivers/hidparser.h create mode 100644 drivers/hidtypes.h create mode 100644 drivers/ietf-mib.c create mode 100644 drivers/ietf-mib.h create mode 100644 drivers/isbmex.c create mode 100644 drivers/ivtscd.c create mode 100644 drivers/libhid.c create mode 100644 drivers/libhid.h create mode 100644 drivers/libshut.c create mode 100644 drivers/libshut.h create mode 100644 drivers/libusb.c create mode 100644 drivers/libusb.h create mode 100644 drivers/liebert-hid.c create mode 100644 drivers/liebert-hid.h create mode 100644 drivers/liebert.c create mode 100644 drivers/liebertgxt2.c create mode 100644 drivers/main-hal.c create mode 100644 drivers/main-hal.h create mode 100644 drivers/main.c create mode 100644 drivers/main.h create mode 100644 drivers/masterguard.c create mode 100644 drivers/megatec.c create mode 100644 drivers/megatec.h create mode 100644 drivers/megatec_usb.c create mode 100644 drivers/metasys.c create mode 100644 drivers/mge-hid.c create mode 100644 drivers/mge-hid.h create mode 100644 drivers/mge-mib.c create mode 100644 drivers/mge-mib.h create mode 100644 drivers/mge-shut.c create mode 100644 drivers/mge-shut.h create mode 100644 drivers/mge-utalk.c create mode 100644 drivers/mge-utalk.h create mode 100644 drivers/mge-xml.c create mode 100644 drivers/mge-xml.h create mode 100644 drivers/microdowell.c create mode 100644 drivers/microdowell.h create mode 100644 drivers/netvision-mib.c create mode 100644 drivers/netvision-mib.h create mode 100644 drivers/netxml-ups.c create mode 100644 drivers/netxml-ups.h create mode 100644 drivers/oneac.c create mode 100644 drivers/oneac.h create mode 100644 drivers/optiups.c create mode 100644 drivers/powercom-hid.c create mode 100644 drivers/powercom-hid.h create mode 100644 drivers/powercom.c create mode 100644 drivers/powercom.h create mode 100644 drivers/powerman-pdu.c create mode 100644 drivers/powerp-bin.c create mode 100644 drivers/powerp-bin.h create mode 100644 drivers/powerp-txt.c create mode 100644 drivers/powerp-txt.h create mode 100644 drivers/powerpanel.c create mode 100644 drivers/powerpanel.h create mode 100644 drivers/powerware-mib.c create mode 100644 drivers/powerware-mib.h create mode 100644 drivers/raritan-pdu-mib.c create mode 100644 drivers/raritan-pdu-mib.h create mode 100644 drivers/rhino.c create mode 100644 drivers/richcomm_usb.c create mode 100644 drivers/safenet.c create mode 100644 drivers/safenet.h create mode 100644 drivers/serial.c create mode 100644 drivers/serial.h create mode 100644 drivers/skel.c create mode 100644 drivers/snmp-ups.c create mode 100644 drivers/snmp-ups.h create mode 100644 drivers/solis.c create mode 100644 drivers/solis.h create mode 100644 drivers/tripplite-hid.c create mode 100644 drivers/tripplite-hid.h create mode 100644 drivers/tripplite.c create mode 100644 drivers/tripplite.h create mode 100644 drivers/tripplite_usb.c create mode 100644 drivers/tripplitesu.c create mode 100644 drivers/upscode2.c create mode 100644 drivers/upsdrvctl.c create mode 100644 drivers/upshandler.h create mode 100644 drivers/usb-common.c create mode 100644 drivers/usb-common.h create mode 100644 drivers/usbhid-ups.c create mode 100644 drivers/usbhid-ups.h create mode 100644 drivers/victronups.c create mode 100644 include/Makefile.am create mode 100644 include/Makefile.in create mode 100644 include/attribute.h create mode 100644 include/common.h create mode 100644 include/config.h.in create mode 100644 include/extstate.h create mode 100644 include/nut_version.h create mode 100644 include/parseconf.h create mode 100644 include/proto.h create mode 100644 include/state.h create mode 100644 include/timehead.h create mode 100644 include/upsconf.h create mode 100755 install-sh create mode 100644 lib/Makefile.am create mode 100644 lib/Makefile.in create mode 100644 lib/README create mode 100644 lib/libupsclient-config.in create mode 100644 lib/libupsclient.pc.in create mode 100755 ltmain.sh create mode 100644 m4/ax_create_stdint_h.m4 create mode 100644 m4/libtool.m4 create mode 100644 m4/ltoptions.m4 create mode 100644 m4/ltsugar.m4 create mode 100644 m4/ltversion.m4 create mode 100644 m4/lt~obsolete.m4 create mode 100644 m4/nut_arg_with.m4 create mode 100644 m4/nut_check_ipv6.m4 create mode 100644 m4/nut_check_libgd.m4 create mode 100644 m4/nut_check_libhal.m4 create mode 100644 m4/nut_check_libneon.m4 create mode 100644 m4/nut_check_libnetsnmp.m4 create mode 100644 m4/nut_check_libpowerman.m4 create mode 100644 m4/nut_check_libssl.m4 create mode 100644 m4/nut_check_libusb.m4 create mode 100644 m4/nut_check_libwrap.m4 create mode 100755 m4/nut_check_os.m4 create mode 100644 m4/nut_report_feature.m4 create mode 100644 m4/nut_type_socklen_t.m4 create mode 100644 man/Makefile.am create mode 100644 man/Makefile.in create mode 100644 man/apcsmart.8 create mode 100644 man/bcmxcp.8 create mode 100644 man/bcmxcp_usb.8 create mode 100644 man/belkin.8 create mode 100644 man/belkinunv.8 create mode 100644 man/bestfcom.8 create mode 100644 man/bestfortress.8 create mode 100644 man/bestuferrups.8 create mode 100644 man/bestups.8 create mode 100644 man/blazer.8 create mode 100644 man/clone.8 create mode 100644 man/dummy-ups.8 create mode 100644 man/etapro.8 create mode 100644 man/everups.8 create mode 100644 man/gamatronic.8 create mode 100644 man/genericups.8 create mode 100644 man/hosts.conf.5 create mode 100644 man/isbmex.8 create mode 100644 man/ivtscd.8 create mode 100644 man/libupsclient-config.1 create mode 100644 man/liebert.8 create mode 100644 man/liebertgxt2.8 create mode 100644 man/masterguard.8 create mode 100644 man/megatec.8 create mode 100644 man/megatec_usb.8 create mode 100644 man/metasys.8 create mode 100644 man/mge-shut.8 create mode 100644 man/mge-utalk.8 create mode 100644 man/microdowell.8 create mode 100644 man/netxml-ups.8 create mode 100644 man/nut.conf.5 create mode 100644 man/nutupsdrv.8 create mode 100644 man/oneac.8 create mode 100644 man/optiups.8 create mode 100644 man/powercom.8 create mode 100644 man/powerman-pdu.8 create mode 100644 man/powerpanel.8 create mode 100644 man/rhino.8 create mode 100644 man/richcomm_usb.8 create mode 100644 man/safenet.8 create mode 100644 man/skel.8 create mode 100644 man/snmp-ups.8 create mode 100644 man/solis.8 create mode 100644 man/tripplite.8 create mode 100644 man/tripplite_usb.8 create mode 100644 man/tripplitesu.8 create mode 100644 man/ups.conf.5 create mode 100644 man/upsc.8 create mode 100644 man/upscli_connect.3 create mode 100644 man/upscli_disconnect.3 create mode 100644 man/upscli_fd.3 create mode 100644 man/upscli_get.3 create mode 100644 man/upscli_list_next.3 create mode 100644 man/upscli_list_start.3 create mode 100644 man/upscli_readline.3 create mode 100644 man/upscli_sendline.3 create mode 100644 man/upscli_splitaddr.3 create mode 100644 man/upscli_splitname.3 create mode 100644 man/upscli_ssl.3 create mode 100644 man/upscli_strerror.3 create mode 100644 man/upscli_upserror.3 create mode 100644 man/upsclient.3 create mode 100644 man/upscmd.8 create mode 100644 man/upscode2.8 create mode 100644 man/upsd.8 create mode 100644 man/upsd.conf.5 create mode 100644 man/upsd.users.5 create mode 100644 man/upsdrvctl.8 create mode 100644 man/upsimage.cgi.8 create mode 100644 man/upslog.8 create mode 100644 man/upsmon.8 create mode 100644 man/upsmon.conf.5 create mode 100644 man/upsrw.8 create mode 100644 man/upssched.8 create mode 100644 man/upssched.conf.5 create mode 100644 man/upsset.cgi.8 create mode 100644 man/upsset.conf.5 create mode 100644 man/upsstats.cgi.8 create mode 100644 man/upsstats.html.5 create mode 100644 man/usbhid-ups.8 create mode 100644 man/victronups.8 create mode 100755 missing create mode 100644 scripts/HP-UX/Makefile create mode 100644 scripts/HP-UX/nut-drvctl create mode 100755 scripts/HP-UX/nut-drvctl.sh create mode 100644 scripts/HP-UX/nut-upsd create mode 100755 scripts/HP-UX/nut-upsd.sh create mode 100644 scripts/HP-UX/nut-upsmon create mode 100755 scripts/HP-UX/nut-upsmon.sh create mode 100644 scripts/Makefile.am create mode 100644 scripts/Makefile.in create mode 100644 scripts/README create mode 100644 scripts/RedHat/README create mode 100644 scripts/RedHat/halt.patch create mode 100644 scripts/RedHat/ups create mode 100644 scripts/RedHat/upsd create mode 100644 scripts/RedHat/upsd.in create mode 100644 scripts/RedHat/upsmon create mode 100644 scripts/RedHat/upsmon.in create mode 100755 scripts/Solaris8/S99upsmon create mode 100644 scripts/Windows/Makefile create mode 100644 scripts/Windows/halt.c create mode 100644 scripts/hal/Makefile.am create mode 100644 scripts/hal/Makefile.in create mode 100644 scripts/hal/ups-nut-device.fdi.in create mode 100644 scripts/hotplug/Makefile.am create mode 100644 scripts/hotplug/Makefile.in create mode 100644 scripts/hotplug/README create mode 100644 scripts/hotplug/libhid.usermap create mode 100644 scripts/hotplug/libhidups.in create mode 100644 scripts/misc/nut.bash_completion create mode 100644 scripts/misc/osd-notify create mode 100644 scripts/python/Makefile.am create mode 100644 scripts/python/Makefile.in create mode 100644 scripts/python/README create mode 100755 scripts/python/app/NUT-Monitor create mode 100644 scripts/python/app/README create mode 100644 scripts/python/app/gui.glade create mode 100644 scripts/python/app/nut-monitor.desktop create mode 100644 scripts/python/app/nut-monitor.png create mode 100644 scripts/python/module/PyNUT.py create mode 100755 scripts/python/module/test_nutclient.py create mode 100755 scripts/subdriver/path-to-subdriver.sh create mode 100644 scripts/udev/Makefile.am create mode 100644 scripts/udev/Makefile.in create mode 100644 scripts/udev/README create mode 100644 scripts/udev/nut-usbups.rules.in create mode 100644 server/Makefile.am create mode 100644 server/Makefile.in create mode 100644 server/conf.c create mode 100644 server/conf.h create mode 100644 server/ctype.h create mode 100644 server/desc.c create mode 100644 server/desc.h create mode 100644 server/netcmds.h create mode 100644 server/neterr.h create mode 100644 server/netget.c create mode 100644 server/netget.h create mode 100644 server/netinstcmd.c create mode 100644 server/netinstcmd.h create mode 100644 server/netlist.c create mode 100644 server/netlist.h create mode 100644 server/netmisc.c create mode 100644 server/netmisc.h create mode 100644 server/netset.c create mode 100644 server/netset.h create mode 100644 server/netuser.c create mode 100644 server/netuser.h create mode 100644 server/sockdebug.c create mode 100644 server/ssl.c create mode 100644 server/ssl.h create mode 100644 server/sstate.c create mode 100644 server/sstate.h create mode 100644 server/stype.h create mode 100644 server/upsd.c create mode 100644 server/upsd.h create mode 100644 server/upstype.h create mode 100644 server/user-data.h create mode 100644 server/user.c create mode 100644 server/user.h create mode 100644 tools/Makefile.am create mode 100644 tools/Makefile.in create mode 100755 tools/device-recorder.sh create mode 100755 tools/nut-usbinfo.pl 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 +