apcupsd-3.14.14/000077500000000000000000000000001274230402600133235ustar00rootroot00000000000000apcupsd-3.14.14/COPYING000066400000000000000000000432541274230402600143660ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. apcupsd-3.14.14/ChangeLog000066400000000000000000007224121274230402600151050ustar00rootroot00000000000000/***************************************************************************/ /* ChangeLog of Apcupsd 3.14.x */ /* */ /* Adam Kropelin */ /* */ /* http://www.apcupsd.com/ */ /* http://sourceforge.net/projects/apcupsd */ /***************************************************************************/ ------------------------------------------------------------------------ r2376 | adk0212 | 2016-05-04 09:57:08 -0400 (Wed, 04 May 2016) | 2 lines Add battery constant for SU3000NET (h/t David Harrison ) ------------------------------------------------------------------------ r2375 | adk0212 | 2016-05-04 09:51:57 -0400 (Wed, 04 May 2016) | 2 lines Update build notes to call out need for libusb patch ------------------------------------------------------------------------ r2374 | adk0212 | 2016-05-04 09:46:02 -0400 (Wed, 04 May 2016) | 2 lines Fix successful interrupt transfers with timeout >= 1 second ------------------------------------------------------------------------ r2373 | adk0212 | 2016-05-03 16:04:58 -0400 (Tue, 03 May 2016) | 2 lines More efficient handling of long timeouts ------------------------------------------------------------------------ r2372 | adk0212 | 2016-05-03 15:32:46 -0400 (Tue, 03 May 2016) | 3 lines darwin libusb fixes for supporting timeouts on interrupt transfers Required for MODBUS/USB reliability ------------------------------------------------------------------------ r2371 | adk0212 | 2016-04-18 16:56:43 -0400 (Mon, 18 Apr 2016) | 2 lines Remove obsolete apcupsd binaries from /sbin ------------------------------------------------------------------------ r2370 | adk0212 | 2016-04-18 16:43:09 -0400 (Mon, 18 Apr 2016) | 2 lines Remove temp file ------------------------------------------------------------------------ r2369 | adk0212 | 2016-04-18 16:26:31 -0400 (Mon, 18 Apr 2016) | 2 lines Regenerate configure script with changes to preprocess additional darwin platform files ------------------------------------------------------------------------ r2368 | adk0212 | 2016-04-18 16:25:33 -0400 (Mon, 18 Apr 2016) | 6 lines Fixes so Mac OS X builds obey sbindir - Enables moving apcupsd executables from /sbin to /usr/local/sbin for compatibility with 10.11 System Integrity Protection (aka rootless) - Autogen apcupsd-start, apcupsd-uninstall, org.apcupsd.apcupsd.plist scripts from configure so they have proper sbindir incorporated instead of hard coded /sbin - Update darwin Makefile to obey sbindir - Update darwin build notes to reflect use of --sbindir= argument to configure ------------------------------------------------------------------------ r2367 | adk0212 | 2016-04-18 16:20:27 -0400 (Mon, 18 Apr 2016) | 2 lines Install signed copy of ApcupsdDummy.kext ------------------------------------------------------------------------ r2366 | adk0212 | 2016-01-29 16:28:07 -0500 (Fri, 29 Jan 2016) | 2 lines Sign ApcupsdDummy.kext ------------------------------------------------------------------------ r2365 | adk0212 | 2016-01-19 12:28:52 -0500 (Tue, 19 Jan 2016) | 2 lines Remove use of BSD USB driver; all platforms except Linux use generic-usb now ------------------------------------------------------------------------ r2364 | adk0212 | 2016-01-19 12:03:20 -0500 (Tue, 19 Jan 2016) | 3 lines Remove use of pthread_setname_np. Too many variants, not enough value. ------------------------------------------------------------------------ r2363 | adk0212 | 2016-01-19 10:04:37 -0500 (Tue, 19 Jan 2016) | 3 lines test(1) uses "=" for string equality. "==" is a bashism. Patch from Patrick Welche ------------------------------------------------------------------------ r2362 | adk0212 | 2015-12-19 16:30:40 -0500 (Sat, 19 Dec 2015) | 3 lines Fix shutdown failure on Windows when UPSNAME includes spaces - Quote UPSNAME field when building apccontrol command line ------------------------------------------------------------------------ r2361 | adk0212 | 2015-10-05 18:29:56 -0400 (Mon, 05 Oct 2015) | 2 lines Update apcupsd.spec for RHEL6 (from David Ranch ) ------------------------------------------------------------------------ r2360 | adk0212 | 2015-09-24 16:14:16 -0400 (Thu, 24 Sep 2015) | 2 lines Add apparent power measurement and nominal values ------------------------------------------------------------------------ r2359 | adk0212 | 2015-09-24 15:58:19 -0400 (Thu, 24 Sep 2015) | 2 lines Increase resolution of OUTCURNT to 0.01 Amps as suggested by Manfred Schwarb ------------------------------------------------------------------------ r2358 | adk0212 | 2015-09-21 11:02:18 -0400 (Mon, 21 Sep 2015) | 2 lines Fixes for ModbusUsbComm::WaitIdle ------------------------------------------------------------------------ r2357 | adk0212 | 2015-09-20 11:01:39 -0400 (Sun, 20 Sep 2015) | 2 lines Add output current to status display ------------------------------------------------------------------------ r2356 | adk0212 | 2015-09-20 11:01:17 -0400 (Sun, 20 Sep 2015) | 3 lines Add support for displaying output currnent on MODBUS - Also rename {REAL,APPARENT}_POWER usages to clarify that they represent percent-of-nominal ------------------------------------------------------------------------ r2355 | adk0212 | 2015-09-20 10:59:32 -0400 (Sun, 20 Sep 2015) | 2 lines Move eeprom to static data section ------------------------------------------------------------------------ r2354 | adk0212 | 2015-06-24 22:29:14 -0400 (Wed, 24 Jun 2015) | 5 lines Fix building bsd-usb driver Correct link order when bsd-usb is enabled. This was broken when modbus-usb support was added. Reported by Kirill Bychkov ------------------------------------------------------------------------ r2352 | adk0212 | 2015-05-31 11:55:44 -0400 (Sun, 31 May 2015) | 2 lines Update ChangeLog ------------------------------------------------------------------------ r2351 | adk0212 | 2015-05-31 11:54:57 -0400 (Sun, 31 May 2015) | 2 lines Update ReleaseNotes ------------------------------------------------------------------------ r2350 | adk0212 | 2015-05-30 16:56:12 -0400 (Sat, 30 May 2015) | 2 lines Prep for 3.14.14 release ------------------------------------------------------------------------ r2349 | adk0212 | 2015-05-09 11:33:29 -0400 (Sat, 09 May 2015) | 2 lines Remove driver subdirs during uninstall ------------------------------------------------------------------------ r2348 | adk0212 | 2015-05-09 11:28:33 -0400 (Sat, 09 May 2015) | 3 lines Fix missing DLLs when installing only apctray Reported by keithg@pobox.com ------------------------------------------------------------------------ r2347 | adk0212 | 2015-03-25 15:55:46 -0400 (Wed, 25 Mar 2015) | 2 lines Add 'svnclean' target to remove all files that show as unversioned in svn ------------------------------------------------------------------------ r2346 | adk0212 | 2015-03-24 23:53:39 -0400 (Tue, 24 Mar 2015) | 3 lines Remove obsolete NET-SNMP driver This has been replaced by the snmplite driver for many years now. ------------------------------------------------------------------------ r2345 | adk0212 | 2015-03-22 11:58:02 -0400 (Sun, 22 Mar 2015) | 2 lines CID107690 Unchecked return value ------------------------------------------------------------------------ r2344 | adk0212 | 2015-03-22 11:51:42 -0400 (Sun, 22 Mar 2015) | 3 lines CID107691 - Pointer to local outside scope UPSINFO goes out of scope before use via 'host' pointer ------------------------------------------------------------------------ r2343 | adk0212 | 2015-03-21 23:21:42 -0400 (Sat, 21 Mar 2015) | 2 lines Set thread names using pthread_setname_np() when available ------------------------------------------------------------------------ r2342 | adk0212 | 2015-03-21 22:06:46 -0400 (Sat, 21 Mar 2015) | 2 lines Remove obsolete comments, add my copyright ------------------------------------------------------------------------ r2341 | adk0212 | 2015-03-21 22:03:30 -0400 (Sat, 21 Mar 2015) | 3 lines Remove workaround for old BSD userspace pthreads bug We have been closing fds after fork() for some time now and we now have CLOEXEC set properly ------------------------------------------------------------------------ r2340 | adk0212 | 2015-03-21 18:43:19 -0400 (Sat, 21 Mar 2015) | 2 lines Explicitly ignore return value ------------------------------------------------------------------------ r2339 | adk0212 | 2015-03-21 18:30:29 -0400 (Sat, 21 Mar 2015) | 2 lines Fix some unchecked returns ------------------------------------------------------------------------ r2338 | adk0212 | 2015-03-21 18:19:20 -0400 (Sat, 21 Mar 2015) | 2 lines Quiet some Coverity errors by explicitly discarding return fgetc() return value ------------------------------------------------------------------------ r2337 | adk0212 | 2015-03-21 17:59:35 -0400 (Sat, 21 Mar 2015) | 2 lines Improvements to hosts.conf parsing logic ------------------------------------------------------------------------ r2336 | adk0212 | 2015-03-21 11:42:50 -0400 (Sat, 21 Mar 2015) | 3 lines CID17191 - Uninitialized scalar field Not reall a defect as _commlost_time is always set before being used, but initialize it in constructor anyway for cleanliness ------------------------------------------------------------------------ r2335 | adk0212 | 2015-03-21 11:39:46 -0400 (Sat, 21 Mar 2015) | 3 lines Another shot at fixing CID 107532,107533 Coverity really wants you to check fcntl retval ------------------------------------------------------------------------ r2334 | adk0212 | 2015-03-20 22:26:04 -0400 (Fri, 20 Mar 2015) | 2 lines CID107533 - Unchecked return value from library ------------------------------------------------------------------------ r2333 | adk0212 | 2015-03-20 21:47:16 -0400 (Fri, 20 Mar 2015) | 2 lines Mark error_out_wrapper as noreturn to prevent bogus warnings ------------------------------------------------------------------------ r2332 | adk0212 | 2015-03-20 00:05:15 -0400 (Fri, 20 Mar 2015) | 2 lines A couple more socket cloexec fixes ------------------------------------------------------------------------ r2331 | adk0212 | 2015-03-19 23:59:41 -0400 (Thu, 19 Mar 2015) | 3 lines Fix open file descriptors leaking to exec'ed children Use O_CLOEXEC and friends as necessary to ensure we don't leak fds to children across exec ------------------------------------------------------------------------ r2330 | adk0212 | 2015-03-19 23:58:11 -0400 (Thu, 19 Mar 2015) | 2 lines Icon file for web site ------------------------------------------------------------------------ r2329 | adk0212 | 2015-03-06 14:05:24 -0500 (Fri, 06 Mar 2015) | 4 lines Fixes for socket error handling Resolves apcaccess crash when connection fails as well as several other theoretical issues. ------------------------------------------------------------------------ r2328 | adk0212 | 2015-02-17 15:18:17 -0500 (Tue, 17 Feb 2015) | 3 lines Now that we are using the system tcpd.h exclusively, use not "tcpd.h" include form. h/t Manfred Schwarb ------------------------------------------------------------------------ r2327 | adk0212 | 2015-02-17 08:47:54 -0500 (Tue, 17 Feb 2015) | 3 lines Stop shipping a hacked copy of tcpd.h and wrap the include of the system header with extern "C" instead. RedHat's tcpd.h already has __{BEGIN,END}_DECL demarcation but SuSE's (for example) does not. ------------------------------------------------------------------------ r2326 | adk0212 | 2015-02-15 17:02:53 -0500 (Sun, 15 Feb 2015) | 2 lines Discard unexpected messages when waiting for idle ------------------------------------------------------------------------ r2325 | adk0212 | 2015-02-15 16:59:04 -0500 (Sun, 15 Feb 2015) | 2 lines Fix hiddev binding when usbfs is mounted on /dev/bus/usb instead of /proc/bus/usb ------------------------------------------------------------------------ r2324 | adk0212 | 2015-02-08 23:35:39 -0500 (Sun, 08 Feb 2015) | 2 lines Include file/line info in hex_dump output to match Dmsg ------------------------------------------------------------------------ r2323 | adk0212 | 2015-02-08 19:45:45 -0500 (Sun, 08 Feb 2015) | 3 lines Detect if compiler supports -Wno-unused-result instead of using it blindly - Also use new AX_ADD_COMPILE_FLAG for -fno-exceptions and -fno-rtti ------------------------------------------------------------------------ r2322 | adk0212 | 2015-02-08 13:00:05 -0500 (Sun, 08 Feb 2015) | 2 lines Update FSF address ------------------------------------------------------------------------ r2321 | adk0212 | 2015-02-08 12:49:27 -0500 (Sun, 08 Feb 2015) | 4 lines Update GPLv2 text - Same license, just minor updates to the text to match current FSF official copy - Changes include FSF address and removal of '19xx' style year annotations ------------------------------------------------------------------------ r2320 | adk0212 | 2015-02-08 12:42:02 -0500 (Sun, 08 Feb 2015) | 2 lines Remove unused file ------------------------------------------------------------------------ r2319 | adk0212 | 2015-02-08 12:01:31 -0500 (Sun, 08 Feb 2015) | 3 lines Remove subsys directory from SuSE lock file location Reported by Manfred Schwarb ------------------------------------------------------------------------ r2318 | adk0212 | 2015-02-07 13:26:15 -0500 (Sat, 07 Feb 2015) | 3 lines Add -Wno-unused-result to suppress "ignoring return value of..." warnings. Prefer to track these via Coverity instead of inconsistent compile warnings. ------------------------------------------------------------------------ r2317 | adk0212 | 2015-02-06 19:31:18 -0500 (Fri, 06 Feb 2015) | 5 lines Improve COMMLOST handling for MODBUS, esp. MODBUS/USB - Fix ModbusUsbComm to handle Open() call when already open - Fix ModbusUpsDriver to close the Comm class when declaring COMMLOST - Fail register read/write calls at ModbusComm layer when underlying transport is not open ------------------------------------------------------------------------ r2315 | adk0212 | 2015-02-02 21:27:26 -0500 (Mon, 02 Feb 2015) | 2 lines Final prep for 3.14.13 release ------------------------------------------------------------------------ r2314 | adk0212 | 2015-02-02 21:16:47 -0500 (Mon, 02 Feb 2015) | 2 lines Correct some outdated information in the apctest section of the manual ------------------------------------------------------------------------ r2313 | adk0212 | 2015-02-02 20:47:30 -0500 (Mon, 02 Feb 2015) | 2 lines Detect failure to modify RedHat halt script and display a message instead of failing the whole installation ------------------------------------------------------------------------ r2312 | adk0212 | 2015-01-31 11:38:09 -0500 (Sat, 31 Jan 2015) | 2 lines Prep for 3.14.13 release ------------------------------------------------------------------------ r2311 | adk0212 | 2015-01-29 09:13:25 -0500 (Thu, 29 Jan 2015) | 5 lines Place apcupsd lock file in /var/lock instead of /var/lock/subsys on Slackware Slackware convention is to use /var/lock; /var/lock/subsys appears to be a Red Hat thing Reported by Sebastian Arcus Patch by Jonathan Woithe ------------------------------------------------------------------------ r2310 | adk0212 | 2015-01-20 12:38:53 -0500 (Tue, 20 Jan 2015) | 3 lines Add notes indicating that apcupsd must be restarted for config file changes to become active. Although it might be considered "obvious", this wasn't actually written down anywhere that I could find. ------------------------------------------------------------------------ r2309 | adk0212 | 2015-01-20 12:15:04 -0500 (Tue, 20 Jan 2015) | 2 lines Updated Windows USB driver signature, courtesy of Jernej Simončič ------------------------------------------------------------------------ r2308 | adk0212 | 2015-01-19 21:45:44 -0500 (Mon, 19 Jan 2015) | 2 lines Add debug to Tx side of modbus USB to match RS232 ------------------------------------------------------------------------ r2307 | adk0212 | 2015-01-19 21:02:01 -0500 (Mon, 19 Jan 2015) | 2 lines Remove unused a{m,re,c}alloc functions ------------------------------------------------------------------------ r2306 | adk0212 | 2015-01-19 20:58:51 -0500 (Mon, 19 Jan 2015) | 2 lines Remove obsolete UPS list code ------------------------------------------------------------------------ r2305 | adk0212 | 2015-01-19 20:55:56 -0500 (Mon, 19 Jan 2015) | 2 lines Remove obsolete references to myUPS ------------------------------------------------------------------------ r2304 | adk0212 | 2015-01-19 20:52:18 -0500 (Mon, 19 Jan 2015) | 2 lines Remove obsolete file ------------------------------------------------------------------------ r2303 | adk0212 | 2015-01-19 20:48:49 -0500 (Mon, 19 Jan 2015) | 2 lines Remove obsolete prototypes ------------------------------------------------------------------------ r2302 | adk0212 | 2015-01-19 20:38:19 -0500 (Mon, 19 Jan 2015) | 2 lines Remove obsolete simple signaling cable info ------------------------------------------------------------------------ r2301 | adk0212 | 2015-01-19 19:09:42 -0500 (Mon, 19 Jan 2015) | 2 lines Bump win32 usb driver date and rev ------------------------------------------------------------------------ r2300 | adk0212 | 2015-01-19 19:04:40 -0500 (Mon, 19 Jan 2015) | 2 lines Fix typo ------------------------------------------------------------------------ r2299 | adk0212 | 2015-01-19 18:52:30 -0500 (Mon, 19 Jan 2015) | 2 lines Fix typo ------------------------------------------------------------------------ r2298 | adk0212 | 2015-01-18 15:38:34 -0500 (Sun, 18 Jan 2015) | 2 lines Add --enable-modbus-usb to Darwin build notes ------------------------------------------------------------------------ r2297 | adk0212 | 2015-01-18 11:41:26 -0500 (Sun, 18 Jan 2015) | 3 lines Update supported USB VID/PID combinations in code and platform-specific drivers - Includes several VID/PID tuples for future use as suggested by APC ------------------------------------------------------------------------ r2296 | adk0212 | 2015-01-12 11:56:25 -0500 (Mon, 12 Jan 2015) | 3 lines Remove ancient unmaintained apcupsd.8 manpage from Debian platform directory. The current manpage set for apcupsd is in doc/ and should be used by all platforms. ------------------------------------------------------------------------ r2295 | adk0212 | 2015-01-07 22:06:44 -0500 (Wed, 07 Jan 2015) | 2 lines Fix handling of return value from USBDEVFS_CONNECT ------------------------------------------------------------------------ r2294 | adk0212 | 2015-01-07 21:31:27 -0500 (Wed, 07 Jan 2015) | 2 lines Add MODBUS/USB info to apcupsd.conf comments ------------------------------------------------------------------------ r2293 | adk0212 | 2015-01-07 21:25:06 -0500 (Wed, 07 Jan 2015) | 2 lines Add MODBUS USB setting info to apcupsd.conf(5) man page ------------------------------------------------------------------------ r2292 | adk0212 | 2015-01-07 20:54:03 -0500 (Wed, 07 Jan 2015) | 2 lines Remove ETIMEDOUT workaround; this is no longer an issue ------------------------------------------------------------------------ r2291 | adk0212 | 2015-01-04 19:24:06 -0500 (Sun, 04 Jan 2015) | 2 lines Update documentation for MODBUS USB. ------------------------------------------------------------------------ r2289 | adk0212 | 2015-01-04 15:41:14 -0500 (Sun, 04 Jan 2015) | 2 lines Update ChangeLog for 3.14.13-test2 ------------------------------------------------------------------------ r2288 | adk0212 | 2015-01-04 15:39:58 -0500 (Sun, 04 Jan 2015) | 2 lines Bump version to 3.14.13-test2 ------------------------------------------------------------------------ r2287 | adk0212 | 2015-01-04 15:35:43 -0500 (Sun, 04 Jan 2015) | 3 lines Fix link error on BSD systems due to use of --{start,end}-group which only works on GNU ld Move HidUps.cpp into libusbhid (since it is a wrapper for that library) which resolves dependency issue so we can eliminate use of --{start,end}-group ------------------------------------------------------------------------ r2285 | adk0212 | 2015-01-04 13:14:22 -0500 (Sun, 04 Jan 2015) | 2 lines Update ChangeLog for 3.14.13-test1 ------------------------------------------------------------------------ r2284 | adk0212 | 2015-01-04 13:08:07 -0500 (Sun, 04 Jan 2015) | 2 lines Bump version for 3.14.13-test1 release ------------------------------------------------------------------------ r2283 | adk0212 | 2015-01-04 13:06:40 -0500 (Sun, 04 Jan 2015) | 4 lines Fix WriteRegister on MODBUS USB Response messages need to be treated individually to determine length of live data. Previously code was assuming READ_HOLDING_REGS format which fails for WRITE_MULTIPLE_REGS. ------------------------------------------------------------------------ r2282 | adk0212 | 2015-01-03 11:26:55 -0500 (Sat, 03 Jan 2015) | 2 lines Allow cable type of USB for MODBUS driver ------------------------------------------------------------------------ r2281 | adk0212 | 2015-01-03 11:26:33 -0500 (Sat, 03 Jan 2015) | 2 lines Update file header comment ------------------------------------------------------------------------ r2280 | adk0212 | 2015-01-03 00:07:49 -0500 (Sat, 03 Jan 2015) | 2 lines Add usb_interrupt_write() to winusb translation layer to support MODBUS USB ------------------------------------------------------------------------ r2279 | adk0212 | 2015-01-03 00:02:51 -0500 (Sat, 03 Jan 2015) | 2 lines Add MODBUS USB support ------------------------------------------------------------------------ r2278 | adk0212 | 2015-01-03 00:00:58 -0500 (Sat, 03 Jan 2015) | 2 lines Remove unused _{new,old}tio variables ------------------------------------------------------------------------ r2277 | adk0212 | 2015-01-02 23:59:59 -0500 (Fri, 02 Jan 2015) | 2 lines Remove hidutils.c as its functionality has been subsumed into HidUps.cpp ------------------------------------------------------------------------ r2276 | adk0212 | 2015-01-02 23:50:36 -0500 (Fri, 02 Jan 2015) | 2 lines Build drivers into separate libs to eliminate rule duplication in src/driver/Makefile ------------------------------------------------------------------------ r2275 | adk0212 | 2015-01-02 16:34:23 -0500 (Fri, 02 Jan 2015) | 3 lines Break libusb and libusbhid interfacing code out into HidUps class. This will allow reuse with MODBUS USB capability. ------------------------------------------------------------------------ r2274 | adk0212 | 2015-01-02 12:12:47 -0500 (Fri, 02 Jan 2015) | 2 lines Configure support for MODBUS/USB ------------------------------------------------------------------------ r2273 | adk0212 | 2014-12-02 16:10:47 -0500 (Tue, 02 Dec 2014) | 3 lines CID75626 Uninitialized scalar field Remove _oldtio and _newtio members, they are not necessary ------------------------------------------------------------------------ r2272 | adk0212 | 2014-12-02 16:06:57 -0500 (Tue, 02 Dec 2014) | 3 lines CID75625 Unchecked return value from library Check return value from fcntl(F_GETFL) and explicitly ignore retval from fcntl(F_SETFL) ------------------------------------------------------------------------ r2271 | adk0212 | 2014-12-01 14:38:54 -0500 (Mon, 01 Dec 2014) | 2 lines Refactor MODBUS RS232 into base and derived class ------------------------------------------------------------------------ r2270 | adk0212 | 2014-11-25 16:33:23 -0500 (Tue, 25 Nov 2014) | 3 lines Fix apcsmart calibration on win32 Need to poll for UPS commands and keyboard input since win32 select only works with sockets ------------------------------------------------------------------------ r2269 | adk0212 | 2014-11-25 08:17:20 -0500 (Tue, 25 Nov 2014) | 2 lines Update comment on LOCKFILE directive to resolve confusion over whether it is a FILE as the name would imply, or a DIRECTORY, which is the truth ------------------------------------------------------------------------ r2268 | adk0212 | 2014-11-24 13:25:49 -0500 (Mon, 24 Nov 2014) | 3 lines Check for setup_device failure and exit with an error instead of continuing on. Reported by Laurent Blume ------------------------------------------------------------------------ r2267 | adk0212 | 2014-11-12 12:30:33 -0500 (Wed, 12 Nov 2014) | 2 lines Fix libsupc++fix.cpp filename in configure ------------------------------------------------------------------------ r2266 | adk0212 | 2014-11-06 22:12:59 -0500 (Thu, 06 Nov 2014) | 2 lines Add missing copyright banners ------------------------------------------------------------------------ r2265 | adk0212 | 2014-11-06 22:00:43 -0500 (Thu, 06 Nov 2014) | 2 lines Use PTHREAD_MUTEX_INITIALIZER to init mutex ------------------------------------------------------------------------ r2264 | adk0212 | 2014-11-06 21:42:11 -0500 (Thu, 06 Nov 2014) | 2 lines Bring back compat/pwd.h and move getpwuid() to it ------------------------------------------------------------------------ r2263 | adk0212 | 2014-11-06 21:28:57 -0500 (Thu, 06 Nov 2014) | 2 lines Remove FREEBSD_SUPCPP_FIX, this file is now compiled only when needed so content can be unconditional ------------------------------------------------------------------------ r2262 | adk0212 | 2014-11-06 17:01:12 -0500 (Thu, 06 Nov 2014) | 2 lines smtp needs pwd.h ------------------------------------------------------------------------ r2261 | adk0212 | 2014-11-06 16:51:13 -0500 (Thu, 06 Nov 2014) | 2 lines Only build libsupc++fix.cpp when needed and in the process clean up LIBEXTRAOBJ handling ------------------------------------------------------------------------ r2260 | adk0212 | 2014-11-06 16:34:20 -0500 (Thu, 06 Nov 2014) | 2 lines Remove unused file ------------------------------------------------------------------------ r2259 | adk0212 | 2014-11-06 16:32:25 -0500 (Thu, 06 Nov 2014) | 2 lines Rename sleep.c to nanosleep.c since that's what it is ------------------------------------------------------------------------ r2258 | adk0212 | 2014-11-06 16:28:45 -0500 (Thu, 06 Nov 2014) | 2 lines Remove unused file ------------------------------------------------------------------------ r2257 | adk0212 | 2014-11-06 16:26:32 -0500 (Thu, 06 Nov 2014) | 2 lines gethostbyname is in winsock2.h on win32, so netdb.h is yet another alias for winsock2.h ------------------------------------------------------------------------ r2256 | adk0212 | 2014-11-06 16:25:54 -0500 (Thu, 06 Nov 2014) | 2 lines Remove more unused win32/compat headers ------------------------------------------------------------------------ r2255 | adk0212 | 2014-11-06 16:11:50 -0500 (Thu, 06 Nov 2014) | 2 lines Remove unused compat/features.h ------------------------------------------------------------------------ r2254 | adk0212 | 2014-11-06 16:10:55 -0500 (Thu, 06 Nov 2014) | 2 lines Remove unused compat/grp.h ------------------------------------------------------------------------ r2253 | adk0212 | 2014-11-06 16:09:19 -0500 (Thu, 06 Nov 2014) | 2 lines Rename netcompat.c -> inet_aton.c since that's the only thing in it now ------------------------------------------------------------------------ r2252 | adk0212 | 2014-11-06 16:06:50 -0500 (Thu, 06 Nov 2014) | 2 lines More win32 compat include file cleanup ------------------------------------------------------------------------ r2251 | adk0212 | 2014-11-06 15:50:07 -0500 (Thu, 06 Nov 2014) | 2 lines Move inet_aton() prototype to arpa/inet.h ------------------------------------------------------------------------ r2250 | adk0212 | 2014-11-06 15:31:45 -0500 (Thu, 06 Nov 2014) | 2 lines Remove obsolete manually-written config.h for win32 builds ------------------------------------------------------------------------ r2249 | adk0212 | 2014-11-05 10:45:28 -0500 (Wed, 05 Nov 2014) | 2 lines List libwin32compat.a as a dependency so exes are relinked when it changes ------------------------------------------------------------------------ r2248 | adk0212 | 2014-11-05 10:32:56 -0500 (Wed, 05 Nov 2014) | 2 lines Remove USBTYPE define; it is not longer used ------------------------------------------------------------------------ r2247 | adk0212 | 2014-11-05 10:28:16 -0500 (Wed, 05 Nov 2014) | 6 lines Big win32 compat cleanup - Eliminate unnecessary compat functions - Split useful functions out into individual files to reduce linking of unnecessary compats - Move prototypes and defines to proper header files instead of jamming them all in compat.h - Remove 90% of the includes from compat.h ------------------------------------------------------------------------ r2246 | adk0212 | 2014-11-04 21:06:09 -0500 (Tue, 04 Nov 2014) | 2 lines Make bind_upses() a no-op if USBDEVFS_CONNECT is not available ------------------------------------------------------------------------ r2245 | adk0212 | 2014-11-04 20:58:45 -0500 (Tue, 04 Nov 2014) | 3 lines Eliminate use of sprintf in digest2ascii Code was fine but audits for sprintf keep tripping here so change it ------------------------------------------------------------------------ r2244 | adk0212 | 2014-11-04 20:56:46 -0500 (Tue, 04 Nov 2014) | 3 lines Rewrite hex_dump to make it clearer that no buffers are being overrun here. Audits for uses of sprintf and strcpy keep tripping over this code, so give in and change it even though there is no bug. ------------------------------------------------------------------------ r2243 | adk0212 | 2014-11-04 18:49:24 -0500 (Tue, 04 Nov 2014) | 2 lines Quiet warning from insufficiently clueful compiler ------------------------------------------------------------------------ r2242 | adk0212 | 2014-11-04 18:47:16 -0500 (Tue, 04 Nov 2014) | 2 lines Braces initializer on struct sigaction is not portable, use memset instead ------------------------------------------------------------------------ r2241 | adk0212 | 2014-11-04 16:54:07 -0500 (Tue, 04 Nov 2014) | 2 lines Remove executable property from Makefile ------------------------------------------------------------------------ r2240 | adk0212 | 2014-11-04 16:17:53 -0500 (Tue, 04 Nov 2014) | 2 lines Remove hiddex.txt as this is an obsolete copy from Linux docs ------------------------------------------------------------------------ r2239 | adk0212 | 2014-11-04 16:13:06 -0500 (Tue, 04 Nov 2014) | 2 lines Exclude gapcmon with --enable-all when cross-building for mingw32 ------------------------------------------------------------------------ r2238 | adk0212 | 2014-11-04 16:02:15 -0500 (Tue, 04 Nov 2014) | 2 lines Fix TOPDIR ------------------------------------------------------------------------ r2237 | adk0212 | 2014-11-04 15:36:35 -0500 (Tue, 04 Nov 2014) | 2 lines Move build-win32-cross-tools script to platforms/mingw ------------------------------------------------------------------------ r2236 | adk0212 | 2014-11-04 15:35:24 -0500 (Tue, 04 Nov 2014) | 2 lines Kill off the old win32 Makefile.in ... Yay! ------------------------------------------------------------------------ r2235 | adk0212 | 2014-11-04 15:34:00 -0500 (Tue, 04 Nov 2014) | 2 lines Remove obsolete readme ------------------------------------------------------------------------ r2234 | adk0212 | 2014-11-04 15:27:08 -0500 (Tue, 04 Nov 2014) | 2 lines Move win32 install package creation to platforms/mingw similar to how OS X is done and update for new file locations ------------------------------------------------------------------------ r2233 | adk0212 | 2014-11-04 14:34:52 -0500 (Tue, 04 Nov 2014) | 3 lines Test for dir existence before blindly adding /usr/local paths to {CPP,LD}FLAGS Darwin LLVM ld complains about non-existent lib directories on the command line ------------------------------------------------------------------------ r2232 | adk0212 | 2014-11-04 14:25:05 -0500 (Tue, 04 Nov 2014) | 2 lines Rebuild configure to incorporate BG variable for win32 background mode processes ------------------------------------------------------------------------ r2231 | adk0212 | 2014-11-04 14:17:43 -0500 (Tue, 04 Nov 2014) | 6 lines Ability to build for win32 via normal make system instead of hardcoded src/win32/Makefile.in Planned to do this many years ago, finally done! Windows build is enabled via normal autoconf cross-compile "./configure --host=mingw32". During configure, CROSSTOOLS env var selects location of mingw32 toolchain (built via build-win32-cross-tools script), default is $(topdir)/../cross-tools Similarly, DEPKGS var points to win32 dependency package directory, default is $(topdir)/../depkgs-win32 ------------------------------------------------------------------------ r2230 | adk0212 | 2014-11-04 08:30:37 -0500 (Tue, 04 Nov 2014) | 2 lines Eliminate apc_config.h by pulling useful pieces into defines.h ------------------------------------------------------------------------ r2229 | adk0212 | 2014-11-04 08:12:56 -0500 (Tue, 04 Nov 2014) | 3 lines Rename config.h to apcconfig.h since config.h is dangerously vague. Win32 pthreads, for example, provides a config.h. ------------------------------------------------------------------------ r2228 | adk0212 | 2014-11-04 07:41:35 -0500 (Tue, 04 Nov 2014) | 2 lines More warning fixes for win32 builds ------------------------------------------------------------------------ r2227 | adk0212 | 2014-11-04 07:19:09 -0500 (Tue, 04 Nov 2014) | 3 lines CID74720 Uninitialized scalar field Initialize _fd to INVALID_SOCKET ------------------------------------------------------------------------ r2226 | adk0212 | 2014-11-03 22:26:04 -0500 (Mon, 03 Nov 2014) | 3 lines Remove unused and buggy strncasecmp() function Remove unused variable from conv_unix_to_win32_path() ------------------------------------------------------------------------ r2225 | adk0212 | 2014-11-03 22:12:11 -0500 (Mon, 03 Nov 2014) | 2 lines Fix strict alising issue in apclibnis by implementing FIONBIO ioctl in compat instead of using macro ------------------------------------------------------------------------ r2224 | adk0212 | 2014-11-03 21:44:54 -0500 (Mon, 03 Nov 2014) | 3 lines Replace use of 'int' as socket type with sock_t, which maps to 'SOCKET' on Windows and 'int' everywhere else. Also use INVALID_SOCKET instead of -1 for socket failure case. This fixes a bunch of warnings on Windows. ------------------------------------------------------------------------ r2223 | adk0212 | 2014-11-03 21:18:56 -0500 (Mon, 03 Nov 2014) | 3 lines Fix a few warnings when building for win32 Many more to go... ------------------------------------------------------------------------ r2222 | adk0212 | 2014-11-03 17:35:36 -0500 (Mon, 03 Nov 2014) | 2 lines Add ------------------------------------------------------------------------ r2221 | adk0212 | 2014-11-03 17:33:22 -0500 (Mon, 03 Nov 2014) | 2 lines Change balloonmgr to use alib containers instead of STL ------------------------------------------------------------------------ r2220 | adk0212 | 2014-11-03 09:54:57 -0500 (Mon, 03 Nov 2014) | 2 lines Remove unnecessary header overrides; mingw versions are fine ------------------------------------------------------------------------ r2219 | adk0212 | 2014-11-03 09:47:55 -0500 (Mon, 03 Nov 2014) | 2 lines Remove stat replacement; mingw stat seems fine ------------------------------------------------------------------------ r2218 | adk0212 | 2014-11-03 09:32:31 -0500 (Mon, 03 Nov 2014) | 2 lines Remove manual definition of integer types; mingw provides ------------------------------------------------------------------------ r2217 | adk0212 | 2014-11-02 21:55:34 -0500 (Sun, 02 Nov 2014) | 2 lines Remove obsolete SHM_RDONLY define ------------------------------------------------------------------------ r2216 | adk0212 | 2014-11-02 21:54:38 -0500 (Sun, 02 Nov 2014) | 2 lines Use strlcpy for strftime replacement instead of strncpy ------------------------------------------------------------------------ r2215 | adk0212 | 2014-10-30 10:35:35 -0400 (Thu, 30 Oct 2014) | 2 lines Disable PCNET TIMELEFT workaround, causing breakage on recent UPSes ------------------------------------------------------------------------ r2214 | adk0212 | 2014-10-28 14:17:23 -0400 (Tue, 28 Oct 2014) | 3 lines Fix installation on older Mac OS X versions Apparently the deprecated auth= attribute is needed on these systems ------------------------------------------------------------------------ r2213 | adk0212 | 2014-10-28 13:04:05 -0400 (Tue, 28 Oct 2014) | 2 lines First pass at application and package signing for Mac OS X ------------------------------------------------------------------------ r2212 | adk0212 | 2014-10-27 18:46:12 -0400 (Mon, 27 Oct 2014) | 2 lines Update copyright ------------------------------------------------------------------------ r2211 | adk0212 | 2014-10-27 18:24:35 -0400 (Mon, 27 Oct 2014) | 2 lines Remove file used by old PackageMaker scripts ------------------------------------------------------------------------ r2210 | adk0212 | 2014-10-27 18:22:43 -0400 (Mon, 27 Oct 2014) | 2 lines Updates for packaging using pkgbuild and productbuild instead of deprecated PackageMaker ------------------------------------------------------------------------ r2209 | adk0212 | 2014-10-27 11:46:19 -0400 (Mon, 27 Oct 2014) | 2 lines Update Mac OS X build notes for newer dev tools and packages ------------------------------------------------------------------------ r2208 | adk0212 | 2014-10-27 11:37:20 -0400 (Mon, 27 Oct 2014) | 2 lines Add patch for libusb-0.1.12 on newer Xcode tools ------------------------------------------------------------------------ r2207 | adk0212 | 2014-10-27 10:32:43 -0400 (Mon, 27 Oct 2014) | 2 lines Remove Growl plist ------------------------------------------------------------------------ r2206 | adk0212 | 2014-10-27 10:23:15 -0400 (Mon, 27 Oct 2014) | 2 lines Remove Growl references in config window, hide notification enable checkbox when Notification Center is not available ------------------------------------------------------------------------ r2205 | adk0212 | 2014-10-27 09:59:45 -0400 (Mon, 27 Oct 2014) | 6 lines More validation improvements and code cleanup Rename BetterNumberFormatter to ActiveNumberFormatter Split ActiveNumberFormatter out into its own file Fail validation if any field is blank Switch input focus to the first blank control to give the user a clue as to why we refused to close the window ------------------------------------------------------------------------ r2204 | adk0212 | 2014-10-26 22:44:24 -0400 (Sun, 26 Oct 2014) | 2 lines Clean up preferences validation; cell background coloring was not working right on newer systems ------------------------------------------------------------------------ r2203 | adk0212 | 2014-10-26 20:49:59 -0400 (Sun, 26 Oct 2014) | 2 lines Check in the built NIB file to allow compiling apcagent with older XCode tools ------------------------------------------------------------------------ r2202 | adk0212 | 2014-10-26 18:18:28 -0400 (Sun, 26 Oct 2014) | 3 lines Fix issue with config 'port' field displaying with thousands separator when built with newer XCode tools Attach a NSNumberFormatter to the config port cell and set it for no formatting ------------------------------------------------------------------------ r2201 | adk0212 | 2014-10-26 17:15:21 -0400 (Sun, 26 Oct 2014) | 2 lines Add comments ------------------------------------------------------------------------ r2200 | adk0212 | 2014-10-26 17:12:36 -0400 (Sun, 26 Oct 2014) | 2 lines NSMenuDelete and NSUserNotificationCenterDelegate did not exist until 10.6 and 10.8, respectively ------------------------------------------------------------------------ r2199 | adk0212 | 2014-10-26 17:06:27 -0400 (Sun, 26 Oct 2014) | 4 lines First pass at Notification Center support for apcagent Little rough still, but working All the ifdefs to allow compiling with pre-10.8 SDKs is annoying ------------------------------------------------------------------------ r2198 | adk0212 | 2014-10-26 15:27:50 -0400 (Sun, 26 Oct 2014) | 3 lines Fix bug in getLoginItem() which caused crashes on 10.5 url is not written when LSSharedFileListItemResolve fails, need to set it to nil each time ------------------------------------------------------------------------ r2197 | adk0212 | 2014-10-26 15:25:53 -0400 (Sun, 26 Oct 2014) | 2 lines Use numeric values instead of macros for OS X version checking so that we can successfully build when the SDK predates the version being tested for ------------------------------------------------------------------------ r2196 | adk0212 | 2014-10-24 15:42:48 -0400 (Fri, 24 Oct 2014) | 3 lines Prefer instantiateWithOwner over instantiateNibWithOwner which was deprecated in 10.8 This makes memory management of the NIB top level object array cleaner ------------------------------------------------------------------------ r2195 | adk0212 | 2014-10-24 13:58:14 -0400 (Fri, 24 Oct 2014) | 2 lines Prefer LSSharedFileListItemCopyResolvedURL over deprecated LSSharedFileListItemResolve when deployment target allows ------------------------------------------------------------------------ r2194 | adk0212 | 2014-10-23 21:32:38 -0400 (Thu, 23 Oct 2014) | 3 lines Kill off LoginItemsAE (login item management via Apple Events) in favor of LSSharedFileList API This is good on 10.5 and higher, so 10.4 support is now formally dropped (and PPC along with it) ------------------------------------------------------------------------ r2193 | adk0212 | 2014-10-22 11:59:06 -0400 (Wed, 22 Oct 2014) | 3 lines Remove Growl support from apcagent Will be adding Notification Center support to replace Growl ------------------------------------------------------------------------ r2192 | adk0212 | 2014-10-22 09:28:46 -0400 (Wed, 22 Oct 2014) | 2 lines CID17181,17182 Argument cannot be negative ------------------------------------------------------------------------ r2191 | adk0212 | 2014-10-21 22:37:29 -0400 (Tue, 21 Oct 2014) | 4 lines CID17162 Dereference after null check Only an issue if CI_STATUS were not in the CiInfo table. But this is unnecessary code anyway, so remove it. ------------------------------------------------------------------------ r2190 | adk0212 | 2014-10-21 22:30:44 -0400 (Tue, 21 Oct 2014) | 3 lines CID17184 Out-of-bounds access (again) Another attempt to address this non-issue in a way that makes it clear to Coverity that there is no buffer overrun ------------------------------------------------------------------------ r2189 | adk0212 | 2014-10-21 22:09:20 -0400 (Tue, 21 Oct 2014) | 4 lines CID74325 Unchecked return value from library Document why we're setting SO_BROADCAST and why we don't care if it fails. Cast return to void to indicate that we don't care about return value. ------------------------------------------------------------------------ r2188 | adk0212 | 2014-10-21 16:40:23 -0400 (Tue, 21 Oct 2014) | 2 lines Remove obsolete POWERFLUTE and POWERLIBS definitions ------------------------------------------------------------------------ r2187 | adk0212 | 2014-10-21 16:29:34 -0400 (Tue, 21 Oct 2014) | 3 lines Be explicit about invoking compiler with C++ language Fixes warnings from clang ------------------------------------------------------------------------ r2186 | adk0212 | 2014-10-21 16:22:20 -0400 (Tue, 21 Oct 2014) | 2 lines Fix forward decl ------------------------------------------------------------------------ r2185 | adk0212 | 2014-10-21 15:10:59 -0400 (Tue, 21 Oct 2014) | 3 lines Remove StartupItems scripts for OS X launchd is supported as far back as 10.4, so no reason to keep StartupItems stuff around ------------------------------------------------------------------------ r2184 | adk0212 | 2014-10-21 14:59:18 -0400 (Tue, 21 Oct 2014) | 2 lines Update Darwin installer welcome text for new email list URL ------------------------------------------------------------------------ r2183 | adk0212 | 2014-10-21 14:44:15 -0400 (Tue, 21 Oct 2014) | 2 lines Update coverity model to mark error_out_wrapper() as no-return. ------------------------------------------------------------------------ r2182 | adk0212 | 2014-10-21 14:41:44 -0400 (Tue, 21 Oct 2014) | 2 lines Wrap calls to error_out function pointer in actual function that can be modeled in Coverity as no-return. This should clean up a number of false positives in Coverity. ------------------------------------------------------------------------ r2181 | adk0212 | 2014-10-21 14:32:46 -0400 (Tue, 21 Oct 2014) | 2 lines Kill off error_exit. It was identical to error_out except didn't have line number and there was only one user (apcconfig). Switch apcconfig over to error_out and remove error_exit. ------------------------------------------------------------------------ r2180 | adk0212 | 2014-10-21 12:09:41 -0400 (Tue, 21 Oct 2014) | 2 lines Tie OS X launchd setup into install and uninstall ------------------------------------------------------------------------ r2179 | adk0212 | 2014-10-21 11:27:20 -0400 (Tue, 21 Oct 2014) | 3 lines Add launchd startup files for OS X Not tied into 'make install' yet but functional if manually installed ------------------------------------------------------------------------ r2178 | adk0212 | 2014-10-21 04:11:51 -0400 (Tue, 21 Oct 2014) | 2 lines CID17183 Array compared against 0 ------------------------------------------------------------------------ r2177 | adk0212 | 2014-10-21 00:10:53 -0400 (Tue, 21 Oct 2014) | 3 lines Fix apcaccess failure when apcupsd.conf does not supply NISIP. Reported by David Walser ------------------------------------------------------------------------ r2176 | adk0212 | 2014-10-20 23:58:46 -0400 (Mon, 20 Oct 2014) | 4 lines Fix errant 'fi' in Mandrake script Reported by Graeme Gemmill Patch by David Walser ------------------------------------------------------------------------ r2175 | adk0212 | 2014-10-20 23:40:33 -0400 (Mon, 20 Oct 2014) | 8 lines Make another attempt to fix startup/shutdown log level issues. LOG_INFO is the obvious level to use, but as trev@sentry.org pointed out in a fix a few years back, LOG_INFO is reserved for apcupsd data logging and is not allowed thru the normal event log (syslog) mechanism. LOG_WARN will make it thru but is too high a level, especially on Windows. Using LOG_NOTICE should work; it's lower than WARN (and, importantly, maps to INFORMATION type on Windows) but it is higher than INFO and therefore will make it thru to syslog. ------------------------------------------------------------------------ r2174 | adk0212 | 2014-10-20 23:13:50 -0400 (Mon, 20 Oct 2014) | 3 lines Fix log level of apcupsd startup message: should be INFO not WARN Reported by marvin@cbr125world.com ------------------------------------------------------------------------ r2173 | adk0212 | 2014-10-17 23:14:48 -0400 (Fri, 17 Oct 2014) | 2 lines Update manual with license info for apcupsd itself as well as libusbhid ------------------------------------------------------------------------ r2172 | adk0212 | 2014-10-17 21:22:05 -0400 (Fri, 17 Oct 2014) | 2 lines linux/usb/ch9.h does not exist on all distros...let's just define the device descriptor struct ourselves ------------------------------------------------------------------------ r2171 | adk0212 | 2014-10-17 21:06:23 -0400 (Fri, 17 Oct 2014) | 2 lines Remove unnecessary assignment ------------------------------------------------------------------------ r2170 | adk0212 | 2014-10-17 18:24:18 -0400 (Fri, 17 Oct 2014) | 2 lines Cleanup ------------------------------------------------------------------------ r2169 | adk0212 | 2014-10-17 18:21:21 -0400 (Fri, 17 Oct 2014) | 2 lines On Linux, attempt to automatically attach USB UPSes to the kernel usbhid/hiddev driver in case they have been detached from it (typically due to running the apcupsd 'generic' USB driver) ------------------------------------------------------------------------ r2168 | adk0212 | 2014-10-16 22:28:17 -0400 (Thu, 16 Oct 2014) | 2 lines Fix remaining compiler warnings in hid-ups.c ------------------------------------------------------------------------ r2167 | adk0212 | 2014-10-16 21:56:08 -0400 (Thu, 16 Oct 2014) | 2 lines Fix the majority of the compiler warning flood in hid-ups.c ------------------------------------------------------------------------ r2166 | adk0212 | 2014-10-16 21:48:17 -0400 (Thu, 16 Oct 2014) | 2 lines Correct units on PresentStatus usage ------------------------------------------------------------------------ r2165 | adk0212 | 2014-10-16 21:46:45 -0400 (Thu, 16 Oct 2014) | 2 lines Convert tabs to spaces ------------------------------------------------------------------------ r2164 | adk0212 | 2014-10-16 21:42:13 -0400 (Thu, 16 Oct 2014) | 2 lines Show logical usage for each field and add the PresentStatus standard usage ------------------------------------------------------------------------ r2163 | adk0212 | 2014-10-16 21:14:58 -0400 (Thu, 16 Oct 2014) | 2 lines Add MODBUS RTU Tx/Rx usages to hid-ups ------------------------------------------------------------------------ r2162 | adk0212 | 2014-10-15 22:03:28 -0400 (Wed, 15 Oct 2014) | 2 lines Update AN176 ------------------------------------------------------------------------ r2161 | adk0212 | 2014-10-14 17:10:25 -0400 (Tue, 14 Oct 2014) | 3 lines Add SYSADMIN and APCUPSD_MAIL setting to apccontrol scripts that were missing it h/t Quick Fox ------------------------------------------------------------------------ r2160 | adk0212 | 2014-10-13 19:42:41 -0400 (Mon, 13 Oct 2014) | 3 lines Fix possible use of uninitialized data in line[] buffer in handle_client_request() - Issue reported by Kevin Cernekee ------------------------------------------------------------------------ r2159 | adk0212 | 2014-10-13 19:18:23 -0400 (Mon, 13 Oct 2014) | 3 lines pktsiz should be unsigned (h/t Kevin Cernekee ) - Same as Kevin's patch plus change sizeof idiom ------------------------------------------------------------------------ r2158 | adk0212 | 2014-05-15 13:39:13 -0400 (Thu, 15 May 2014) | 3 lines Fix apcaccess on (broken!) systems where -funsigned-char is the default behavior Reported by Patrick Fallberg ------------------------------------------------------------------------ r2157 | adk0212 | 2014-04-20 16:36:29 -0400 (Sun, 20 Apr 2014) | 2 lines Populate some additional columns in Windows Programs & Features control panel ------------------------------------------------------------------------ r2156 | adk0212 | 2014-04-20 16:14:52 -0400 (Sun, 20 Apr 2014) | 2 lines V_UNKNOWN conflicts with win32 headers, as does V_NONE. V_DEFAULT it is, then. ------------------------------------------------------------------------ r2155 | adk0212 | 2014-04-09 18:18:29 -0400 (Wed, 09 Apr 2014) | 2 lines Remove unused script ------------------------------------------------------------------------ r2154 | adk0212 | 2014-04-09 18:15:34 -0400 (Wed, 09 Apr 2014) | 2 lines More svn:executable property removals ------------------------------------------------------------------------ r2153 | adk0212 | 2014-04-09 14:25:05 -0400 (Wed, 09 Apr 2014) | 2 lines Remove a few more unnecessary svn:executable properties ------------------------------------------------------------------------ r2152 | adk0212 | 2014-04-09 14:20:29 -0400 (Wed, 09 Apr 2014) | 3 lines Remove svn:executable property from many files that have no reason to be executable Most of these are an artifact of creating new files remotely via samba share ------------------------------------------------------------------------ r2151 | adk0212 | 2014-04-09 14:04:46 -0400 (Wed, 09 Apr 2014) | 3 lines Add model file for Coverity Currently models error_out as static analysis can't tell error_out fnptr is plumbed thru to something that does exit(2) ------------------------------------------------------------------------ r2150 | adk0212 | 2014-04-09 13:57:57 -0400 (Wed, 09 Apr 2014) | 2 lines Use variadic macro for Error_abort ------------------------------------------------------------------------ r2149 | adk0212 | 2014-04-09 12:26:42 -0400 (Wed, 09 Apr 2014) | 5 lines CID 17184: Out-of-bounds access Not really...unnecessary bounds check on 'n' is making Coverity believe n could be >= sizeof(buf) In reality, n is limited to 0 < n < sizeof(buf) due to net_recv(..., sizeof(buf)-1) Eliminate unnecessary bounds check on 'n' ------------------------------------------------------------------------ r2148 | adk0212 | 2014-04-09 12:18:09 -0400 (Wed, 09 Apr 2014) | 3 lines CID 17187: String not null terminated Missed the temp == 0 case ------------------------------------------------------------------------ r2147 | adk0212 | 2014-04-09 12:09:58 -0400 (Wed, 09 Apr 2014) | 4 lines Filter out bogus ITEMP readings from SNMP Error is on APC side, we will work around in apcupsd Reported by Sergey ------------------------------------------------------------------------ r2146 | adk0212 | 2014-04-06 12:21:40 -0400 (Sun, 06 Apr 2014) | 4 lines CID 17187: String not null terminated String was not being NUL terminated in the event of exactly filling the buffer Rearrange loop to NUL terminate on every iteration and remove unnecessary memset ------------------------------------------------------------------------ r2145 | adk0212 | 2014-04-06 12:13:30 -0400 (Sun, 06 Apr 2014) | 3 lines CID 17189: Uninitialized scalar variable Properly initialize all fields of struct sigaction ------------------------------------------------------------------------ r2144 | adk0212 | 2014-04-06 12:10:10 -0400 (Sun, 06 Apr 2014) | 3 lines CID 17190: Uninitialized scalar variable Give s_usb_value a constructor to reset fields to sane values ------------------------------------------------------------------------ r2143 | adk0212 | 2014-04-06 11:40:11 -0400 (Sun, 06 Apr 2014) | 3 lines CID 17198: Double free Fix clear() and Append() to avoid potential double-free ------------------------------------------------------------------------ r2142 | adk0212 | 2014-04-06 11:32:58 -0400 (Sun, 06 Apr 2014) | 3 lines CID 17139: Buffer not null terminated Change strncpy to strlcpy ------------------------------------------------------------------------ r2141 | adk0212 | 2014-04-06 11:20:20 -0400 (Sun, 06 Apr 2014) | 3 lines CID 17186: Resource leak Close sockfd when returning early ------------------------------------------------------------------------ r2140 | adk0212 | 2014-04-06 11:07:02 -0400 (Sun, 06 Apr 2014) | 6 lines CID 17199: Double free (not really) Coverity thinks we have a double free because it doesn't realize Error_abort never returns However we can easily rearrange the code to make it clearer (even to a human) Also there is no reason to exit the process on a soft error; just notify client and close connection Misc other cleanup in the same function ------------------------------------------------------------------------ r2139 | adk0212 | 2014-04-05 20:18:14 -0400 (Sat, 05 Apr 2014) | 2 lines Update my email address globally ------------------------------------------------------------------------ r2138 | adk0212 | 2014-04-05 19:00:20 -0400 (Sat, 05 Apr 2014) | 2 lines Remove ancient Linux kernel hiddev patches ------------------------------------------------------------------------ r2137 | adk0212 | 2014-04-05 18:40:59 -0400 (Sat, 05 Apr 2014) | 2 lines Remove empty dirs ------------------------------------------------------------------------ r2136 | adk0212 | 2014-04-05 18:14:17 -0400 (Sat, 05 Apr 2014) | 2 lines Add my copyright to configure.in as I've definitely played with it enough now to justify it ------------------------------------------------------------------------ r2135 | adk0212 | 2014-04-05 18:12:23 -0400 (Sat, 05 Apr 2014) | 2 lines Remove old todo list ------------------------------------------------------------------------ r2134 | adk0212 | 2014-04-05 15:21:37 -0400 (Sat, 05 Apr 2014) | 2 lines Remove unused script ------------------------------------------------------------------------ r2133 | adk0212 | 2014-04-05 15:20:12 -0400 (Sat, 05 Apr 2014) | 2 lines Run autoheader automatically when running autoconf ------------------------------------------------------------------------ r2132 | adk0212 | 2014-04-05 15:19:31 -0400 (Sat, 05 Apr 2014) | 5 lines Autoconf cleanup - Add description info to AC_DEFINEs (replaces acconfig.h) - Regen config.h.in using autoheader - Misc other cleanup ------------------------------------------------------------------------ r2131 | adk0212 | 2014-04-01 23:44:52 -0400 (Tue, 01 Apr 2014) | 2 lines Update config.guess, config.sub to latest from git.savannah.gnu.org ------------------------------------------------------------------------ r2130 | adk0212 | 2014-04-01 23:41:40 -0400 (Tue, 01 Apr 2014) | 2 lines Remove some unused scripts ------------------------------------------------------------------------ r2129 | adk0212 | 2014-03-31 11:47:46 -0400 (Mon, 31 Mar 2014) | 2 lines Remove old static web site ------------------------------------------------------------------------ r2128 | adk0212 | 2014-03-30 10:55:19 -0400 (Sun, 30 Mar 2014) | 3 lines Remove debug print of ASN types This code is pretty thoroughly tested at this point, debug is no longer necessary ------------------------------------------------------------------------ r2124 | adk0212 | 2014-03-28 23:51:10 -0400 (Fri, 28 Mar 2014) | 2 lines Prep for 3.14.12 release ------------------------------------------------------------------------ r2123 | adk0212 | 2014-03-28 23:36:33 -0400 (Fri, 28 Mar 2014) | 2 lines Remove reference to CHARGING as possible STATUS output ------------------------------------------------------------------------ r2122 | adk0212 | 2014-03-28 22:51:54 -0400 (Fri, 28 Mar 2014) | 3 lines Remove value normalization from apcaccess and eliminate -u dependency on -p (again) apcupsd will no longer zero-pad values so normalization is unnecessary ------------------------------------------------------------------------ r2121 | adk0212 | 2014-03-28 22:51:02 -0400 (Fri, 28 Mar 2014) | 3 lines Remove field width specifiers to eliminate space- and zero-padding This makes parsing status output easier for scripts at a very small cost to human readability ------------------------------------------------------------------------ r2120 | adk0212 | 2014-03-28 22:31:45 -0400 (Fri, 28 Mar 2014) | 3 lines Workaround for UPS firmware bug causing killpower to execute repeatedly in a loop Thanks to Neil Robinson for very clearly documenting the issue and running many, many tests to help track down a solution. ------------------------------------------------------------------------ r2119 | adk0212 | 2014-03-28 17:08:28 -0400 (Fri, 28 Mar 2014) | 3 lines Make apcaccess -u dependent on -p again but with a runtime check to fail if user violates this dependency. Man page update for the same. ------------------------------------------------------------------------ r2118 | adk0212 | 2014-03-28 16:14:29 -0400 (Fri, 28 Mar 2014) | 3 lines Update apcaccess man page From Timothe Litt ------------------------------------------------------------------------ r2117 | adk0212 | 2014-03-28 16:02:05 -0400 (Fri, 28 Mar 2014) | 2 lines Improve usage info, fix comment ------------------------------------------------------------------------ r2116 | adk0212 | 2014-03-28 15:17:14 -0400 (Fri, 28 Mar 2014) | 2 lines Use strtok() as strtok_r() on MinGW ------------------------------------------------------------------------ r2115 | adk0212 | 2014-03-28 14:41:26 -0400 (Fri, 28 Mar 2014) | 3 lines Move leading zero suppression to -p handler instead of -u Also allow solitary 0 to pass unaffected ------------------------------------------------------------------------ r2114 | adk0212 | 2014-03-28 14:10:59 -0400 (Fri, 28 Mar 2014) | 3 lines Add support for stripping units off of values From Timothe Litt , modified a little ------------------------------------------------------------------------ r2113 | adk0212 | 2014-03-28 13:42:07 -0400 (Fri, 28 Mar 2014) | 2 lines Fix apcupsd.conf NISIP overriding command line -h in apcaccess ------------------------------------------------------------------------ r2112 | adk0212 | 2014-03-28 13:08:29 -0400 (Fri, 28 Mar 2014) | 3 lines Command line should override config file settings From Timothe Litt ------------------------------------------------------------------------ r2111 | adk0212 | 2014-03-28 13:04:20 -0400 (Fri, 28 Mar 2014) | 4 lines Status output "units" cleanup Eliminate unnecessary text after values where that text is redundant with the field name Regularize names of units to use same capitalization ------------------------------------------------------------------------ r2110 | adk0212 | 2014-03-27 22:36:41 -0400 (Thu, 27 Mar 2014) | 4 lines Add support for pattern matching and apcupsd.conf parsing in apcaccess Also some code cleanup. Idea and most of the code courtesty of Timothe Litt ------------------------------------------------------------------------ r2109 | adk0212 | 2014-03-26 19:01:57 -0400 (Wed, 26 Mar 2014) | 2 lines Firmware rev usages are string indices ------------------------------------------------------------------------ r2108 | adk0212 | 2014-03-24 23:03:25 -0400 (Mon, 24 Mar 2014) | 2 lines Add usb_release_interface stub now that generic USB driver needs it ------------------------------------------------------------------------ r2107 | adk0212 | 2014-03-24 23:03:00 -0400 (Mon, 24 Mar 2014) | 2 lines One last astrncpy conversion ------------------------------------------------------------------------ r2106 | adk0212 | 2014-03-24 22:55:41 -0400 (Mon, 24 Mar 2014) | 3 lines Global replace of atrncat with strlcat All uses of astrncat were incorrect (passing full buffer size instead of remaining size as limit) ------------------------------------------------------------------------ r2105 | adk0212 | 2014-03-24 22:52:10 -0400 (Mon, 24 Mar 2014) | 3 lines Global replace of astrcpy with strlcpy Same behavor (aside from return value) but strlcpy is standardized ------------------------------------------------------------------------ r2104 | adk0212 | 2014-03-24 22:47:47 -0400 (Mon, 24 Mar 2014) | 4 lines Fix misuse of astrncat in apcstatus by replacing with strlcat strlcpy/strlcat implemented internally if libc does not provide Thanks to Timothe Litt for pointing out this long-standing error ------------------------------------------------------------------------ r2103 | adk0212 | 2014-03-22 13:06:22 -0400 (Sat, 22 Mar 2014) | 2 lines Update udev info in manual with tips from Timothe Litt ------------------------------------------------------------------------ r2102 | adk0212 | 2014-03-22 12:55:26 -0400 (Sat, 22 Mar 2014) | 3 lines Add UPS name to subject line of event emails and allow one-stop override of SYSADMIN and APCUPSD_MAIL via config file in SCRIPTDIR Contributed by Timothe Litt ------------------------------------------------------------------------ r2101 | adk0212 | 2014-03-22 12:47:53 -0400 (Sat, 22 Mar 2014) | 4 lines Fix compiler warning Implicit narrowing within {} is not allowed in C++11 h/t Timothe Litt ------------------------------------------------------------------------ r2100 | adk0212 | 2014-03-22 12:34:18 -0400 (Sat, 22 Mar 2014) | 3 lines Remove references to --with-css-dir configure option This option hasn't existed since 2004 ------------------------------------------------------------------------ r2099 | adk0212 | 2014-03-22 12:27:55 -0400 (Sat, 22 Mar 2014) | 3 lines Fix display of battery level during MODBUS calibration (h/t Timothe Litt for pointing out the compiler warning that indicated an issue here.) ------------------------------------------------------------------------ r2098 | adk0212 | 2014-03-08 10:57:56 -0500 (Sat, 08 Mar 2014) | 2 lines Update some URLs (h/t Ted Mittelstaedt ) ------------------------------------------------------------------------ r2097 | adk0212 | 2014-02-26 10:08:09 -0500 (Wed, 26 Feb 2014) | 2 lines Fix driver program_eeprom() and entry_point() function naming ------------------------------------------------------------------------ r2096 | adk0212 | 2014-02-18 14:36:51 -0500 (Tue, 18 Feb 2014) | 2 lines Close and re-open serial port during extended COMMLOST in apcsmart driver ------------------------------------------------------------------------ r2095 | adk0212 | 2014-02-17 23:13:43 -0500 (Mon, 17 Feb 2014) | 2 lines Make COMMLOST_EVENT_GRACE_PERIOD of type time_t to quiet signed/unsigned comparison warnings ------------------------------------------------------------------------ r2094 | adk0212 | 2014-02-16 11:42:59 -0500 (Sun, 16 Feb 2014) | 2 lines Fix compilation with 10.4 SDK -- NSTableViewDataSource was not a formal protocol until 10.6 ------------------------------------------------------------------------ r2093 | adk0212 | 2014-02-16 11:29:26 -0500 (Sun, 16 Feb 2014) | 2 lines Fix indentation and comment on lastStatus ------------------------------------------------------------------------ r2092 | adk0212 | 2014-02-16 11:28:52 -0500 (Sun, 16 Feb 2014) | 3 lines Indicate that StatusTableDataSource and EventsTableDataSource adhere to the NSTableViewDataSource protocol This eliminates compiler warning about incompatible pointers when data source is passed to NSTableView ------------------------------------------------------------------------ r2091 | adk0212 | 2014-02-16 11:08:26 -0500 (Sun, 16 Feb 2014) | 4 lines Remove definition of bool/true/false for non-C++ environments Causes warnings in Objective C code since OBJC has bool Regular C should not be using bool and friends in the first place ------------------------------------------------------------------------ r2090 | adk0212 | 2014-02-15 21:03:01 -0500 (Sat, 15 Feb 2014) | 2 lines Replace deprecated stringWithCString with stringWithUTF8String ------------------------------------------------------------------------ r2089 | adk0212 | 2014-02-15 19:05:50 -0500 (Sat, 15 Feb 2014) | 3 lines Remove 'eprominfo' command Same information is available via 'status' along with a lot more ------------------------------------------------------------------------ r2088 | adk0212 | 2014-02-15 19:04:43 -0500 (Sat, 15 Feb 2014) | 4 lines Remove 'rawupsinfo' command This was useful many, many years ago when UPSINFO was a shmem structure Not so much any more. ------------------------------------------------------------------------ r2087 | adk0212 | 2014-02-15 19:02:20 -0500 (Sat, 15 Feb 2014) | 3 lines Remove techlogs - Interesting historical artifacts, but not something we need to keep shipping in every tarball ------------------------------------------------------------------------ r2086 | adk0212 | 2014-02-12 22:46:38 -0500 (Wed, 12 Feb 2014) | 2 lines Fix use of bool as integer in net driver ------------------------------------------------------------------------ r2085 | adk0212 | 2014-02-12 22:28:00 -0500 (Wed, 12 Feb 2014) | 2 lines int to bool cleanup in USB drivers ------------------------------------------------------------------------ r2084 | adk0212 | 2014-02-12 11:18:56 -0500 (Wed, 12 Feb 2014) | 2 lines Add section on NIS network protocol to the manual ------------------------------------------------------------------------ r2083 | adk0212 | 2014-02-10 21:40:00 -0500 (Mon, 10 Feb 2014) | 2 lines Remove unused MGE VID ------------------------------------------------------------------------ r2082 | adk0212 | 2014-02-10 21:39:42 -0500 (Mon, 10 Feb 2014) | 2 lines Avoid probing non-APC devices as they may not like it ------------------------------------------------------------------------ r2081 | adk0212 | 2014-02-10 21:25:47 -0500 (Mon, 10 Feb 2014) | 2 lines Release interface in generic usb driver when probe fails ------------------------------------------------------------------------ r2080 | adk0212 | 2014-02-09 19:25:31 -0500 (Sun, 09 Feb 2014) | 3 lines Fix spelling of 'exhausted' in apccontrol Contributed by Paul Keusemann ------------------------------------------------------------------------ r2079 | adk0212 | 2014-02-09 13:00:52 -0500 (Sun, 09 Feb 2014) | 6 lines Fix issue with service failing to start on Windows during boot with USB UPS - UPS is not found on USB bus until a little while after service starts up - Make USB driver Open method return failure instead of exiting the daemon - Treat Open failure as COMMLOST when starting up - Normal COMMLOST event is suppressed for 60 seconds to avoid needless log spam when UPS becomes available in short order ------------------------------------------------------------------------ r2078 | adk0212 | 2014-02-09 12:49:06 -0500 (Sun, 09 Feb 2014) | 2 lines Regen html manual with updated docutils ------------------------------------------------------------------------ r2077 | adk0212 | 2014-02-05 21:35:20 -0500 (Wed, 05 Feb 2014) | 2 lines Update the link to David Ranch's TrinityOS page ------------------------------------------------------------------------ r2076 | adk0212 | 2014-02-05 12:50:19 -0500 (Wed, 05 Feb 2014) | 2 lines Fix bogus lock file error when config file error forces early termination ------------------------------------------------------------------------ r2075 | adk0212 | 2014-02-04 22:22:42 -0500 (Tue, 04 Feb 2014) | 2 lines Fix spelling error in APC app note comment and clarify origin of app notes ------------------------------------------------------------------------ r2074 | adk0212 | 2014-02-04 22:16:42 -0500 (Tue, 04 Feb 2014) | 2 lines Update MODBUS NOMOUTV mapping for voltages other than 120VAC ------------------------------------------------------------------------ r2073 | adk0212 | 2014-02-04 09:51:54 -0500 (Tue, 04 Feb 2014) | 4 lines Fix LOADPCT (CI_LOAD) on MODBUS driver - Missing break on CI_LowBattery case caused us to fall through and overwrite CI_LOAD - Reported by Sash Ulrich ------------------------------------------------------------------------ r2072 | adk0212 | 2014-02-03 18:30:10 -0500 (Mon, 03 Feb 2014) | 2 lines Support rst2html in addition to rst2html.py ------------------------------------------------------------------------ r2071 | adk0212 | 2014-02-03 18:28:18 -0500 (Mon, 03 Feb 2014) | 2 lines Remove net-snmp from enable-all ------------------------------------------------------------------------ r2070 | adk0212 | 2014-02-01 12:53:59 -0500 (Sat, 01 Feb 2014) | 2 lines Test commit 2 ------------------------------------------------------------------------ r2069 | adk0212 | 2014-02-01 12:22:12 -0500 (Sat, 01 Feb 2014) | 2 lines Test commit ------------------------------------------------------------------------ r2068 | adk0212 | 2014-02-01 12:17:55 -0500 (Sat, 01 Feb 2014) | 3 lines Fix issue with net driver not reporting MODEL value Reported by Chris Dallimore ------------------------------------------------------------------------ r2067 | adk0212 | 2014-01-31 20:59:13 -0500 (Fri, 31 Jan 2014) | 2 lines Fix 3.14.11 info that got clobbered in last update ------------------------------------------------------------------------ r2066 | adk0212 | 2014-01-31 20:25:15 -0500 (Fri, 31 Jan 2014) | 2 lines Update web site with SVN link ------------------------------------------------------------------------ r2065 | adk0212 | 2014-01-31 11:52:13 -0500 (Fri, 31 Jan 2014) | 2 lines Update web site with 3.14.11 release info ------------------------------------------------------------------------ r2063 | adk0212 | 2014-01-31 10:45:36 -0500 (Fri, 31 Jan 2014) | 2 lines Update ChangeLog (again) ------------------------------------------------------------------------ r2062 | adk0212 | 2014-01-31 10:44:48 -0500 (Fri, 31 Jan 2014) | 2 lines Bump release date ------------------------------------------------------------------------ r2061 | adk0212 | 2014-01-31 10:43:24 -0500 (Fri, 31 Jan 2014) | 2 lines Update ReleaseNotes for 3.14.11 ------------------------------------------------------------------------ r2060 | adk0212 | 2014-01-31 10:33:38 -0500 (Fri, 31 Jan 2014) | 2 lines Minor update to win32 USB driver installation notes ------------------------------------------------------------------------ r2059 | adk0212 | 2014-01-29 17:58:16 -0500 (Wed, 29 Jan 2014) | 2 lines Final prep for 3.14.11 ------------------------------------------------------------------------ r2058 | adk0212 | 2014-01-29 17:56:36 -0500 (Wed, 29 Jan 2014) | 2 lines Add apcupsd.cat signature file to USB driver installation ------------------------------------------------------------------------ r2057 | adk0212 | 2014-01-29 17:54:21 -0500 (Wed, 29 Jan 2014) | 2 lines Commit signed winusb driver courtesy of Jernej Simoncic ------------------------------------------------------------------------ r2056 | adk0212 | 2013-11-20 19:14:12 -0500 (Wed, 20 Nov 2013) | 2 lines Update ChangeLog for 3.14.11 ------------------------------------------------------------------------ r2055 | adk0212 | 2013-11-20 19:13:31 -0500 (Wed, 20 Nov 2013) | 2 lines Update version info for 3.14.11 release ------------------------------------------------------------------------ r2054 | adk0212 | 2013-11-20 19:12:21 -0500 (Wed, 20 Nov 2013) | 2 lines Add modbus info to DEVICE section ------------------------------------------------------------------------ r2053 | adk0212 | 2013-11-20 19:08:50 -0500 (Wed, 20 Nov 2013) | 2 lines Add modbus information to the manual ------------------------------------------------------------------------ r2052 | adk0212 | 2013-11-20 18:28:13 -0500 (Wed, 20 Nov 2013) | 2 lines Update cached copy of AN176, add AN177, AN178 ------------------------------------------------------------------------ r2051 | adk0212 | 2013-11-20 18:21:31 -0500 (Wed, 20 Nov 2013) | 2 lines Add pointers to relevant APC app notes in modbus driver source files. ------------------------------------------------------------------------ r2050 | adk0212 | 2013-08-19 21:23:12 -0400 (Mon, 19 Aug 2013) | 4 lines Implement the modbus killpower test in apctest. Comment out the other modbus tests that are not implemented (due to lack of MODBUS mappings in the UPS for the relevant controls) ------------------------------------------------------------------------ r2049 | adk0212 | 2013-08-19 21:18:58 -0400 (Mon, 19 Aug 2013) | 3 lines Add current rev of App Note 176 (June 2013) describing the MODBUS implementation on APC UPSes ------------------------------------------------------------------------ r2048 | adk0212 | 2013-08-05 10:05:17 -0400 (Mon, 05 Aug 2013) | 2 lines Initial rev of MODBUS support ------------------------------------------------------------------------ r2047 | adk0212 | 2013-04-18 21:12:46 -0400 (Thu, 18 Apr 2013) | 2 lines Build fixes for gcc-4.2.4 ------------------------------------------------------------------------ r2046 | adk0212 | 2013-04-18 21:12:11 -0400 (Thu, 18 Apr 2013) | 7 lines Upgrade cross-tools to more recent versions gcc-4.2.4 (latest version which is easily built on RHEL5 due to gmp and mpfr dependencies) binutils-2.23.1 (latest) mingw-3.20 (latest, aside from 3.20-2 which is buggy) w32api-3.17-2 (latest) nsis-2.46 (latest, unchanged) ------------------------------------------------------------------------ r2045 | adk0212 | 2013-02-18 19:25:43 -0500 (Mon, 18 Feb 2013) | 2 lines Add lock file creation to apctest main() ------------------------------------------------------------------------ r2044 | adk0212 | 2013-02-18 19:24:38 -0500 (Mon, 18 Feb 2013) | 2 lines Fix copy-paste error in main() ------------------------------------------------------------------------ r2043 | adk0212 | 2013-02-18 19:22:08 -0500 (Mon, 18 Feb 2013) | 4 lines Remove redundant creation of lock file from setup_device(). Lock file was already being created in main(). Change error message in main() to match the one we are removing because it is more informative. ------------------------------------------------------------------------ r2042 | adk0212 | 2013-02-18 19:18:17 -0500 (Mon, 18 Feb 2013) | 3 lines Get rid of UPS setup flag. This was a holdover from back when the UPSINFO structure was held in sysv shmem. ------------------------------------------------------------------------ r2041 | adk0212 | 2013-02-11 10:21:51 -0500 (Mon, 11 Feb 2013) | 2 lines Use variadic macros for Dmsg since we pretty much require gcc at this point ------------------------------------------------------------------------ r2040 | adk0212 | 2012-08-19 22:29:28 -0400 (Sun, 19 Aug 2012) | 3 lines If SNMP trap catching cannot be enabled, log a warning and fall back to polling instead of crashing. ------------------------------------------------------------------------ r2039 | adk0212 | 2012-08-19 22:07:12 -0400 (Sun, 19 Aug 2012) | 2 lines Revert notch/spike LASTXFER change; UPS reporting is too ambiguous. ------------------------------------------------------------------------ r2038 | adk0212 | 2012-08-17 15:53:45 -0400 (Fri, 17 Aug 2012) | 2 lines Add info about disabling INF signature enforcement in Windows 8 ------------------------------------------------------------------------ r2037 | adk0212 | 2012-08-10 13:40:01 -0400 (Fri, 10 Aug 2012) | 2 lines Recategorize notch/spike related LASTXFER values appropriately. ------------------------------------------------------------------------ r2036 | adk0212 | 2012-06-18 21:47:08 -0400 (Mon, 18 Jun 2012) | 2 lines Make MIB (vendor) name search case insensitive in snmplite driver ------------------------------------------------------------------------ r2035 | adk0212 | 2012-03-30 23:48:58 -0400 (Fri, 30 Mar 2012) | 2 lines Rename known_info -> _known_info ------------------------------------------------------------------------ r2034 | adk0212 | 2012-03-30 23:40:59 -0400 (Fri, 30 Mar 2012) | 2 lines Convert BSD USB driver to UpsDriver derivative ------------------------------------------------------------------------ r2033 | adk0212 | 2012-03-30 19:47:08 -0400 (Fri, 30 Mar 2012) | 2 lines Convert drivers to C++ classes derived from UpsDriver ------------------------------------------------------------------------ r2032 | adk0212 | 2012-03-26 20:48:22 -0400 (Mon, 26 Mar 2012) | 2 lines Break out of getline() if read() returns an error ------------------------------------------------------------------------ r2031 | adk0212 | 2012-03-06 12:04:27 -0500 (Tue, 06 Mar 2012) | 2 lines Fix PCNET runtime remaining on Smart-UPS X and RT models. ------------------------------------------------------------------------ r2030 | adk0212 | 2012-03-04 22:40:40 -0500 (Sun, 04 Mar 2012) | 2 lines Add missing debug for REG2 ------------------------------------------------------------------------ r2029 | adk0212 | 2012-01-26 21:23:44 -0500 (Thu, 26 Jan 2012) | 4 lines Apply some Mandrake patches, thanks to David Walser - http://svn.mandriva.com/svn/packages/cooker/apcupsd/current/SOURCES/apcupsd-3.10.16-staleusb.patch - http://svn.mandriva.com/svn/packages/cooker/apcupsd/current/SOURCES/apcupsd-3.14.4-mdv_conf.diff ------------------------------------------------------------------------ r2028 | adk0212 | 2011-12-09 10:23:33 -0500 (Fri, 09 Dec 2011) | 2 lines Fix missing DATATIME report info for SNMPLITE_UPS ------------------------------------------------------------------------ r2027 | adk0212 | 2011-12-09 10:20:08 -0500 (Fri, 09 Dec 2011) | 3 lines Fix missing DATATIME report info for PCNET UPSes. Contributed by Dan Swartzendruber . ------------------------------------------------------------------------ r2026 | adk0212 | 2011-11-21 22:05:26 -0500 (Mon, 21 Nov 2011) | 2 lines Fix quoting around AC_LANG_PROGRAM to eliminate warning with autoconf-2.68 ------------------------------------------------------------------------ r2025 | adk0212 | 2011-11-21 22:03:53 -0500 (Mon, 21 Nov 2011) | 4 lines Fix failure to compile when libsupc++ is not available. Need to link using g++ when not linking libsupc++. If linking with libsupc++ use gcc to avoid gettting libstdc++ linked by default. Fixes build on stock Mandriva 2011. ------------------------------------------------------------------------ r2024 | adk0212 | 2011-11-21 21:23:39 -0500 (Mon, 21 Nov 2011) | 2 lines Remove set-but-unused variables pointed out by g++-4.6.1 ------------------------------------------------------------------------ r2023 | adk0212 | 2011-11-21 13:23:53 -0500 (Mon, 21 Nov 2011) | 3 lines Fix smartups configuration example. "UPSTYPE smartups" should be "UPSTYPE apcsmart". Reported by Moray Henderson ------------------------------------------------------------------------ r2022 | adk0212 | 2011-11-10 08:06:36 -0500 (Thu, 10 Nov 2011) | 5 lines Fix ability to detect SNMP GET failures by adding a 'valid' flag to data variables. Flag is defaulted to false when a GET is performed and set to true when valid data is assigned to the variable. This allows the caller to know if any of the OIDs did not fetch successfully. ------------------------------------------------------------------------ r2021 | adk0212 | 2011-11-09 22:58:51 -0500 (Wed, 09 Nov 2011) | 3 lines Tighten restriction to screen out bad CI_NOMBATTV. Add check for invalid CI_BADBATTS. ------------------------------------------------------------------------ r2020 | adk0212 | 2011-11-09 15:12:01 -0500 (Wed, 09 Nov 2011) | 3 lines Fix handling of UPS calibration by adding a dedicated state for when UPS is performing calibration. ------------------------------------------------------------------------ r2019 | adk0212 | 2011-11-09 15:10:49 -0500 (Wed, 09 Nov 2011) | 3 lines Fix self test detection in snmplite driver by implementing snmplite_ups_entry_point() and adding support for DEVICE_CMD_CHECK_SELFTEST ------------------------------------------------------------------------ r2018 | adk0212 | 2011-11-09 15:08:55 -0500 (Wed, 09 Nov 2011) | 2 lines Add missing debug print for C_WHY_BATT ------------------------------------------------------------------------ r2017 | adk0212 | 2011-11-07 22:02:51 -0500 (Mon, 07 Nov 2011) | 4 lines Fix crash when snmplite_ups_open() fails due to SnmpEngine::Open() failure. We need to exit directly rather than returning failure code since caller stupidly ignores the return code and will blindly continue on. ------------------------------------------------------------------------ r2016 | adk0212 | 2011-11-07 21:58:59 -0500 (Mon, 07 Nov 2011) | 2 lines Fix socket leaks on SnmpEngine::Open() failure paths ------------------------------------------------------------------------ r2015 | adk0212 | 2011-11-07 21:57:48 -0500 (Mon, 07 Nov 2011) | 2 lines Remove NLS textdomain call since NLS has been removed long ago. ------------------------------------------------------------------------ r2014 | adk0212 | 2011-11-07 21:36:20 -0500 (Mon, 07 Nov 2011) | 4 lines Strip unprintable characters from UPS model string. Pointed out by Peter Henn in the PCNET driver. Fix applied globally since this issue could affect any driver. ------------------------------------------------------------------------ r2013 | adk0212 | 2011-11-07 21:23:19 -0500 (Mon, 07 Nov 2011) | 3 lines Fix compatibility with mdoc(7) on OpenBSDD. From Ingo Schwarze via Kirill Bychkov . ------------------------------------------------------------------------ r2012 | adk0212 | 2011-10-14 23:41:07 -0400 (Fri, 14 Oct 2011) | 2 lines Add VID/PID for HP T1500 G3 UPS which is a rebadged APC unit ------------------------------------------------------------------------ r2011 | adk0212 | 2011-10-12 09:00:15 -0400 (Wed, 12 Oct 2011) | 6 lines Remove vendor check from BSD and Generic USB drivers. HP OEMed some UPSes from APC so they are compatible with apcupsd in spite of carrying an HP vendor id. We might as well try to talk to anything a user connects. We will still fail if the required UPS application collection is not found and that is a better indicator of potential compatiblity. ------------------------------------------------------------------------ r2010 | fleetworks | 2011-10-02 09:51:45 -0400 (Sun, 02 Oct 2011) | 2 lines Release 3.14.10 ------------------------------------------------------------------------ r2009 | adk0212 | 2011-09-27 23:33:21 -0400 (Tue, 27 Sep 2011) | 3 lines Fix compile issue with newer net-snmp on CentOS 6. 'MIB' is apparently a macro now, so need to avoid using it. ------------------------------------------------------------------------ r2008 | adk0212 | 2011-09-26 08:56:08 -0400 (Mon, 26 Sep 2011) | 5 lines Filter out SNMP query results that have zero-length sequences. This prevents a crash in the event that the SNMP request times out, as it appears to do very occasionally on certain hardware. Thanks to Lars Tauber for reporting the issue and testing the fix. ------------------------------------------------------------------------ r2007 | adk0212 | 2011-09-22 18:22:41 -0400 (Thu, 22 Sep 2011) | 2 lines Add list of UPSes to avoid ------------------------------------------------------------------------ r2006 | adk0212 | 2011-09-15 22:16:14 -0400 (Thu, 15 Sep 2011) | 2 lines Fix MODEL reporting ------------------------------------------------------------------------ r2005 | adk0212 | 2011-09-13 22:57:16 -0400 (Tue, 13 Sep 2011) | 2 lines Update home page for 3.14.10 release ------------------------------------------------------------------------ r2003 | adk0212 | 2011-09-13 22:34:31 -0400 (Tue, 13 Sep 2011) | 2 lines Prep for 3.14.10 release ------------------------------------------------------------------------ r2002 | adk0212 | 2011-09-02 15:17:13 -0400 (Fri, 02 Sep 2011) | 5 lines Add PID 5 for SMX750 (at least that's what mine uses). Also change com.apple.kernel.iokit to com.apple.kpi.iokit in OS X plist as suggested in an apple dev list posting. It's unclear this does anything but it might help resolve issues with the kext not being selected on certain systems. ------------------------------------------------------------------------ r2001 | adk0212 | 2011-09-02 11:44:41 -0400 (Fri, 02 Sep 2011) | 2 lines Report proper error numbers, not just -1. ------------------------------------------------------------------------ r2000 | adk0212 | 2011-09-02 11:44:14 -0400 (Fri, 02 Sep 2011) | 7 lines Switch USB drivers to prefer FEATURE reports over INPUT reports. This fixes issues with a number of newer UPS models where they advertise INPUT reports but fail to send them when you query for them. Also check report length when processing an interrupt report and ignore it if the length is wrong. This fixes an issue where some UPSes sporadically send truncated interrupt reports. ------------------------------------------------------------------------ r1999 | adk0212 | 2011-08-12 19:01:38 -0400 (Fri, 12 Aug 2011) | 6 lines Ignore transitions to battery because of calibration. This can happen if user initiates calibration in apctest, then exits apctest and starts apcupsd before the calibration has completed. In this case we do not want to shut down the machine, so treat onbattery+cal as not on battery at all. Reported by Sergey . ------------------------------------------------------------------------ r1998 | adk0212 | 2011-08-05 16:31:40 -0400 (Fri, 05 Aug 2011) | 3 lines Use astrncpy instead of strncpy to avoid leaving strings without NUL termination in the overflow case ------------------------------------------------------------------------ r1997 | adk0212 | 2011-08-05 16:30:37 -0400 (Fri, 05 Aug 2011) | 3 lines Enlarge upsmodel buffer to handle longer model strings. Needed for "Smart-UPS RT 5000 XL" as reported by Sergey ------------------------------------------------------------------------ r1996 | adk0212 | 2011-08-05 16:29:21 -0400 (Fri, 05 Aug 2011) | 2 lines Add missing function prototype ------------------------------------------------------------------------ r1995 | adk0212 | 2011-08-05 16:15:29 -0400 (Fri, 05 Aug 2011) | 2 lines Regen manual for 3.14.9 release ------------------------------------------------------------------------ r1994 | adk0212 | 2011-08-05 16:14:29 -0400 (Fri, 05 Aug 2011) | 6 lines Fix MODEL vs. APCMODEL confusion Remove APCMODEL, rename old MODEL aka mode to DRIVER. Update apcsmart driver to put model string into upsmodel field. Remove PCNET workaround for CI_UPSMODEL that is no longer needed. Change USB driver to leave mode field alone. ------------------------------------------------------------------------ r1993 | adk0212 | 2011-08-04 19:19:32 -0400 (Thu, 04 Aug 2011) | 2 lines Add link to OS X binary for 3.14.9 now that it's been released ------------------------------------------------------------------------ r1992 | adk0212 | 2011-08-04 19:17:38 -0400 (Thu, 04 Aug 2011) | 3 lines Work around PackageMaker bug that causes apcagent.app to be relocated at install time in spite of --no-relocate flag ------------------------------------------------------------------------ r1991 | adk0212 | 2011-07-22 23:41:40 -0400 (Fri, 22 Jul 2011) | 2 lines Update web site for 3.14.9 release ------------------------------------------------------------------------ r1989 | adk0212 | 2011-07-22 12:27:54 -0400 (Fri, 22 Jul 2011) | 2 lines Prep for 3.14.9 release ------------------------------------------------------------------------ r1988 | adk0212 | 2011-05-19 18:55:25 -0400 (Thu, 19 May 2011) | 2 lines Add support for changing PCNET port in apcupsd.conf ------------------------------------------------------------------------ r1987 | adk0212 | 2011-05-15 19:07:31 -0400 (Sun, 15 May 2011) | 2 lines Add PIDs for AP9620 LCC ------------------------------------------------------------------------ r1986 | adk0212 | 2011-05-15 19:04:29 -0400 (Sun, 15 May 2011) | 2 lines Fix community probing, misc cleanup ------------------------------------------------------------------------ r1985 | adk0212 | 2011-01-06 10:24:43 -0500 (Thu, 06 Jan 2011) | 2 lines Fix download links on web site; sf.net change the page format again so dl.php no longer works ------------------------------------------------------------------------ r1984 | adk0212 | 2010-09-17 08:44:51 -0400 (Fri, 17 Sep 2010) | 6 lines Change back so we no longer wait for threads to exit. This is necessary because pthread_cancel on OS X does not interrupt blocking calls, even those defined as cancellation points by SuSv3. Argh. Someday we need to fix apcupsd thread shutdown correctly, but for now this is no worse than before. ------------------------------------------------------------------------ r1983 | adk0212 | 2010-09-10 10:50:12 -0400 (Fri, 10 Sep 2010) | 7 lines Rework signal handling to eliminate crashes and hangs. Old signal handler was doing many things wrong: calling unsafe functions in signal context, freeing memory before ensuring users were gone, invoking functions that lock the UPSINFO mutex resulting in deadlock if it's already locked, etc. FIx all this by using a signal handling thread waiting on sigwait() in place of raw handler. ------------------------------------------------------------------------ r1982 | adk0212 | 2010-09-10 08:32:19 -0400 (Fri, 10 Sep 2010) | 2 lines Use "iter->" instead of "(*iter)." ------------------------------------------------------------------------ r1981 | adk0212 | 2010-09-10 08:30:53 -0400 (Fri, 10 Sep 2010) | 3 lines Update MGE MIB handler for SNMP sequence support. Contributed by Lars Taeuber ------------------------------------------------------------------------ r1980 | adk0212 | 2010-09-09 09:40:51 -0400 (Thu, 09 Sep 2010) | 3 lines Fix shutdown command when utility power has been restored. Contributed by Michal Soltys ------------------------------------------------------------------------ r1979 | adk0212 | 2010-09-09 09:17:13 -0400 (Thu, 09 Sep 2010) | 3 lines Prevent apctest from locking up on UPSes that do not respond (at all) to the 'a' command. Contributed by Michal Soltys ------------------------------------------------------------------------ r1978 | adk0212 | 2010-09-09 09:12:49 -0400 (Thu, 09 Sep 2010) | 2 lines Remove remaining NLS artifacts ------------------------------------------------------------------------ r1977 | adk0212 | 2010-09-08 19:25:07 -0400 (Wed, 08 Sep 2010) | 4 lines Remove obsolete mode types and simplify cable vs. mode disambiguation logic. UPSTYPE wins. UPSCABLE is only used for dumb driver. Remove a bit of screwy BackUPS Pro and v/s logic that is long obsolete. ------------------------------------------------------------------------ r1976 | adk0212 | 2010-09-08 19:23:34 -0400 (Wed, 08 Sep 2010) | 2 lines Minor update to K command ------------------------------------------------------------------------ r1975 | adk0212 | 2010-09-08 15:06:21 -0400 (Wed, 08 Sep 2010) | 3 lines Average LOADPCT across all lines rather than summing them since mfgrs appear to not be adhering to the spec very closely. ------------------------------------------------------------------------ r1974 | adk0212 | 2010-09-08 14:44:30 -0400 (Wed, 08 Sep 2010) | 2 lines Use GETNEXT instead of GET so OIDs no longer need trailing zero. ------------------------------------------------------------------------ r1973 | adk0212 | 2010-09-07 11:35:13 -0400 (Tue, 07 Sep 2010) | 3 lines Add support for fetching SNMP table columns as sequences and use it in RFC1628 MIB support. ------------------------------------------------------------------------ r1972 | adk0212 | 2010-09-03 16:36:08 -0400 (Fri, 03 Sep 2010) | 2 lines Fix misformatted path due to missing back-tick ------------------------------------------------------------------------ r1971 | adk0212 | 2010-09-03 16:33:59 -0400 (Fri, 03 Sep 2010) | 2 lines Update manual for Ed Dondlinger's Windows email scripts ------------------------------------------------------------------------ r1970 | adk0212 | 2010-09-03 16:18:58 -0400 (Fri, 03 Sep 2010) | 2 lines More updates for new winusb driver ------------------------------------------------------------------------ r1969 | adk0212 | 2010-09-03 16:13:41 -0400 (Fri, 03 Sep 2010) | 3 lines Update supported OSes list...USB on x86_64 Windows is now supported. USB on Win98/ME/2000 is no longer supported. ------------------------------------------------------------------------ r1968 | adk0212 | 2010-09-03 14:41:46 -0400 (Fri, 03 Sep 2010) | 2 lines Fix snmplite build on win32 by adding missing mge-mib ------------------------------------------------------------------------ r1967 | adk0212 | 2010-09-03 14:40:59 -0400 (Fri, 03 Sep 2010) | 3 lines Add Windows email scripts and include them in win32 installs as examples Contributed by Ed Dondlinger ------------------------------------------------------------------------ r1966 | adk0212 | 2010-09-02 15:31:39 -0400 (Thu, 02 Sep 2010) | 2 lines Reorder cases so they are in numerical order ------------------------------------------------------------------------ r1965 | adk0212 | 2010-09-02 15:29:34 -0400 (Thu, 02 Sep 2010) | 2 lines Add missing break ------------------------------------------------------------------------ r1964 | adk0212 | 2010-09-02 15:26:35 -0400 (Thu, 02 Sep 2010) | 2 lines Minor correction to low battery logic: Depleted also counts as low. ------------------------------------------------------------------------ r1963 | adk0212 | 2010-09-02 15:05:41 -0400 (Thu, 02 Sep 2010) | 2 lines Missed a couple with table workaround ------------------------------------------------------------------------ r1962 | adk0212 | 2010-09-02 14:51:53 -0400 (Thu, 02 Sep 2010) | 3 lines Workaround for line in and line out data on RFC MIB. Blindly use first index in table. ------------------------------------------------------------------------ r1961 | adk0212 | 2010-09-02 10:23:39 -0400 (Thu, 02 Sep 2010) | 3 lines docutils appears to no longer include a rst2html wrapper for rst2html.py. Update configure accordingly. ------------------------------------------------------------------------ r1960 | adk0212 | 2010-09-02 10:22:26 -0400 (Thu, 02 Sep 2010) | 2 lines Enable generation of footnotes at the bottom of the page in rst2pdf. ------------------------------------------------------------------------ r1959 | adk0212 | 2010-09-02 09:26:12 -0400 (Thu, 02 Sep 2010) | 2 lines Update SNMP section ------------------------------------------------------------------------ r1958 | adk0212 | 2010-09-02 08:27:35 -0400 (Thu, 02 Sep 2010) | 2 lines Add community probing ------------------------------------------------------------------------ r1957 | adk0212 | 2010-09-01 13:14:04 -0400 (Wed, 01 Sep 2010) | 3 lines Screen out LTRANS, HTRANS, NOMOUTV, NOMINV, NOMPOWER which are reading zero via an RFC1628 Generex CS121 on a Newave Conceptpower DPA UPS. ------------------------------------------------------------------------ r1956 | adk0212 | 2010-09-01 08:41:27 -0400 (Wed, 01 Sep 2010) | 4 lines Fix compile error on newer glibc. Passing a const for the first argument of strstr() causes the return value to be const. This is Correct (TM) but annoying in this case. So just cast away the constness of the first arg. ------------------------------------------------------------------------ r1955 | adk0212 | 2010-08-31 19:17:33 -0400 (Tue, 31 Aug 2010) | 3 lines Remove unnecessary checks for NULL oid. Verify returned data type matches expectation. ------------------------------------------------------------------------ r1954 | adk0212 | 2010-08-31 14:57:44 -0400 (Tue, 31 Aug 2010) | 3 lines Remove strategy-specific probe hook. We don't need it now and probably will never need it. ------------------------------------------------------------------------ r1953 | adk0212 | 2010-08-31 14:06:44 -0400 (Tue, 31 Aug 2010) | 4 lines Add support for MIB autodetection by probing for CI_STATUS OID. Also rework NOTRAP handling to not require a special notrap MibStrategy for each MIB. ------------------------------------------------------------------------ r1952 | adk0212 | 2010-08-30 14:41:04 -0400 (Mon, 30 Aug 2010) | 3 lines Allow user to omit one or more subsections of SNMP DEVICE string. Contributed by Lars Täer ------------------------------------------------------------------------ r1951 | adk0212 | 2010-08-30 14:18:47 -0400 (Mon, 30 Aug 2010) | 2 lines Fix typo. Contributed by Lars Täer ------------------------------------------------------------------------ r1950 | adk0212 | 2010-08-30 14:18:23 -0400 (Mon, 30 Aug 2010) | 2 lines Add support for MGE SNMP MIB. Contributed by Lars Täer ------------------------------------------------------------------------ r1949 | adk0212 | 2010-08-20 20:34:48 -0400 (Fri, 20 Aug 2010) | 2 lines Add SU1000INET battery constant ------------------------------------------------------------------------ r1947 | adk0212 | 2010-08-17 14:24:15 -0400 (Tue, 17 Aug 2010) | 2 lines Update for 3.14.9-test1 release ------------------------------------------------------------------------ r1946 | adk0212 | 2010-08-16 19:18:35 -0400 (Mon, 16 Aug 2010) | 2 lines Default to winusb driver ------------------------------------------------------------------------ r1945 | adk0212 | 2010-08-16 19:15:28 -0400 (Mon, 16 Aug 2010) | 2 lines Update for new files in snmplite ------------------------------------------------------------------------ r1944 | adk0212 | 2010-08-13 14:52:15 -0400 (Fri, 13 Aug 2010) | 3 lines Take another guess at RFC1628 killpower/shutdown based on TrippLite's interpretation of upsAutoRestart. ------------------------------------------------------------------------ r1943 | adk0212 | 2010-08-13 14:40:37 -0400 (Fri, 13 Aug 2010) | 3 lines Attempt to implement shutdown/killpower for RFC1628 SNMP MIB. MIB docs are somewhat unclear so this is a best guess. ------------------------------------------------------------------------ r1942 | adk0212 | 2010-08-13 14:03:28 -0400 (Fri, 13 Aug 2010) | 2 lines Add missing file. ------------------------------------------------------------------------ r1941 | adk0212 | 2010-08-13 14:00:15 -0400 (Fri, 13 Aug 2010) | 4 lines Reorganize multiple MIB support. Vendor names are now associated with MIB strategies directly. killpower and shutdown operations are deferred to the strategy as is trap waiting. Other general cleanup. ------------------------------------------------------------------------ r1940 | adk0212 | 2010-07-30 18:04:13 -0400 (Fri, 30 Jul 2010) | 4 lines Add support for RFC1628 SNMP MIB. Refactor APC MIB and create MibStrategy struct for associating MIB/CI mapping with corresponding processing function. RFC1628 strategy is coded per the MIB but untested. ------------------------------------------------------------------------ r1939 | adk0212 | 2010-07-10 11:32:53 -0400 (Sat, 10 Jul 2010) | 2 lines Update Windows *.inf files for LCC PIDs ------------------------------------------------------------------------ r1938 | adk0212 | 2010-05-16 18:11:39 -0400 (Sun, 16 May 2010) | 2 lines Remove unused variable shm_OK ------------------------------------------------------------------------ r1937 | adk0212 | 2010-05-16 18:09:43 -0400 (Sun, 16 May 2010) | 4 lines When logging events, convert LOG_CRIT to a WARNING on Win32 rather than an ERROR since apcupsd uses it for power events which aren't really daemon errors. LOG_ERR is still converted to ERROR for use in true error cases. ------------------------------------------------------------------------ r1936 | adk0212 | 2010-05-16 17:57:34 -0400 (Sun, 16 May 2010) | 6 lines Fix bug where pid file was overwritten even when lock file indicates another instance is running. Now we only write the pid file after writing the lock file successfully. Also automatically remove pid file on termination if we created it in the first place. Reported by Justin Killen ------------------------------------------------------------------------ r1935 | adk0212 | 2010-04-29 19:25:25 -0400 (Thu, 29 Apr 2010) | 3 lines When running uninstaller in silent mode, always remove config and events files without prompting. Reported by Zdenek Jirous ------------------------------------------------------------------------ r1934 | adk0212 | 2010-04-29 19:20:04 -0400 (Thu, 29 Apr 2010) | 3 lines Honor INSTDIR specified on command line via /D. Reported by Zdenek Jirous ------------------------------------------------------------------------ r1933 | adk0212 | 2010-02-20 10:09:23 -0500 (Sat, 20 Feb 2010) | 8 lines Variable largebuf may be overflowed by the buf data, which can cause overwriting of subsequent variables. I: Statement might be overflowing a buffer in strncat. Common mistake: BAD: strncat(buffer,charptr,sizeof(buffer)) is wrong, it takes the left over size as 3rd argument GOOD: strncat(buffer,charptr,sizeof(buffer)-strlen(buffer)-1) E: apcupsd bufferoverflowstrncat reports.c:110 Reported by Stanislav Brabec ------------------------------------------------------------------------ r1932 | adk0212 | 2010-01-31 12:16:18 -0500 (Sun, 31 Jan 2010) | 2 lines Update SmartUPS protocol register 2 bit 5. This is supported on SmartUPSes. ------------------------------------------------------------------------ r1931 | adk0212 | 2010-01-31 11:10:59 -0500 (Sun, 31 Jan 2010) | 5 lines Add missing handling for DALARM. Also PWSUM is a LOGICAL collection, not a PYSICAL collection, so add support for checking LOGICAL collection and update known_info table appropriately. This fixes BATTV and MANDATE on certain newer APC models. ------------------------------------------------------------------------ r1930 | adk0212 | 2010-01-24 08:19:37 -0500 (Sun, 24 Jan 2010) | 2 lines Remove unnecessary debug print ------------------------------------------------------------------------ r1929 | adk0212 | 2010-01-17 19:12:02 -0500 (Sun, 17 Jan 2010) | 5 lines When using generic-usb driver, interpret DEVICE setting as the serial number of the UPS to monitor. This allows the user to control which UPS is monitored if more than one is connected. A blank DEVICE setting continues to mean autodetect. ------------------------------------------------------------------------ r1928 | adk0212 | 2010-01-17 13:58:32 -0500 (Sun, 17 Jan 2010) | 2 lines Fix define ------------------------------------------------------------------------ r1927 | adk0212 | 2010-01-17 13:38:10 -0500 (Sun, 17 Jan 2010) | 3 lines Add workaround for FreeBSD libsupc++.a issue (FreeBSD PR #99702) This will allow snmplite driver to compile/link on FreeBSD 5.x ------------------------------------------------------------------------ r1926 | adk0212 | 2010-01-17 10:58:34 -0500 (Sun, 17 Jan 2010) | 3 lines Force use of generic_usb on FreeBSD 8.0 and higher. FreeBSD USB API was changed in 8.0, so from now on we will use libusb. ------------------------------------------------------------------------ r1925 | adk0212 | 2010-01-17 10:38:43 -0500 (Sun, 17 Jan 2010) | 2 lines Fix compile warning ------------------------------------------------------------------------ r1924 | adk0212 | 2010-01-17 10:30:05 -0500 (Sun, 17 Jan 2010) | 2 lines Fix comment ------------------------------------------------------------------------ r1923 | adk0212 | 2010-01-17 10:29:20 -0500 (Sun, 17 Jan 2010) | 3 lines If libusb-config is not found, fall back on a plain old AC_CHECK_LIB. This will allow building against the new libusb-1.x with compatibility API. ------------------------------------------------------------------------ r1922 | adk0212 | 2010-01-17 10:26:47 -0500 (Sun, 17 Jan 2010) | 2 lines Regen manual for release ------------------------------------------------------------------------ r1921 | adk0212 | 2010-01-16 15:17:05 -0500 (Sat, 16 Jan 2010) | 2 lines Update for 3.14.8 release ------------------------------------------------------------------------ r1919 | adk0212 | 2010-01-16 11:09:47 -0500 (Sat, 16 Jan 2010) | 2 lines Prep for 3.14.8 release ------------------------------------------------------------------------ r1918 | adk0212 | 2010-01-16 11:01:38 -0500 (Sat, 16 Jan 2010) | 2 lines Update apctest manpage for USB changes ------------------------------------------------------------------------ r1917 | adk0212 | 2010-01-16 10:19:20 -0500 (Sat, 16 Jan 2010) | 2 lines Move winusb coinstallers to depkgs-win32 so they do not bloat the source tree. ------------------------------------------------------------------------ r1916 | adk0212 | 2010-01-12 18:08:18 -0500 (Tue, 12 Jan 2010) | 3 lines Fix compiler warnings. Also remove whitespace at the end of lines. Contributed by Andy O'Shaughnessy ------------------------------------------------------------------------ r1915 | adk0212 | 2010-01-10 16:50:56 -0500 (Sun, 10 Jan 2010) | 2 lines Remove apcagent application in darwin uninstall script ------------------------------------------------------------------------ r1914 | adk0212 | 2010-01-10 16:45:45 -0500 (Sun, 10 Jan 2010) | 2 lines spec updates for new SNMP driver ------------------------------------------------------------------------ r1913 | adk0212 | 2010-01-10 16:44:59 -0500 (Sun, 10 Jan 2010) | 2 lines Minor style changes ------------------------------------------------------------------------ r1912 | adk0212 | 2010-01-10 16:31:02 -0500 (Sun, 10 Jan 2010) | 2 lines Minor updates for SNMP. Also add gapcmon and apcagent configure options. ------------------------------------------------------------------------ r1911 | adk0212 | 2010-01-10 15:32:21 -0500 (Sun, 10 Jan 2010) | 3 lines Fix bug that caused key/value columns to become mismatched if a row was removed from the list. ------------------------------------------------------------------------ r1910 | adk0212 | 2010-01-10 15:14:13 -0500 (Sun, 10 Jan 2010) | 3 lines Increase SNMP query timeout to prevent false failures when UPS is being hit by two SNMP clients at once. ------------------------------------------------------------------------ r1909 | adk0212 | 2010-01-10 15:05:34 -0500 (Sun, 10 Jan 2010) | 3 lines Fix up SNMP driver selection. Config file "snmp" selects snmplite, while old driver remains available as 'netsnmp'. Same for ./configure script. ------------------------------------------------------------------------ r1908 | adk0212 | 2010-01-10 15:02:40 -0500 (Sun, 10 Jan 2010) | 2 lines Fix DALARM (depends on alarm timer setting from upsAdvConfigAlarmTimer) ------------------------------------------------------------------------ r1907 | adk0212 | 2010-01-10 15:00:46 -0500 (Sun, 10 Jan 2010) | 2 lines Improve warning message for USB driver install failure ------------------------------------------------------------------------ r1906 | adk0212 | 2010-01-10 12:59:48 -0500 (Sun, 10 Jan 2010) | 3 lines Add a troubleshooting section describing that the common cause of failure with "Error Code 10" is that the driver was installed on the wrong device. ------------------------------------------------------------------------ r1905 | adk0212 | 2010-01-10 12:58:33 -0500 (Sun, 10 Jan 2010) | 2 lines Add a driver version to assist with upgrading. ------------------------------------------------------------------------ r1904 | adk0212 | 2010-01-10 10:39:02 -0500 (Sun, 10 Jan 2010) | 3 lines Consolidate get/set USB options. Since all 'set' operations allow you to bail out without changing anything, they also serve as 'get'. ------------------------------------------------------------------------ r1903 | adk0212 | 2010-01-10 10:29:00 -0500 (Sun, 10 Jan 2010) | 4 lines Add apctest support for reading/setting self-test interval on USB. Also show current setting in UPS status. Contributed by James Belleau ------------------------------------------------------------------------ r1902 | adk0212 | 2010-01-10 10:02:13 -0500 (Sun, 10 Jan 2010) | 3 lines Use 'Q' to exit menus instead of the last number which is always changing. Contributed by James Belleau ------------------------------------------------------------------------ r1901 | adk0212 | 2010-01-09 13:35:16 -0500 (Sat, 09 Jan 2010) | 4 lines Consolidate win-usb driver back into generic-usb by writing a simple libusb API adapter for winusb (libusb-winusb-bridge). This eliminates the code duplication between win-usb and generic-usb. ------------------------------------------------------------------------ r1900 | adk0212 | 2010-01-08 19:23:27 -0500 (Fri, 08 Jan 2010) | 5 lines Update detail text while waiting for apps to exit so user knows why we're sitting here for a few seconds. Also skip apctray exit wait if we've installed the main apcupsd package since that means we've already ensured apctray is not running. ------------------------------------------------------------------------ r1899 | adk0212 | 2010-01-08 19:11:28 -0500 (Fri, 08 Jan 2010) | 2 lines Update installer to automatically install WinUSB driver when possible. ------------------------------------------------------------------------ r1898 | adk0212 | 2010-01-03 20:51:54 -0500 (Sun, 03 Jan 2010) | 4 lines Win2k3 has an extra icon in shell32.dll which throws off the numbering causing the manpages to have the wrong icon. Just use the same icon for manpages and user manual. ------------------------------------------------------------------------ r1897 | adk0212 | 2010-01-03 20:19:56 -0500 (Sun, 03 Jan 2010) | 3 lines Set icons for start menu shortcuts. For now, just use common icons from shell32.dll. ------------------------------------------------------------------------ r1896 | adk0212 | 2010-01-03 17:02:23 -0500 (Sun, 03 Jan 2010) | 2 lines Include driver install instructions text file ------------------------------------------------------------------------ r1895 | adk0212 | 2010-01-03 17:01:19 -0500 (Sun, 03 Jan 2010) | 2 lines Cleanup INF naming, class, etc. ------------------------------------------------------------------------ r1894 | adk0212 | 2010-01-03 17:00:53 -0500 (Sun, 03 Jan 2010) | 2 lines Initial rev of winusb driver install instructions. ------------------------------------------------------------------------ r1893 | adk0212 | 2010-01-03 13:08:26 -0500 (Sun, 03 Jan 2010) | 3 lines Update VERSION munging for resource script to accomodate version strings with a -foo extension. ------------------------------------------------------------------------ r1892 | adk0212 | 2010-01-03 12:46:49 -0500 (Sun, 03 Jan 2010) | 2 lines Fix build order so libusb.h is created before it is needed. ------------------------------------------------------------------------ r1891 | adk0212 | 2010-01-03 12:33:41 -0500 (Sun, 03 Jan 2010) | 3 lines Add support for building and installing WinUSB. Default remains as generic-usb. To build for WinUSB set USBTYPE=winusb. ------------------------------------------------------------------------ r1890 | adk0212 | 2010-01-03 12:32:26 -0500 (Sun, 03 Jan 2010) | 3 lines Move StrReplace to its own file. Remove unused version functions now that we're using the built-in WinVer.nsh. ------------------------------------------------------------------------ r1889 | adk0212 | 2010-01-03 12:27:54 -0500 (Sun, 03 Jan 2010) | 2 lines Enable building the NSIS System plugin. ------------------------------------------------------------------------ r1888 | adk0212 | 2010-01-03 10:29:16 -0500 (Sun, 03 Jan 2010) | 3 lines WinUsb-based INF file customized for APCUPSD and driver coinstallers from Win7 DDK. ------------------------------------------------------------------------ r1887 | adk0212 | 2010-01-03 10:22:22 -0500 (Sun, 03 Jan 2010) | 3 lines First rev of Windows-specific USB driver based on Microsoft's WinUsb framework for user mode USB drivers. ------------------------------------------------------------------------ r1886 | adk0212 | 2010-01-02 16:28:28 -0500 (Sat, 02 Jan 2010) | 2 lines Revert previous change: Locks are already held by snmp.c wrapper funcs. ------------------------------------------------------------------------ r1885 | adk0212 | 2010-01-02 14:58:00 -0500 (Sat, 02 Jan 2010) | 3 lines Remove old non-txt files so they do not get stuck around after an install-in-place. ------------------------------------------------------------------------ r1884 | adk0212 | 2010-01-02 14:50:14 -0500 (Sat, 02 Jan 2010) | 7 lines Convert win32 config and doc files to DOS line endings so they can be viewed and edited in notepad. This is necessary because the workaround of using write.exe for UNIX format files does not work well on Win7 due to it using wide margins that unpleasantly word-wraps all the text. Use a *.txt extension on filenames where possible and use default 'open' behavior so if user has configured an alternate editor for *.txt it will be used. ------------------------------------------------------------------------ r1883 | adk0212 | 2010-01-02 14:47:43 -0500 (Sat, 02 Jan 2010) | 2 lines Update to nsis-2.46 and w32api-3.14 ------------------------------------------------------------------------ r1882 | adk0212 | 2010-01-02 13:42:07 -0500 (Sat, 02 Jan 2010) | 5 lines Update installer to use /kill switch to shutdown apps again. This will provide more reliable shutdowns, especially on Vista/Win7 where apcupsd service is running in another session and therefore is inaccessible by the window message mechanism. Remove old window message based shutdown logic. ------------------------------------------------------------------------ r1881 | adk0212 | 2010-01-01 12:02:06 -0500 (Fri, 01 Jan 2010) | 2 lines Add support for APC_NOTRAP vendor which disabled trap catching. ------------------------------------------------------------------------ r1880 | adk0212 | 2010-01-01 11:41:36 -0500 (Fri, 01 Jan 2010) | 3 lines Hold the write lock while updating UPSINFO state variables. This is necessary to prevent NIS clients from seeing partially-updated state. ------------------------------------------------------------------------ r1879 | adk0212 | 2010-01-01 11:16:50 -0500 (Fri, 01 Jan 2010) | 2 lines Remove cygwin platform. This has been unused for years. ------------------------------------------------------------------------ r1878 | adk0212 | 2010-01-01 11:13:39 -0500 (Fri, 01 Jan 2010) | 3 lines Only do popups on Win95/98/ME/NT. Newer OSes will run apctray which shows events in a balloon notification. ------------------------------------------------------------------------ r1877 | adk0212 | 2010-01-01 11:12:16 -0500 (Fri, 01 Jan 2010) | 2 lines Bring back /kill support. Registry change detection no longer needed. ------------------------------------------------------------------------ r1876 | adk0212 | 2010-01-01 11:11:37 -0500 (Fri, 01 Jan 2010) | 2 lines Remove conditionals; always display a popup. ------------------------------------------------------------------------ r1875 | adk0212 | 2009-11-21 12:34:10 -0500 (Sat, 21 Nov 2009) | 2 lines Center date field now that sf.net is not reporting time info. ------------------------------------------------------------------------ r1874 | adk0212 | 2009-11-21 12:32:06 -0500 (Sat, 21 Nov 2009) | 5 lines Fix issue with displaying DMG .sig info for 3.14.7 source code link. Something at the top of the source is messing up the regexp, but can't figure out exactly what. So just chop off the top of the page completely. We only want the data in the All Files section anyway. ------------------------------------------------------------------------ r1873 | adk0212 | 2009-11-15 12:57:00 -0500 (Sun, 15 Nov 2009) | 2 lines Remove obsolete image files. ------------------------------------------------------------------------ r1872 | adk0212 | 2009-11-15 10:05:42 -0500 (Sun, 15 Nov 2009) | 2 lines Update for change in sf.net HTML (data format changed) ------------------------------------------------------------------------ r1871 | adk0212 | 2009-11-15 09:18:43 -0500 (Sun, 15 Nov 2009) | 5 lines Add support for reading battery voltage from the PowerSummary instead of the Battery physical usage. At least one Back-UPS model appears to place its battery readout there instead of the normal place. Back-UPS 500 FW: 6.3.I USB FW: c1 ------------------------------------------------------------------------ r1870 | adk0212 | 2009-11-09 21:19:23 -0500 (Mon, 09 Nov 2009) | 2 lines Fix timezone on Windows. This has always been wrong. ------------------------------------------------------------------------ r1869 | adk0212 | 2009-11-09 21:05:14 -0500 (Mon, 09 Nov 2009) | 2 lines Switch time/date output format to simplified ISO "YYYY-MM-DD HH:MM:SS +/-UTC" ------------------------------------------------------------------------ r1868 | adk0212 | 2009-11-09 21:03:40 -0500 (Mon, 09 Nov 2009) | 2 lines Fix compile error. ------------------------------------------------------------------------ r1867 | adk0212 | 2009-10-31 11:32:53 -0400 (Sat, 31 Oct 2009) | 2 lines Sync alib with gelogger project ------------------------------------------------------------------------ r1866 | adk0212 | 2009-10-31 10:04:32 -0400 (Sat, 31 Oct 2009) | 2 lines Fix compile warning ------------------------------------------------------------------------ r1865 | adk0212 | 2009-10-31 09:31:42 -0400 (Sat, 31 Oct 2009) | 2 lines Move INADDR_NONE define to common header ------------------------------------------------------------------------ r1864 | adk0212 | 2009-10-31 09:28:57 -0400 (Sat, 31 Oct 2009) | 2 lines Fix signed/unsigned comparison warning ------------------------------------------------------------------------ r1863 | adk0212 | 2009-10-31 09:24:31 -0400 (Sat, 31 Oct 2009) | 2 lines Fix compile error on Solaris 10 ------------------------------------------------------------------------ r1862 | adk0212 | 2009-10-31 08:55:17 -0400 (Sat, 31 Oct 2009) | 2 lines win32 build fixes ------------------------------------------------------------------------ r1861 | adk0212 | 2009-10-31 08:42:17 -0400 (Sat, 31 Oct 2009) | 2 lines Fix comment ------------------------------------------------------------------------ r1860 | adk0212 | 2009-10-31 08:37:32 -0400 (Sat, 31 Oct 2009) | 2 lines Switch libnis to thread-safe gethostname_re() ------------------------------------------------------------------------ r1859 | adk0212 | 2009-10-27 20:31:12 -0400 (Tue, 27 Oct 2009) | 2 lines Updates so win32 will build with gethostbyname_r ------------------------------------------------------------------------ r1858 | adk0212 | 2009-10-27 20:24:29 -0400 (Tue, 27 Oct 2009) | 2 lines Switch SnmpEngine to thread-safe resolver, gethostbyname_r() ------------------------------------------------------------------------ r1857 | adk0212 | 2009-10-27 19:28:48 -0400 (Tue, 27 Oct 2009) | 2 lines Misc cleanup ------------------------------------------------------------------------ r1856 | adk0212 | 2009-10-27 19:19:41 -0400 (Tue, 27 Oct 2009) | 2 lines Make lengths universally unsigned ------------------------------------------------------------------------ r1855 | adk0212 | 2009-10-27 19:11:40 -0400 (Tue, 27 Oct 2009) | 5 lines Add ability to calculate marshalled size of each data type without actually marshalling the data. This allows Sequence to precalculate its size which in turn allows us to encode length fields in the minimum possible number of octets instead of always using 4. This reduces packet size substantially. ------------------------------------------------------------------------ r1854 | adk0212 | 2009-10-26 19:37:27 -0400 (Mon, 26 Oct 2009) | 2 lines Definitions for APC UPS traps. Not used yet, but may be handy someday. ------------------------------------------------------------------------ r1853 | adk0212 | 2009-10-26 19:36:52 -0400 (Mon, 26 Oct 2009) | 2 lines Spacing changes ------------------------------------------------------------------------ r1852 | adk0212 | 2009-10-26 19:36:31 -0400 (Mon, 26 Oct 2009) | 2 lines Add support for SNMP trap catching ------------------------------------------------------------------------ r1851 | adk0212 | 2009-10-25 21:30:59 -0400 (Sun, 25 Oct 2009) | 2 lines Toy with spacing ------------------------------------------------------------------------ r1850 | adk0212 | 2009-10-25 21:07:50 -0400 (Sun, 25 Oct 2009) | 2 lines Add snmplite support for shutdown and killpower ------------------------------------------------------------------------ r1849 | adk0212 | 2009-10-25 21:07:08 -0400 (Sun, 25 Oct 2009) | 2 lines Add SET command support to SnmpEngine and support classes ------------------------------------------------------------------------ r1848 | adk0212 | 2009-10-25 18:00:04 -0400 (Sun, 25 Oct 2009) | 2 lines Update comments ------------------------------------------------------------------------ r1847 | adk0212 | 2009-10-25 17:48:13 -0400 (Sun, 25 Oct 2009) | 2 lines Add units to ambient humidity and temp status lines ------------------------------------------------------------------------ r1846 | adk0212 | 2009-10-25 17:45:39 -0400 (Sun, 25 Oct 2009) | 4 lines Remove sanity filter on ambient temp and humidity readings. These both read zero if your MeasureUPS probe is not connected, so we don't want to exclude them in that case. ------------------------------------------------------------------------ r1845 | adk0212 | 2009-10-25 17:37:04 -0400 (Sun, 25 Oct 2009) | 2 lines Add support for detecting and recovering from network errors ------------------------------------------------------------------------ r1844 | adk0212 | 2009-10-25 16:47:43 -0400 (Sun, 25 Oct 2009) | 2 lines Misc cleanup ------------------------------------------------------------------------ r1843 | adk0212 | 2009-10-25 16:31:08 -0400 (Sun, 25 Oct 2009) | 2 lines Bump version string ------------------------------------------------------------------------ r1842 | adk0212 | 2009-10-25 15:56:37 -0400 (Sun, 25 Oct 2009) | 2 lines Reorder function ------------------------------------------------------------------------ r1841 | adk0212 | 2009-10-25 15:53:57 -0400 (Sun, 25 Oct 2009) | 3 lines Spit OID arrays out into their own file so they're not cluttering mib.cpp. Also wrap gcc-specific attribute. ------------------------------------------------------------------------ r1840 | adk0212 | 2009-10-25 15:41:55 -0400 (Sun, 25 Oct 2009) | 2 lines Add snmplite driver to win32 build ------------------------------------------------------------------------ r1839 | adk0212 | 2009-10-25 15:41:40 -0400 (Sun, 25 Oct 2009) | 2 lines Minor changes so snmplite can build for win32 ------------------------------------------------------------------------ r1838 | adk0212 | 2009-10-25 15:28:28 -0400 (Sun, 25 Oct 2009) | 2 lines Update MIB map with more CIs from old powernet driver. ------------------------------------------------------------------------ r1837 | adk0212 | 2009-10-25 14:48:34 -0400 (Sun, 25 Oct 2009) | 2 lines Updates for compatibility with old AP960x SNMP cards. ------------------------------------------------------------------------ r1836 | adk0212 | 2009-10-25 12:14:33 -0400 (Sun, 25 Oct 2009) | 2 lines Remove some debug ------------------------------------------------------------------------ r1835 | adk0212 | 2009-10-25 11:54:46 -0400 (Sun, 25 Oct 2009) | 5 lines Rearrange ASN types. Although it seems like a good idea to have a strict separation between ASN and SNMP such that the ASN layer is not polluted with SNMP types, this isn't working very well in practice. So teach ASN about the basic SNMP types and get rid of the Snmp::PduType. ------------------------------------------------------------------------ r1834 | adk0212 | 2009-10-25 11:03:14 -0400 (Sun, 25 Oct 2009) | 4 lines Add SNMP Lite driver which does not depend on net-snmp library. This makes it more portable and eliminates need to move libsnmp.so to /lib in order to do a killpower on systems where /usr is unmounted. ------------------------------------------------------------------------ r1833 | adk0212 | 2009-10-25 10:58:35 -0400 (Sun, 25 Oct 2009) | 2 lines Make size unsigned ------------------------------------------------------------------------ r1832 | adk0212 | 2009-10-24 15:41:10 -0400 (Sat, 24 Oct 2009) | 2 lines Simple (and inefficient) dynamic array template class ------------------------------------------------------------------------ r1831 | adk0212 | 2009-10-24 10:04:01 -0400 (Sat, 24 Oct 2009) | 3 lines Force use of HFS+ rather than HFSX (case-sensitive HFS+) so 10.5+ will open the image without crying about it. ------------------------------------------------------------------------ r1830 | adk0212 | 2009-10-15 20:46:39 -0400 (Thu, 15 Oct 2009) | 4 lines Revert snmp static lib change. This is too incompatible. Solaris only has static versions of libnetsnmp but not libcrypto. Darwin doesn't seem to have static versions of either of them. ------------------------------------------------------------------------ r1829 | adk0212 | 2009-10-15 18:44:47 -0400 (Thu, 15 Oct 2009) | 4 lines Link with static snmp libs since some platforms do not have the shared ones in /lib. Contributed by Brad King via Debian bugtracker. http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=316932 ------------------------------------------------------------------------ r1828 | adk0212 | 2009-10-15 18:13:45 -0400 (Thu, 15 Oct 2009) | 3 lines Merge WALL fix from Justin T Pryzby http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=546019 ------------------------------------------------------------------------ r1827 | adk0212 | 2009-10-14 19:14:22 -0400 (Wed, 14 Oct 2009) | 2 lines Update status window control layout to match apctray ------------------------------------------------------------------------ r1826 | adk0212 | 2009-10-12 19:22:23 -0400 (Mon, 12 Oct 2009) | 2 lines Lowercase $(COMMA) ------------------------------------------------------------------------ r1825 | adk0212 | 2009-10-12 19:15:58 -0400 (Mon, 12 Oct 2009) | 2 lines Patch version info into resource file on the fly ------------------------------------------------------------------------ r1824 | adk0212 | 2009-10-12 18:53:05 -0400 (Mon, 12 Oct 2009) | 2 lines Set operating system field correctly ------------------------------------------------------------------------ r1823 | adk0212 | 2009-10-12 18:50:27 -0400 (Mon, 12 Oct 2009) | 2 lines Update file information block. Still not sure what to do about version info ------------------------------------------------------------------------ r1822 | adk0212 | 2009-10-12 18:35:32 -0400 (Mon, 12 Oct 2009) | 2 lines Convert all member variable names to leading underscore convention ------------------------------------------------------------------------ r1821 | adk0212 | 2009-10-12 18:27:25 -0400 (Mon, 12 Oct 2009) | 2 lines Update for StatMgr::GetAll() changes ------------------------------------------------------------------------ r1820 | adk0212 | 2009-10-12 18:17:14 -0400 (Mon, 12 Oct 2009) | 3 lines Change StatMgr::GetAll() to return keys and values separately instead of combining them into a single string which the caller then has to split. ------------------------------------------------------------------------ r1819 | adk0212 | 2009-10-12 18:09:09 -0400 (Mon, 12 Oct 2009) | 2 lines Consolidate listview update code into ListView wrapper class. ------------------------------------------------------------------------ r1818 | adk0212 | 2009-10-12 17:43:16 -0400 (Mon, 12 Oct 2009) | 6 lines Fix issue with events and status dialogs not updating until the next poll thread tick. Kicking the poll thread inline with window creation does not work since new window is not yet fully created (WM_INITDIALOG has not been processed yet). Fix is to have status and events dialogs request a refresh when WM_INITDIALOG arrives. ------------------------------------------------------------------------ r1817 | adk0212 | 2009-10-11 18:51:04 -0400 (Sun, 11 Oct 2009) | 2 lines Minor cleanup ------------------------------------------------------------------------ r1816 | adk0212 | 2009-10-11 18:33:05 -0400 (Sun, 11 Oct 2009) | 2 lines Add menu item for controlling autostart ------------------------------------------------------------------------ r1815 | adk0212 | 2009-10-11 15:21:22 -0400 (Sun, 11 Oct 2009) | 4 lines Change events and status dialogs to not use cached statmgr since it will be replaced when user changes config. Update events window to use listview and have resize capability. ------------------------------------------------------------------------ r1814 | adk0212 | 2009-10-11 13:04:43 -0400 (Sun, 11 Oct 2009) | 3 lines Move reconfig to poll thread so UI is not held up when applying a new config. This is in line with what the OS X apcagent does. ------------------------------------------------------------------------ r1813 | adk0212 | 2009-10-11 12:41:32 -0400 (Sun, 11 Oct 2009) | 2 lines Fix redrawing icons when explorer restarts with new taskbar ------------------------------------------------------------------------ r1812 | adk0212 | 2009-10-11 12:15:48 -0400 (Sun, 11 Oct 2009) | 2 lines Minor cleanup ------------------------------------------------------------------------ r1811 | adk0212 | 2009-10-11 12:15:04 -0400 (Sun, 11 Oct 2009) | 4 lines Rework network error handling so Update() only retries on soft errors, not hard errors. This helps minimize the length of time a given monitor will ignore UI events when it is unable to connect to an apcupsd. ------------------------------------------------------------------------ r1810 | adk0212 | 2009-10-11 12:12:59 -0400 (Sun, 11 Oct 2009) | 2 lines Fix thread hang by lengthening thread exit wait to accomodate worst case ------------------------------------------------------------------------ r1809 | adk0212 | 2009-10-11 12:12:08 -0400 (Sun, 11 Oct 2009) | 2 lines Move runtime field onto same line as status and shrink dialog to match ------------------------------------------------------------------------ r1808 | adk0212 | 2009-10-10 13:41:21 -0400 (Sat, 10 Oct 2009) | 2 lines About box updates: Remove old logo, fix version/date info, update copyright ------------------------------------------------------------------------ r1807 | adk0212 | 2009-10-10 11:56:25 -0400 (Sat, 10 Oct 2009) | 2 lines Set focus to first invalid control ------------------------------------------------------------------------ r1806 | adk0212 | 2009-10-10 11:55:58 -0400 (Sat, 10 Oct 2009) | 2 lines Restrict port and refresh fields to digits only ------------------------------------------------------------------------ r1805 | adk0212 | 2009-10-10 11:42:37 -0400 (Sat, 10 Oct 2009) | 2 lines Add support for disabling popups. Other misc cleanup. ------------------------------------------------------------------------ r1804 | adk0212 | 2009-10-08 18:59:41 -0400 (Thu, 08 Oct 2009) | 2 lines Fixes for config dialog. Implement basic input validation. ------------------------------------------------------------------------ r1803 | adk0212 | 2009-10-08 18:05:14 -0400 (Thu, 08 Oct 2009) | 2 lines Fix row deletion bug when number of items decreases ------------------------------------------------------------------------ r1802 | adk0212 | 2009-10-07 20:36:54 -0400 (Wed, 07 Oct 2009) | 2 lines First pass at config dialog ------------------------------------------------------------------------ r1801 | adk0212 | 2009-10-07 20:36:32 -0400 (Wed, 07 Oct 2009) | 2 lines First pass at configuration dialog. ------------------------------------------------------------------------ r1800 | adk0212 | 2009-10-07 19:10:02 -0400 (Wed, 07 Oct 2009) | 3 lines Multiple instances working again now. New 'add' menu option to add a new monitor. Rearrange menu items to match OS X. Lots of code cleanup. ------------------------------------------------------------------------ r1799 | adk0212 | 2009-10-07 19:08:49 -0400 (Wed, 07 Oct 2009) | 2 lines Add support for operator->() on iterator ------------------------------------------------------------------------ r1798 | adk0212 | 2009-10-07 08:02:28 -0400 (Wed, 07 Oct 2009) | 3 lines Begin to clean up instance management by creating an InstanceManager. Basic functions are working again, but add/remove instance needs work. ------------------------------------------------------------------------ r1797 | adk0212 | 2009-10-05 20:35:22 -0400 (Mon, 05 Oct 2009) | 3 lines Fix possible crash if FillStatusBox() were to be called at just the wrong instant. ------------------------------------------------------------------------ r1796 | adk0212 | 2009-10-05 20:07:05 -0400 (Mon, 05 Oct 2009) | 2 lines Don't leak ListView wrappers ------------------------------------------------------------------------ r1795 | adk0212 | 2009-10-05 20:05:17 -0400 (Mon, 05 Oct 2009) | 2 lines Add wrapper class for listview and use it from winstat ------------------------------------------------------------------------ r1794 | adk0212 | 2009-10-05 20:04:23 -0400 (Mon, 05 Oct 2009) | 2 lines Add wrapper class for listview and use it in winstat. ------------------------------------------------------------------------ r1793 | adk0212 | 2009-10-05 19:35:54 -0400 (Mon, 05 Oct 2009) | 2 lines Add/update copyright banners ------------------------------------------------------------------------ r1792 | adk0212 | 2009-10-05 19:34:49 -0400 (Mon, 05 Oct 2009) | 5 lines Colorize load and battery meters, as per apcagent. Break meter code out into a separate wrapper class -- a poor man's MFC essentially. Only update controls when their values change to further reduce refresh flicker. Misc cleanup. ------------------------------------------------------------------------ r1791 | adk0212 | 2009-10-04 13:02:11 -0400 (Sun, 04 Oct 2009) | 8 lines Rewrite apctray status dialog to mimic apcagent on OS X. Window now updates on the fly, is resizeable, and has summary info at the top. Also uses ListView control for raw status info so it is in two nice columns and no longer needs to be rendered in an ugly fixed-width font. Switch to ResEdit (http://www.resedit.net) for GUI resource editing instead of tweaking winres.rc by hand. This requires renaming winres.h to resource.h since that's what ResEdit wants to generate. ------------------------------------------------------------------------ r1790 | adk0212 | 2009-10-03 13:26:41 -0400 (Sat, 03 Oct 2009) | 4 lines Fix preferences window label text being obscured by the surrounding box. Issue only appeared on 10.4, but probably just getting lucky with drawing order on 10.5. ------------------------------------------------------------------------ r1789 | adk0212 | 2009-10-03 10:20:25 -0400 (Sat, 03 Oct 2009) | 3 lines Fix issue with popups not appearing if Growl is installed while apcagent is running. ------------------------------------------------------------------------ r1788 | adk0212 | 2009-09-30 19:15:41 -0400 (Wed, 30 Sep 2009) | 2 lines Include apcagent in OS X installer DMG ------------------------------------------------------------------------ r1787 | adk0212 | 2009-09-29 19:20:45 -0400 (Tue, 29 Sep 2009) | 3 lines Build apcagent automatically on OS X but let user disable it via configure if s/he so desires. ------------------------------------------------------------------------ r1786 | adk0212 | 2009-09-29 18:58:49 -0400 (Tue, 29 Sep 2009) | 2 lines Add support for popup notifications via Growl ------------------------------------------------------------------------ r1785 | adk0212 | 2009-09-27 19:39:29 -0400 (Sun, 27 Sep 2009) | 4 lines Fix login item creation on 10.4. Problem and solution is nicely documented by Jake Sprouse here: http://jakesprouse.net/2007/03/28/debugging-apples-loginitemsaec-on-intel-macs ------------------------------------------------------------------------ r1784 | adk0212 | 2009-09-27 16:03:12 -0400 (Sun, 27 Sep 2009) | 2 lines Overwrite dmg ------------------------------------------------------------------------ r1783 | adk0212 | 2009-09-27 15:56:02 -0400 (Sun, 27 Sep 2009) | 2 lines Add menu item to enable/disable starting at login ------------------------------------------------------------------------ r1782 | adk0212 | 2009-09-27 14:37:10 -0400 (Sun, 27 Sep 2009) | 5 lines Add UPS and HOST info to top of menu a'la apctray on win32. Automatically add user login item when apcagent is started for the first time. Remove login item when last monitor is removed. Add menu option to remove all monitors at once. Reorder menu items slightly. ------------------------------------------------------------------------ r1781 | adk0212 | 2009-09-27 10:57:03 -0400 (Sun, 27 Sep 2009) | 2 lines Support for multiple instances ------------------------------------------------------------------------ r1780 | adk0212 | 2009-09-23 20:14:37 -0400 (Wed, 23 Sep 2009) | 3 lines Interpret failure to read any status items as failure of the connection and close it. Retry Update() once in case it fails. ------------------------------------------------------------------------ r1779 | adk0212 | 2009-09-23 18:19:53 -0400 (Wed, 23 Sep 2009) | 2 lines Fix linking of libapc.a so it is included as a dependency. ------------------------------------------------------------------------ r1778 | adk0212 | 2009-09-23 18:17:19 -0400 (Wed, 23 Sep 2009) | 4 lines Ignore SIGPIPE, which can happen when writing to a socket where the remote end has closed the connection. Also improve error handling in write_nbytes(). ------------------------------------------------------------------------ r1777 | adk0212 | 2009-09-23 18:16:14 -0400 (Wed, 23 Sep 2009) | 2 lines Copy hostname so caller doesn't have to keep it valid. ------------------------------------------------------------------------ r1776 | adk0212 | 2009-09-20 19:47:01 -0400 (Sun, 20 Sep 2009) | 2 lines Minor cleanups ------------------------------------------------------------------------ r1775 | adk0212 | 2009-09-20 19:29:37 -0400 (Sun, 20 Sep 2009) | 2 lines Minor optimization to DataSource classes ------------------------------------------------------------------------ r1774 | adk0212 | 2009-09-20 19:07:45 -0400 (Sun, 20 Sep 2009) | 3 lines Plumb in about panel. Expand copyright text slightly. Rename menu items to more closely match other OS X app naming conventions. ------------------------------------------------------------------------ r1773 | adk0212 | 2009-09-20 18:23:10 -0400 (Sun, 20 Sep 2009) | 2 lines Make icon backgrounds transparent ------------------------------------------------------------------------ r1772 | adk0212 | 2009-09-20 17:25:22 -0400 (Sun, 20 Sep 2009) | 2 lines Add horizontal separators to the menu ------------------------------------------------------------------------ r1771 | adk0212 | 2009-09-20 17:13:22 -0400 (Sun, 20 Sep 2009) | 2 lines Remove InfoPlist.strings dependency ------------------------------------------------------------------------ r1770 | adk0212 | 2009-09-20 17:11:53 -0400 (Sun, 20 Sep 2009) | 3 lines Update Info.plist with copyright and version info. Version is substituted at build time for __VERSION__. Remove unused InfoPlist.strings file. ------------------------------------------------------------------------ r1769 | adk0212 | 2009-09-20 17:11:09 -0400 (Sun, 20 Sep 2009) | 2 lines Minor cleanup ------------------------------------------------------------------------ r1768 | adk0212 | 2009-09-20 16:39:42 -0400 (Sun, 20 Sep 2009) | 2 lines Add apcagent, an apctray-like applet for Mac OS X ------------------------------------------------------------------------ r1767 | adk0212 | 2009-09-20 16:26:05 -0400 (Sun, 20 Sep 2009) | 2 lines Move FetchStatus() to StatMgr class and rename to GetSummary() ------------------------------------------------------------------------ r1766 | adk0212 | 2009-09-20 16:11:13 -0400 (Sun, 20 Sep 2009) | 2 lines Convert win32 apctray to use shared statmgr and alib classes. ------------------------------------------------------------------------ r1765 | adk0212 | 2009-09-20 15:47:47 -0400 (Sun, 20 Sep 2009) | 2 lines Add copy of win32 statmgr with win32-isms replaced with alib equivalents ------------------------------------------------------------------------ r1764 | adk0212 | 2009-09-20 15:46:13 -0400 (Sun, 20 Sep 2009) | 2 lines Add lightweight STL-like class library ------------------------------------------------------------------------ r1763 | adk0212 | 2009-09-20 15:41:26 -0400 (Sun, 20 Sep 2009) | 2 lines Add support for building Objective-C files (*.m) ------------------------------------------------------------------------ r1762 | adk0212 | 2009-09-20 15:39:24 -0400 (Sun, 20 Sep 2009) | 2 lines Forgot -arch flags for apcupsd build ------------------------------------------------------------------------ r1761 | adk0212 | 2009-09-13 18:08:58 -0400 (Sun, 13 Sep 2009) | 2 lines And more updates to the notes. Nearly done now, I think. ------------------------------------------------------------------------ r1760 | adk0212 | 2009-09-13 17:36:46 -0400 (Sun, 13 Sep 2009) | 2 lines More build notes updates. ------------------------------------------------------------------------ r1759 | adk0212 | 2009-09-13 17:28:20 -0400 (Sun, 13 Sep 2009) | 2 lines More updates to Darwin build notes. ------------------------------------------------------------------------ r1758 | adk0212 | 2009-09-13 17:05:42 -0400 (Sun, 13 Sep 2009) | 5 lines Disable PackageMaker's "suggested permissions" in favor of using our own explicit permissions. Tweak perms on /Library to keep PackageMaker happy. Remove permission fixups from preflight/postflight scripts. Copy the apcupsd-uninstall script to /sbin during install. ------------------------------------------------------------------------ r1757 | adk0212 | 2009-09-13 17:02:31 -0400 (Sun, 13 Sep 2009) | 2 lines Add uninstall script. ------------------------------------------------------------------------ r1756 | adk0212 | 2009-09-13 09:29:11 -0400 (Sun, 13 Sep 2009) | 3 lines Work around PackageMaker bug that gets ApcupsdDummy.kext directory permissions wrong. ------------------------------------------------------------------------ r1755 | adk0212 | 2009-09-11 20:01:58 -0400 (Fri, 11 Sep 2009) | 2 lines Update OS X build notes with more info I've discovered. ------------------------------------------------------------------------ r1754 | adk0212 | 2009-09-08 18:03:38 -0400 (Tue, 08 Sep 2009) | 2 lines Update apctest manpage for USB battery calibration function. ------------------------------------------------------------------------ r1753 | adk0212 | 2009-09-01 20:30:37 -0400 (Tue, 01 Sep 2009) | 4 lines Implement battery calibration in apctest for USB models. Thanks to James Belleau for the original implementation which has been modified somewhat in this commit. ------------------------------------------------------------------------ r1752 | adk0212 | 2009-08-30 11:24:04 -0400 (Sun, 30 Aug 2009) | 2 lines Update Darwin USB section to call out libusb-0.1.12 specifically. ------------------------------------------------------------------------ r1751 | adk0212 | 2009-08-30 11:14:04 -0400 (Sun, 30 Aug 2009) | 2 lines Fix TTY mode comms option on Win32. ------------------------------------------------------------------------ r1750 | adk0212 | 2009-08-30 10:15:39 -0400 (Sun, 30 Aug 2009) | 3 lines Add notes about compatibility builds. Update universal binaries notes. Rename file to 'build-notes.txt'. ------------------------------------------------------------------------ r1749 | adk0212 | 2009-08-29 14:33:23 -0400 (Sat, 29 Aug 2009) | 3 lines Regen configure with autoconf-2.61 (Darwin XCode-3.3) to fix some warnings when configuring on OS X. ------------------------------------------------------------------------ r1748 | adk0212 | 2009-08-29 14:27:50 -0400 (Sat, 29 Aug 2009) | 8 lines Update OS X installer for XCode-3.x Unable to find a simple way to create metapackages from the command line so separate Daemon and UsbShim subpackages are gone. Everything is now in the top-level package. On the up side, however, we can now override the version string from the command line so we no longer need autoconf to preprocess the plist. Additionally, packagemaker generates the plist now and just merges in any overrides we specify. Much nicer. ------------------------------------------------------------------------ r1747 | adk0212 | 2009-08-23 15:04:31 -0400 (Sun, 23 Aug 2009) | 3 lines Add missing NOMINV, NOMOUTV, and NOMPOWER to clients. Reported by Luciano De Rosa ------------------------------------------------------------------------ r1745 | adk0212 | 2009-08-14 11:02:19 -0400 (Fri, 14 Aug 2009) | 2 lines Introduce new download page since sf.net is so hard to navigate now. ------------------------------------------------------------------------ r1744 | adk0212 | 2009-08-07 08:15:37 -0400 (Fri, 07 Aug 2009) | 3 lines Change ReleaseNotes links to point at versions in CVS since SF isn't properly serving the file if you point to the downloads section. ------------------------------------------------------------------------ r1743 | adk0212 | 2009-08-02 10:36:30 -0400 (Sun, 02 Aug 2009) | 2 lines Update for 3.14.7 release. ------------------------------------------------------------------------ r1741 | adk0212 | 2009-08-01 13:29:15 -0400 (Sat, 01 Aug 2009) | 2 lines Final prep for 3.14.7 release. ------------------------------------------------------------------------ r1740 | fleetworks | 2009-08-01 10:41:16 -0400 (Sat, 01 Aug 2009) | 2 lines 3.14.7 spec update ------------------------------------------------------------------------ r1739 | adk0212 | 2009-08-01 08:18:35 -0400 (Sat, 01 Aug 2009) | 2 lines Remove obsolete files ------------------------------------------------------------------------ r1738 | adk0212 | 2009-08-01 08:01:59 -0400 (Sat, 01 Aug 2009) | 2 lines Remove remnants of powerflute ------------------------------------------------------------------------ r1737 | adk0212 | 2009-07-31 16:23:51 -0400 (Fri, 31 Jul 2009) | 2 lines Prep for 3.14.7 release ------------------------------------------------------------------------ r1736 | adk0212 | 2009-07-31 16:19:07 -0400 (Fri, 31 Jul 2009) | 6 lines Fix configure not noticing when C++ compiler does not exist. Annoyingly, only the first of AC_PROG_CXX and AC_PROG_CC actually error out if the conpiler does not exist. The second one just quietly sets a default and keeps going. Temporary fix is to just move CXX detection to be first since that's the compiler we really need. ------------------------------------------------------------------------ r1735 | adk0212 | 2009-07-31 15:35:55 -0400 (Fri, 31 Jul 2009) | 2 lines Document multimon cgi programs for Windows. ------------------------------------------------------------------------ r1734 | adk0212 | 2009-07-31 11:34:27 -0400 (Fri, 31 Jul 2009) | 2 lines Add support for formatting manpages into plain text ------------------------------------------------------------------------ r1733 | adk0212 | 2009-07-31 11:33:59 -0400 (Fri, 31 Jul 2009) | 4 lines Include plain text manpages in windows install. Organize documentation and provide start menu shortcuts. Also add a shortcut for editing the config file. ------------------------------------------------------------------------ r1732 | adk0212 | 2009-07-31 11:33:10 -0400 (Fri, 31 Jul 2009) | 2 lines Format manpages into plain text. ------------------------------------------------------------------------ r1731 | adk0212 | 2009-07-31 10:22:55 -0400 (Fri, 31 Jul 2009) | 2 lines Add CGI scripts to Windows installer. ------------------------------------------------------------------------ r1730 | adk0212 | 2009-07-31 10:22:33 -0400 (Fri, 31 Jul 2009) | 2 lines Build CGI programs for WIN32. ------------------------------------------------------------------------ r1729 | adk0212 | 2009-07-31 10:21:58 -0400 (Fri, 31 Jul 2009) | 2 lines Remove manual calls to WSA_Init(). It's done automatically in libnis now. ------------------------------------------------------------------------ r1728 | adk0212 | 2009-07-31 10:20:35 -0400 (Fri, 31 Jul 2009) | 3 lines Split network-related compat functions into their own file so users don't have to link in all of compat.cpp. ------------------------------------------------------------------------ r1727 | adk0212 | 2009-07-31 10:18:31 -0400 (Fri, 31 Jul 2009) | 2 lines Automatically invoke WSA_Init() during static initialization on WIN32. ------------------------------------------------------------------------ r1726 | adk0212 | 2009-07-31 10:16:42 -0400 (Fri, 31 Jul 2009) | 2 lines Set stdout to binary mode on WIN32 to prevent corruption of image data. ------------------------------------------------------------------------ r1725 | adk0212 | 2009-07-26 10:50:59 -0400 (Sun, 26 Jul 2009) | 3 lines Automatically add \\.\ UNC prefix to COMx device name on Windows. This allows selection of ports above COM9. ------------------------------------------------------------------------ r1724 | adk0212 | 2009-07-26 10:42:31 -0400 (Sun, 26 Jul 2009) | 3 lines Remove CI_BattReplaceDate because it does not seem to be populated on any modern UPS. CI_BATTDAT works just fine. ------------------------------------------------------------------------ r1721 | adk0212 | 2009-06-07 21:15:05 -0400 (Sun, 07 Jun 2009) | 2 lines Update to NSIS-2.45. ------------------------------------------------------------------------ r1720 | adk0212 | 2009-06-02 20:45:28 -0400 (Tue, 02 Jun 2009) | 2 lines Fix typo. ------------------------------------------------------------------------ r1719 | adk0212 | 2009-05-31 12:18:55 -0400 (Sun, 31 May 2009) | 2 lines Spell check. ------------------------------------------------------------------------ r1718 | adk0212 | 2009-05-31 12:14:48 -0400 (Sun, 31 May 2009) | 2 lines Spell check. ------------------------------------------------------------------------ r1717 | adk0212 | 2009-05-31 11:13:49 -0400 (Sun, 31 May 2009) | 2 lines Fix a few "apcupd" typos. ------------------------------------------------------------------------ r1714 | adk0212 | 2009-05-20 20:43:16 -0400 (Wed, 20 May 2009) | 2 lines Fix UPS version in CGI stats and examples. ------------------------------------------------------------------------ r1713 | adk0212 | 2009-05-16 12:46:41 -0400 (Sat, 16 May 2009) | 2 lines Update web site for 3.14.6 release. ------------------------------------------------------------------------ r1712 | adk0212 | 2009-05-16 12:46:21 -0400 (Sat, 16 May 2009) | 2 lines Update script ------------------------------------------------------------------------ r1710 | adk0212 | 2009-05-16 10:07:36 -0400 (Sat, 16 May 2009) | 2 lines Final prep for 3.14.6. Locked and loaded. ------------------------------------------------------------------------ r1709 | fleetworks | 2009-05-16 09:05:25 -0400 (Sat, 16 May 2009) | 2 lines Comment out latex build. ------------------------------------------------------------------------ r1707 | adk0212 | 2009-05-15 20:13:20 -0400 (Fri, 15 May 2009) | 2 lines Prep for 3.14.6 release (again). ------------------------------------------------------------------------ r1706 | adk0212 | 2009-05-15 20:13:00 -0400 (Fri, 15 May 2009) | 2 lines Fix miscalculated length. Noticed by Stacy Millions ------------------------------------------------------------------------ r1705 | adk0212 | 2009-05-15 19:57:59 -0400 (Fri, 15 May 2009) | 3 lines Add --no-footnote-backlinks to RST2PDF options. It's now supported in rst2pdf SVN trunk. ------------------------------------------------------------------------ r1704 | adk0212 | 2009-05-15 19:44:26 -0400 (Fri, 15 May 2009) | 2 lines changes for new user manual location and format ------------------------------------------------------------------------ r1703 | adk0212 | 2009-05-15 19:32:13 -0400 (Fri, 15 May 2009) | 2 lines Add script to publish the manual to the web site. ------------------------------------------------------------------------ r1702 | adk0212 | 2009-05-15 19:29:37 -0400 (Fri, 15 May 2009) | 2 lines Remove old latex manual. We're all RST now! ------------------------------------------------------------------------ r1701 | adk0212 | 2009-05-15 19:23:19 -0400 (Fri, 15 May 2009) | 3 lines Keep a preformatted copy of the user manual in CVS to ease tool dependencies for packagers. ------------------------------------------------------------------------ r1700 | adk0212 | 2009-05-15 19:07:37 -0400 (Fri, 15 May 2009) | 2 lines Update for new user manual location. ------------------------------------------------------------------------ r1699 | adk0212 | 2009-05-15 18:43:09 -0400 (Fri, 15 May 2009) | 2 lines Fix Scott's name being misinterpreted as an enumerated (elettered?) list. ------------------------------------------------------------------------ r1698 | adk0212 | 2009-05-13 19:49:40 -0400 (Wed, 13 May 2009) | 2 lines Applied updates from Trevor Roydhouse ------------------------------------------------------------------------ r1697 | adk0212 | 2009-05-12 19:45:39 -0400 (Tue, 12 May 2009) | 3 lines Remove Linux /proc/bus/usb text files from appendix. They're a ton of baggage for not much gain. ------------------------------------------------------------------------ r1696 | adk0212 | 2009-05-12 19:35:18 -0400 (Tue, 12 May 2009) | 2 lines Minor formatting and typo fixes to smart protocol docs. ------------------------------------------------------------------------ r1695 | adk0212 | 2009-05-09 09:04:31 -0400 (Sat, 09 May 2009) | 2 lines Fix some {} style markup I missed on the first pass. ------------------------------------------------------------------------ r1694 | adk0212 | 2009-05-09 08:50:08 -0400 (Sat, 09 May 2009) | 2 lines Fix expansion of APC acronym. ------------------------------------------------------------------------ r1693 | adk0212 | 2009-05-07 21:10:40 -0400 (Thu, 07 May 2009) | 2 lines Some tweaks for better compatibility with rst2pdf. ------------------------------------------------------------------------ r1692 | adk0212 | 2009-05-06 21:51:00 -0400 (Wed, 06 May 2009) | 6 lines Several updates to the manual. Replace existing section on UPS maintenance with a new one contributed by Trevor Roydhouse . Replace old disclaimer with a new one, also from Trev. Add some hyperlinks in the smart protocol section. Clean up some table formatting in that section as well. ------------------------------------------------------------------------ r1691 | adk0212 | 2009-05-06 21:50:07 -0400 (Wed, 06 May 2009) | 2 lines Noninterlaced version of logo for compatibility with rst2pdf. ------------------------------------------------------------------------ r1690 | adk0212 | 2009-05-05 17:51:26 -0400 (Tue, 05 May 2009) | 2 lines Add allowable settings for LOWBATT. From Trevor Roydhouse ------------------------------------------------------------------------ r1689 | adk0212 | 2009-05-04 18:21:57 -0400 (Mon, 04 May 2009) | 3 lines Autodetect locations of rst2pdf and rst2html. Politely skip typesetting each format if the generator is not available. ------------------------------------------------------------------------ r1688 | adk0212 | 2009-05-04 18:20:42 -0400 (Mon, 04 May 2009) | 3 lines Add support for QNX. Tested on QNX 6.3.2. Contributed by Mikhail Gruzdev ------------------------------------------------------------------------ r1687 | adk0212 | 2009-05-04 18:03:06 -0400 (Mon, 04 May 2009) | 3 lines Add support for QNX. Tested on QNX 6.3.2. Contributed by Mikhail Gruzdev ------------------------------------------------------------------------ r1686 | adk0212 | 2009-05-04 17:56:24 -0400 (Mon, 04 May 2009) | 2 lines s/batteryload/load/. Contributed by Mikhail Gruzdev ------------------------------------------------------------------------ r1685 | adk0212 | 2009-05-03 17:56:25 -0400 (Sun, 03 May 2009) | 2 lines Generate PDF manual automatically. ------------------------------------------------------------------------ r1684 | adk0212 | 2009-05-03 17:55:09 -0400 (Sun, 03 May 2009) | 2 lines Fix typo. ------------------------------------------------------------------------ r1683 | adk0212 | 2009-05-03 13:31:39 -0400 (Sun, 03 May 2009) | 2 lines Fix broken references. Now formats cleanly with no errors or warnings. ------------------------------------------------------------------------ r1682 | adk0212 | 2009-05-03 12:31:03 -0400 (Sun, 03 May 2009) | 2 lines Minor tweaks to spacing, etc. ------------------------------------------------------------------------ r1681 | adk0212 | 2009-05-03 12:27:18 -0400 (Sun, 03 May 2009) | 3 lines Rejuvinate smart protocol section and add it back in. Merged with updates from NUT site. ------------------------------------------------------------------------ r1680 | adk0212 | 2009-05-02 19:46:59 -0400 (Sat, 02 May 2009) | 3 lines Add EEPROM configuration directives. Text stolen shamelessly from Trevor's apcupsd.conf(5). ------------------------------------------------------------------------ r1679 | adk0212 | 2009-05-02 19:30:07 -0400 (Sat, 02 May 2009) | 2 lines Minor fixes to apctest section. This needs major updates eventually. ------------------------------------------------------------------------ r1678 | adk0212 | 2009-05-02 19:20:42 -0400 (Sat, 02 May 2009) | 2 lines Bring in a shortened version of the supportedupses text. ------------------------------------------------------------------------ r1677 | adk0212 | 2009-05-02 18:37:30 -0400 (Sat, 02 May 2009) | 2 lines Add Windows 7. Split Solaris into 8/9 (no USB) and 10 (USB supported). ------------------------------------------------------------------------ r1676 | adk0212 | 2009-05-02 18:30:38 -0400 (Sat, 02 May 2009) | 2 lines Rewrite and add in supported operating systems section. ------------------------------------------------------------------------ r1675 | adk0212 | 2009-05-02 18:29:35 -0400 (Sat, 02 May 2009) | 3 lines Don't generate backrefs for footnotes; they make the footnotes hard to read. ------------------------------------------------------------------------ r1674 | adk0212 | 2009-05-02 12:11:32 -0400 (Sat, 02 May 2009) | 4 lines Surround TOC with transition dividers to help set it apart. I wish the text for the TOC title were rendered larger. Need to investigate alternate stylesheets. ------------------------------------------------------------------------ r1673 | adk0212 | 2009-05-02 12:00:00 -0400 (Sat, 02 May 2009) | 4 lines Add preliminary Makefile support for rst2html. Dependencies are working. Not tied in to top-level make yet since not everyone will have rst2html. 'make clean' not working yet. Need to figure out what to do about that. ------------------------------------------------------------------------ r1672 | adk0212 | 2009-05-02 10:30:19 -0400 (Sat, 02 May 2009) | 4 lines Change log level of UPS self-test messages to WARNING from ALERT. Given that self-test messages are routine, they do not belong at LOG_ALERT. Contributed by Dave Ewart . ------------------------------------------------------------------------ r1671 | adk0212 | 2009-05-02 10:21:20 -0400 (Sat, 02 May 2009) | 2 lines Install manpages as part of 'make install'. ------------------------------------------------------------------------ r1670 | adk0212 | 2009-05-02 10:05:42 -0400 (Sat, 02 May 2009) | 2 lines Remove one leftover old manpage. ------------------------------------------------------------------------ r1669 | adk0212 | 2009-05-02 10:04:35 -0400 (Sat, 02 May 2009) | 3 lines Replace old manpages with shiny new ones, courtesy of Trevor Roydhousea . Many thanks, Trev! ------------------------------------------------------------------------ r1668 | adk0212 | 2009-04-30 19:20:14 -0400 (Thu, 30 Apr 2009) | 2 lines Minor updates plus clean up and add back in the cables section. ------------------------------------------------------------------------ r1667 | adk0212 | 2009-04-26 20:34:05 -0400 (Sun, 26 Apr 2009) | 2 lines Revert accidental changes. ------------------------------------------------------------------------ r1666 | adk0212 | 2009-04-26 19:12:25 -0400 (Sun, 26 Apr 2009) | 4 lines First pass at converting apcupsd user manual to reStructuredText. Initial conversion via Pandoc, then lots of hand editing. It's in pretty good shape now. Need to fix up external files. ------------------------------------------------------------------------ r1665 | adk0212 | 2009-04-25 11:04:25 -0400 (Sat, 25 Apr 2009) | 9 lines Make startup success message appear in logs again. From Trevor Roydhouse : apcupsd stopped printing startup success messages at some point. Looking through the code it is because it was decided that the LOG_INFO facility level should only be used for data file logging and so it filters out other uses. Unfortunately the startup message is set to that level. Changing the startup message to LOG_WARNING works and is consistent with the normal shutdown message facility level. ------------------------------------------------------------------------ r1664 | adk0212 | 2009-04-25 10:58:29 -0400 (Sat, 25 Apr 2009) | 5 lines Remove EVENTFILE, EVENTFILEMAX config directives. These were replaced by the plural versions that are in use today (EVENTSFILE, EVENTSFILEMAX) almost 10 years ago. It's time to kill the old names. (h/t Trevor Roydhouse ) ------------------------------------------------------------------------ r1663 | adk0212 | 2009-04-25 10:47:50 -0400 (Sat, 25 Apr 2009) | 3 lines Add -P,--pid-file to -h output. Update copyright. (h/t Trevor Roydhouse ) ------------------------------------------------------------------------ r1662 | adk0212 | 2009-04-25 10:45:04 -0400 (Sat, 25 Apr 2009) | 3 lines RELEASE is merely a subset of VERSION. Remove RELEASE. (h/t Trevor Roydhouse ) ------------------------------------------------------------------------ r1661 | adk0212 | 2009-03-19 19:18:07 -0400 (Thu, 19 Mar 2009) | 2 lines Update sf.net logo per new guidelines. ------------------------------------------------------------------------ r1660 | adk0212 | 2009-03-02 18:16:55 -0500 (Mon, 02 Mar 2009) | 2 lines Pseudo-prep for 3.14.6 ------------------------------------------------------------------------ r1659 | adk0212 | 2009-03-02 17:52:57 -0500 (Mon, 02 Mar 2009) | 3 lines Workaround for crash during process shutdown. Contributed by Andrey Sharandakov ------------------------------------------------------------------------ r1658 | adk0212 | 2009-03-02 17:48:26 -0500 (Mon, 02 Mar 2009) | 5 lines Add support for turning the UPS off completely. This complements existing hibernate (aka killpower) functionality. Turn-off is implemented for apcsmart and USB drivers, subject to support for the relevant commands in the UPS itself. Contributed by Keith Campbell . ------------------------------------------------------------------------ r1657 | adk0212 | 2009-03-01 10:03:51 -0500 (Sun, 01 Mar 2009) | 2 lines Fix build with gcc-4.4. Contributed by Michal Hlavinka . ------------------------------------------------------------------------ r1656 | adk0212 | 2009-02-14 16:35:16 -0500 (Sat, 14 Feb 2009) | 5 lines Fix number of array entries which was causing a buffer overflow. Contributed by David Fries . Also change loop counters to unsigned, eliminating a new warning introduced by the above change plus allowing removal of unnecessary casts to int. ------------------------------------------------------------------------ r1655 | adk0212 | 2009-02-10 18:39:30 -0500 (Tue, 10 Feb 2009) | 18 lines Fix some deadlocks in the case of a comm failure when smart_poll() is called without holding the UPS lock. Contributed by Keith Campbell : On one of our machines, apcupsd 3.14.5 (using a smart serial cable) would occasionally not finish starting up. Running strace revealed that it was stuck in deadlock on a futex() system call. I've traced this to some poorly written code inside the apcsmart driver. Inside smart.c there is a UPSlinkCheck() function which according to the documentation must be called with the UPS lock held (ugh). smart_poll() calls the UPSlinkCheck() function (but only in a rarely followed error handling branch), so therefore it must also be called with the lock held. The problem is, many things call smart_poll() but some call it without the lock, and other with the lock. I've put locks around a few smart_poll() calls in smartsetup2.c which corrected the problem I was seeing. ------------------------------------------------------------------------ r1654 | adk0212 | 2009-01-15 17:57:38 -0500 (Thu, 15 Jan 2009) | 3 lines Year++ h/t Kirill S. Bychkov ------------------------------------------------------------------------ r1653 | adk0212 | 2009-01-14 18:00:41 -0500 (Wed, 14 Jan 2009) | 2 lines Update publish scripts for sf.net changes ------------------------------------------------------------------------ r1652 | adk0212 | 2009-01-14 17:49:26 -0500 (Wed, 14 Jan 2009) | 2 lines Update for 3.14.5 release. ------------------------------------------------------------------------ r1650 | adk0212 | 2009-01-10 15:02:56 -0500 (Sat, 10 Jan 2009) | 2 lines 3.14.5 for real this time. ------------------------------------------------------------------------ r1649 | adk0212 | 2008-11-10 19:14:58 -0500 (Mon, 10 Nov 2008) | 3 lines Compile fixes for nagios plugin. Contributed by Ronald J. Yacketta ------------------------------------------------------------------------ r1648 | adk0212 | 2008-11-01 11:03:26 -0400 (Sat, 01 Nov 2008) | 3 lines Remove unused DISTVER code. Contributed by Miloň Papežík ------------------------------------------------------------------------ r1647 | adk0212 | 2008-10-26 10:25:41 -0400 (Sun, 26 Oct 2008) | 2 lines Prep for 3.14.5 release (again) ------------------------------------------------------------------------ r1646 | adk0212 | 2008-10-20 18:19:10 -0400 (Mon, 20 Oct 2008) | 2 lines Update to nsis-2.40. ------------------------------------------------------------------------ r1645 | adk0212 | 2008-10-20 18:18:32 -0400 (Mon, 20 Oct 2008) | 2 lines Document the /refresh switch for apctray. ------------------------------------------------------------------------ r1644 | skoona | 2008-09-16 00:58:20 -0400 (Tue, 16 Sep 2008) | 8 lines Corrected the timebase on the sockopts(0 api call. I intended to set the timeout for two tenths of a second, instead I set it for 200 usec. The results was un-stability and frequently dropped session on my quad-core; dual and single cores didn't seem to be bothered. Now is it set for 200000 usec as I originally intended. James, ------------------------------------------------------------------------ r1643 | skoona | 2008-09-16 00:34:37 -0400 (Tue, 16 Sep 2008) | 2 lines Corrected person references, FreeBSD is the platform Jason Hale maintains ------------------------------------------------------------------------ r1642 | skoona | 2008-09-16 00:23:32 -0400 (Tue, 16 Sep 2008) | 7 lines Applied two patches 1. eggtrayicon.c -- applies background transparency when in systray mode to systray icon. 2. gapcmon.c -- Add include for BSD sockaddr_in, no impact on other platforms. Note: Socket timeout timers were shortened in a prior update James, ------------------------------------------------------------------------ r1641 | adk0212 | 2008-09-10 18:34:05 -0400 (Wed, 10 Sep 2008) | 5 lines Do not create pid file in apctest. There is little reason for it since apctest is a command-line tool, not a daemon. Plus nothing ever deletes the file so it interferes with apcupsd operation. Reported by Eddie Atherton ------------------------------------------------------------------------ r1640 | adk0212 | 2008-09-09 17:51:18 -0400 (Tue, 09 Sep 2008) | 3 lines Change -? to -h for the sake of consistency with other software. Contributed by Thomas Pfaff ------------------------------------------------------------------------ r1639 | adk0212 | 2008-08-17 11:01:51 -0400 (Sun, 17 Aug 2008) | 2 lines Work around PackageMaker bug in XCode-2.5. ------------------------------------------------------------------------ r1638 | adk0212 | 2008-08-17 10:43:13 -0400 (Sun, 17 Aug 2008) | 2 lines Update Darwin universal binary instructions. ------------------------------------------------------------------------ r1637 | skoona | 2008-08-15 01:24:50 -0400 (Fri, 15 Aug 2008) | 4 lines Added setsockopt() to sknet_open() to resolve timeout related issue. I set it to 200ms initially, need to test a bet before releasing. James, ------------------------------------------------------------------------ r1635 | adk0212 | 2008-08-03 16:24:04 -0400 (Sun, 03 Aug 2008) | 3 lines A convenient side-effect of the flags split is that deps now work correctly during a universal binary build. ------------------------------------------------------------------------ r1634 | adk0212 | 2008-08-03 12:51:16 -0400 (Sun, 03 Aug 2008) | 4 lines Fix a few unsafe uses of sprintf and strcat. Although OpenBSD warns about several more, these other instances are demonstrably correct as-written and are therefore unchanged. ------------------------------------------------------------------------ r1633 | adk0212 | 2008-08-03 11:13:33 -0400 (Sun, 03 Aug 2008) | 2 lines Update Darwin build instructions for CPPFLAGS/CFLAGS/CXXFLAGS split. ------------------------------------------------------------------------ r1632 | adk0212 | 2008-08-03 11:00:05 -0400 (Sun, 03 Aug 2008) | 2 lines gapcmon build fixes for new CPPFLAGS/CFLAGS/CXXFLAGS split. ------------------------------------------------------------------------ r1631 | adk0212 | 2008-08-03 10:51:57 -0400 (Sun, 03 Aug 2008) | 3 lines Regen configure script on Linux. OpenBSD autoconf searches for X11 differently (and possibly incorrectly). ------------------------------------------------------------------------ r1630 | adk0212 | 2008-08-03 10:48:45 -0400 (Sun, 03 Aug 2008) | 4 lines Fix configure warnings for gd.h by properly splitting compiler flags versus preprocessor flags. CFLAGS=C compiler flags, CXXFLAGS=C++ compiler flags, CPPFLAGS=C preprocessor flags. ------------------------------------------------------------------------ r1629 | adk0212 | 2008-08-02 19:13:28 -0400 (Sat, 02 Aug 2008) | 2 lines Regen configure script from configure.in. ------------------------------------------------------------------------ r1628 | adk0212 | 2008-08-02 19:11:29 -0400 (Sat, 02 Aug 2008) | 3 lines Fix cgi build on OpenBSD. libgd on OpenBSD requires X_LIBS for libfreetype and libfontconfig. ------------------------------------------------------------------------ r1627 | adk0212 | 2008-07-25 10:17:51 -0400 (Fri, 25 Jul 2008) | 2 lines Update ChangeLog after win32 exit fix. ------------------------------------------------------------------------ r1626 | adk0212 | 2008-07-25 09:18:03 -0400 (Fri, 25 Jul 2008) | 4 lines Fix handling of old-style exit requests (WM_QUIT message to hidden window). Apparently PeekMessage() is not sufficient, so go back to using GetMessage and spawn a separate thread to watch for the global exit event. ------------------------------------------------------------------------ r1625 | adk0212 | 2008-07-24 16:29:33 -0400 (Thu, 24 Jul 2008) | 2 lines Prep for 3.14.5 release. ------------------------------------------------------------------------ r1624 | adk0212 | 2008-07-24 16:12:58 -0400 (Thu, 24 Jul 2008) | 3 lines Save $INSTDIR in registry for future use. Also remove examples/ directory from install package since almost nothing in there applies to win32. ------------------------------------------------------------------------ r1623 | adk0212 | 2008-07-24 16:10:58 -0400 (Thu, 24 Jul 2008) | 2 lines Remove another obsolete sample config. ------------------------------------------------------------------------ r1622 | adk0212 | 2008-07-24 16:08:18 -0400 (Thu, 24 Jul 2008) | 2 lines Remove obsolete configuration examples. ------------------------------------------------------------------------ r1621 | skoona | 2008-07-12 22:51:13 -0400 (Sat, 12 Jul 2008) | 2 lines Update the ChangeLog ------------------------------------------------------------------------ r1620 | skoona | 2008-07-12 22:32:21 -0400 (Sat, 12 Jul 2008) | 16 lines Fix two of two: KDE issue, because of the _iconify() api issue, _hide() was chosen. _ hide() presents a useability issue where its possible hide all windows in such a way that no artifact is visible for you to use to restore a window. This is caused by the use of gtk_widget_hide() instead of gtk_window_iconify(); thus the only solution is to remove the close buttons off both the main window and all monitor windows. Its the close button that presents the active-but-no-window effect. Problem Cause: KDE Window Manager Behaviour Changed -- gtk_window_iconify() ignored. Problem Resolved: Removed Close Button from all windows. Switched to gtk_widget_hide() to manage window visibility. James, ------------------------------------------------------------------------ r1619 | skoona | 2008-07-12 20:23:35 -0400 (Sat, 12 Jul 2008) | 2 lines Part two of the kde fix failed. Icon-mode works fine. Window mode can find itself without a takslist entry and effecctively invisible with no way to recall the active program. ------------------------------------------------------------------------ r1618 | adk0212 | 2008-07-12 15:13:56 -0400 (Sat, 12 Jul 2008) | 2 lines Update to nsis-2.38 ------------------------------------------------------------------------ r1617 | skoona | 2008-07-12 13:53:54 -0400 (Sat, 12 Jul 2008) | 2 lines Part two of two parts -- kde iconify fix ------------------------------------------------------------------------ r1616 | skoona | 2008-07-12 12:54:17 -0400 (Sat, 12 Jul 2008) | 2 lines Part one of two parts -- kde iconify fix ------------------------------------------------------------------------ r1607 | adk0212 | 2008-06-29 11:12:10 -0400 (Sun, 29 Jun 2008) | 5 lines Fix bug in LOWBATT glitch handling. We must examine LOWBATT for changes every time thru the status loop, not just during the OnBattery state. Otherwise we can miss the initial LOWBATT assertion, which defeats the glitch rejection logic. ------------------------------------------------------------------------ r1606 | adk0212 | 2008-06-24 19:24:43 -0400 (Tue, 24 Jun 2008) | 2 lines Silly spacing fix. ------------------------------------------------------------------------ r1605 | adk0212 | 2008-06-24 19:23:18 -0400 (Tue, 24 Jun 2008) | 3 lines Fail configure if required tools are not found. Fix targets.mak to reference a few more tools by variable instead of hardcoded name. ------------------------------------------------------------------------ r1604 | adk0212 | 2008-06-21 17:04:15 -0400 (Sat, 21 Jun 2008) | 3 lines Clean up win32 compat. Remove unused functions and files. Remove wide char support. Organize compat.h. ------------------------------------------------------------------------ r1603 | adk0212 | 2008-06-21 14:43:56 -0400 (Sat, 21 Jun 2008) | 6 lines Improve apctray multiple instance behavior for /add, /del, and /kill on modern platforms (Win2K and newer). Monitor registry for changes caused by /add and /del and automatically reset when a change is detected. Also ensure /kill will terminate all apctray instances, even those running in other sessions. ------------------------------------------------------------------------ r1602 | adk0212 | 2008-06-19 18:23:50 -0400 (Thu, 19 Jun 2008) | 3 lines Support shutting down apcupsd instances running in other sessions (such as terminal services or remote desktop sessions). ------------------------------------------------------------------------ r1601 | adk0212 | 2008-06-15 14:11:06 -0400 (Sun, 15 Jun 2008) | 2 lines Use 'tr' to strip trailing newline from 'echo' instead of 'echo -n'. ------------------------------------------------------------------------ r1600 | adk0212 | 2008-06-15 09:15:07 -0400 (Sun, 15 Jun 2008) | 2 lines Update install to use new CHKCFG macro. ------------------------------------------------------------------------ r1599 | adk0212 | 2008-06-15 09:10:47 -0400 (Sun, 15 Jun 2008) | 2 lines Update redhat to use new CHKCFG macro. ------------------------------------------------------------------------ r1598 | adk0212 | 2008-06-15 09:04:31 -0400 (Sun, 15 Jun 2008) | 2 lines Fix harmless but annoying compiler warning on suse. ------------------------------------------------------------------------ r1597 | adk0212 | 2008-06-15 09:03:19 -0400 (Sun, 15 Jun 2008) | 7 lines Fix 'make install' on suse. Sadly, suse's chkconfig always returns success for --list even when the service does not exist. So we add a more sophisticated chkconfig handler which tests for existence of the init script manually, then invokes chkconfig. The whole thing is hidden behind a macro. Also add CHKCONFIG definition (currently always /sbin/chkconfig) in case we someday encounter a distro that hides it elsewhere. ------------------------------------------------------------------------ r1596 | adk0212 | 2008-06-11 07:47:13 -0400 (Wed, 11 Jun 2008) | 3 lines Update PCNET info: minimum password length is 15 chars, default username is 'apc', no known way to change the username. ------------------------------------------------------------------------ r1595 | adk0212 | 2008-06-11 07:39:43 -0400 (Wed, 11 Jun 2008) | 3 lines Add a hex dump function and use it from pcnet and usb drivers instead of manually coding ugly loops. ------------------------------------------------------------------------ r1594 | adk0212 | 2008-06-11 07:20:30 -0400 (Wed, 11 Jun 2008) | 2 lines Add captured packets for testing PCNET driver. ------------------------------------------------------------------------ r1593 | adk0212 | 2008-06-09 21:22:47 -0400 (Mon, 09 Jun 2008) | 4 lines Use $(ECHO). Important for 'echo -n' on some platforms, and we might as well use it everywhere we use 'echo'. Thanks to Jeremy Daniel for finding and fixing this on Mac OS X. ------------------------------------------------------------------------ r1592 | adk0212 | 2008-06-09 21:16:48 -0400 (Mon, 09 Jun 2008) | 3 lines Remove conditional HAVE_NISLIB settings. HAVE_NISLIB is set already set unconditionally. ------------------------------------------------------------------------ r1591 | adk0212 | 2008-06-01 17:57:56 -0400 (Sun, 01 Jun 2008) | 7 lines Fix first install failure on redhat and suse. We were unconditionally running 'chkconfig --del apcupsd' which failed if apcupsd was not already installed. Now we check 'chkconfig --list apcupsd' first to see if chkconfig believes apcupsd is installed. Make same fix in uninstall. Also change most uninstall steps to allow failure. This facilitates the best- effort uninstall of an aborted or otherwise botched install. ------------------------------------------------------------------------ r1590 | fleetworks | 2008-05-31 08:42:50 -0400 (Sat, 31 May 2008) | 2 lines Add restart of daemon on upgrade. ------------------------------------------------------------------------ r1583 | adk0212 | 2008-05-25 14:46:34 -0400 (Sun, 25 May 2008) | 2 lines Update for 3.14.4 release. ------------------------------------------------------------------------ r1581 | adk0212 | 2008-05-18 14:21:27 -0400 (Sun, 18 May 2008) | 2 lines Update ChangeLog. ------------------------------------------------------------------------ r1580 | adk0212 | 2008-05-18 14:18:54 -0400 (Sun, 18 May 2008) | 3 lines Fix init script location on SuSE. It should be /etc/rc.d, but we were placing the file in /etc/rc.d/init.d. ------------------------------------------------------------------------ r1579 | adk0212 | 2008-05-18 13:16:48 -0400 (Sun, 18 May 2008) | 2 lines Fix release date. ------------------------------------------------------------------------ r1578 | adk0212 | 2008-05-18 13:15:34 -0400 (Sun, 18 May 2008) | 2 lines Prep for 3.14.4 release. ------------------------------------------------------------------------ r1577 | adk0212 | 2008-05-18 13:12:30 -0400 (Sun, 18 May 2008) | 2 lines Add 'make install' support for man pages. ------------------------------------------------------------------------ r1576 | adk0212 | 2008-05-12 20:09:47 -0400 (Mon, 12 May 2008) | 2 lines Remove obsolete files. ------------------------------------------------------------------------ r1575 | adk0212 | 2008-05-12 20:06:49 -0400 (Mon, 12 May 2008) | 2 lines Update contributors list. This is probably still way out of date. ------------------------------------------------------------------------ r1574 | adk0212 | 2008-05-12 20:01:25 -0400 (Mon, 12 May 2008) | 2 lines Remove references to powerflute. ------------------------------------------------------------------------ r1573 | adk0212 | 2008-05-11 18:34:37 -0400 (Sun, 11 May 2008) | 2 lines Remove --with-powerflute flag from specs. ------------------------------------------------------------------------ r1572 | adk0212 | 2008-05-11 18:18:53 -0400 (Sun, 11 May 2008) | 2 lines Remove old changelog. ------------------------------------------------------------------------ r1571 | adk0212 | 2008-05-11 17:00:55 -0400 (Sun, 11 May 2008) | 2 lines Prep for 3.14.4 test release. ------------------------------------------------------------------------ r1570 | adk0212 | 2008-05-11 16:23:17 -0400 (Sun, 11 May 2008) | 2 lines Remove unused file. ------------------------------------------------------------------------ r1569 | adk0212 | 2008-05-11 10:24:13 -0400 (Sun, 11 May 2008) | 2 lines Update Mac OS X universal binary build instructions. ------------------------------------------------------------------------ r1568 | adk0212 | 2008-05-11 10:10:35 -0400 (Sun, 11 May 2008) | 2 lines Remove unnecessary dependency includes. ------------------------------------------------------------------------ r1567 | adk0212 | 2008-05-11 09:56:51 -0400 (Sun, 11 May 2008) | 2 lines Remove some obsolete Makefile.in ------------------------------------------------------------------------ r1566 | adk0212 | 2008-05-11 09:56:16 -0400 (Sun, 11 May 2008) | 2 lines New Makefile for examples/ and source fixes to build with C++ compiler. ------------------------------------------------------------------------ r1565 | adk0212 | 2008-05-10 20:10:48 -0400 (Sat, 10 May 2008) | 2 lines Micor cleanups: Rename 'INST' to 'COPY'. Remove extraneous semicolons. ------------------------------------------------------------------------ r1564 | adk0212 | 2008-05-10 20:07:52 -0400 (Sat, 10 May 2008) | 5 lines Better solution for install ordering. Invoke make explicitly to build targets and then again to perform the install. This is just an extension of the same trick used to force 'all' to build subdirs before local targets. ------------------------------------------------------------------------ r1563 | adk0212 | 2008-05-10 13:54:40 -0400 (Sat, 10 May 2008) | 4 lines Fix parallel 'make install' from an unbuilt tree. Requires manually making install-* depend on all-targets. I'd prefer this be done automatically but I cannot find a way that works (yet). ------------------------------------------------------------------------ r1562 | adk0212 | 2008-05-10 11:19:09 -0400 (Sat, 10 May 2008) | 2 lines Do not perform platform install in parallel. ------------------------------------------------------------------------ r1561 | adk0212 | 2008-05-10 11:18:43 -0400 (Sat, 10 May 2008) | 2 lines Recurse into platforms/ after src/. ------------------------------------------------------------------------ r1560 | adk0212 | 2008-05-10 10:52:46 -0400 (Sat, 10 May 2008) | 2 lines Install banners for alpha. ------------------------------------------------------------------------ r1559 | adk0212 | 2008-05-10 10:51:15 -0400 (Sat, 10 May 2008) | 2 lines Add banners to 'make install'. ------------------------------------------------------------------------ r1558 | adk0212 | 2008-05-10 10:47:37 -0400 (Sat, 10 May 2008) | 2 lines Tweak install/uninstall banner spacing. ------------------------------------------------------------------------ r1557 | adk0212 | 2008-05-10 10:47:19 -0400 (Sat, 10 May 2008) | 2 lines 'make install' support for unifix and yellowdog. ------------------------------------------------------------------------ r1556 | adk0212 | 2008-05-09 20:04:45 -0400 (Fri, 09 May 2008) | 3 lines 'make install' support for SuSE. Plus remove some bitrotted platform files for SuSE 8.x. ------------------------------------------------------------------------ r1555 | adk0212 | 2008-05-09 19:39:56 -0400 (Fri, 09 May 2008) | 2 lines 'make install' support for sun. ------------------------------------------------------------------------ r1554 | adk0212 | 2008-05-08 19:37:16 -0400 (Thu, 08 May 2008) | 2 lines Do not autogenerate platform/*/Makefile any more. ------------------------------------------------------------------------ r1553 | adk0212 | 2008-05-08 19:36:45 -0400 (Thu, 08 May 2008) | 2 lines Add install/uninstall banner macros. ------------------------------------------------------------------------ r1552 | adk0212 | 2008-05-08 19:36:07 -0400 (Thu, 08 May 2008) | 2 lines Add some path variables needed by platform install scripts. ------------------------------------------------------------------------ r1551 | adk0212 | 2008-05-08 19:35:21 -0400 (Thu, 08 May 2008) | 2 lines 'make install' support for gentoo, hpux, mandrake, slackware. ------------------------------------------------------------------------ r1550 | adk0212 | 2008-05-08 18:57:15 -0400 (Thu, 08 May 2008) | 2 lines 'make install' support for *BSD ------------------------------------------------------------------------ r1549 | skoona | 2008-05-06 20:16:56 -0400 (Tue, 06 May 2008) | 2 lines Corrected the use of NOMPOWER and the calc of current usage amount ------------------------------------------------------------------------ r1548 | adk0212 | 2008-05-04 11:30:42 -0400 (Sun, 04 May 2008) | 3 lines Remove powerflute option from configure. Powerflute has been broken for several releases after the removal of rawupsstats support from NIS ------------------------------------------------------------------------ r1547 | adk0212 | 2008-05-04 11:13:57 -0400 (Sun, 04 May 2008) | 4 lines Add a heuristic to fix up incorrect NOMINV or NOMOUTV. Some UPSes (RS 500) report decivolts instead of volts. Reported by Kirill S. Bychkov . ------------------------------------------------------------------------ r1546 | adk0212 | 2008-05-04 10:43:27 -0400 (Sun, 04 May 2008) | 2 lines Update to NSIS 2.37. ------------------------------------------------------------------------ r1545 | adk0212 | 2008-05-04 10:43:12 -0400 (Sun, 04 May 2008) | 3 lines Add win32/Makefile to generate list. Necessary since we're not rewriting the win32 Makefile stuff yet. ------------------------------------------------------------------------ r1544 | skoona | 2008-04-20 19:03:10 -0400 (Sun, 20 Apr 2008) | 13 lines - Removed close() fron sknet_net_close() api. g_io_channel_shutdown() handled the close and shutdown of the socket. second close was actually closing an active socket from another thread (i.e. reuse #) discovered on a quad-core platform. - Added ICON_DIR to compiler makefiles to support _load_icons ability to find icons at run-time. $(datadir) is passed into ICON_DIR; its assumed datadir include $(DISTDIR). This change was pointed out by Kirill S. Bychkov in Feb/2008. James, ------------------------------------------------------------------------ r1543 | adk0212 | 2008-04-19 10:12:46 -0400 (Sat, 19 Apr 2008) | 2 lines Remove mention of serial port since there are many other comms types now. ------------------------------------------------------------------------ r1542 | adk0212 | 2008-04-07 19:03:13 -0400 (Mon, 07 Apr 2008) | 3 lines Add 'make install' support for alpha, darwin, debian, engarde, and unknown. Also misc fixes to existing install support. ------------------------------------------------------------------------ r1541 | adk0212 | 2008-04-06 20:24:38 -0400 (Sun, 06 Apr 2008) | 2 lines Don't autogenerate redhat Makefile. ------------------------------------------------------------------------ r1540 | adk0212 | 2008-04-06 19:35:52 -0400 (Sun, 06 Apr 2008) | 2 lines Remove unused files: Various Makefile.in, gd1.2/, intl/, po/. ------------------------------------------------------------------------ r1539 | adk0212 | 2008-04-06 19:09:02 -0400 (Sun, 06 Apr 2008) | 2 lines Remove unused file. ------------------------------------------------------------------------ r1538 | adk0212 | 2008-04-06 19:07:43 -0400 (Sun, 06 Apr 2008) | 3 lines First round of 'make install' implementation. Basic install/uninstall is working. Only platform implemented so far is redhat. ------------------------------------------------------------------------ r1537 | adk0212 | 2008-04-04 19:11:15 -0400 (Fri, 04 Apr 2008) | 2 lines Fix clean output on Solaris. ------------------------------------------------------------------------ r1536 | adk0212 | 2008-04-04 19:01:03 -0400 (Fri, 04 Apr 2008) | 5 lines Fix gapcmon build on OpenSolaris. On OpenSolaris, gethostbyname_r() is in libnsl. Also fix up some tests in configure to use AC_SEARCH_LIBS. Thanks to James Dean for loaning me an ssh login on his OpenSolaris box. ------------------------------------------------------------------------ r1535 | adk0212 | 2008-04-02 18:55:31 -0400 (Wed, 02 Apr 2008) | 7 lines Add new make system - configure and build works (including dependencies and parallel make) - 'make install' not yet implemented - i18n support removed - included libgd support removed - obsolete Makefile.in files will remain until 'make install' is complete ------------------------------------------------------------------------ r1533 | adk0212 | 2008-02-06 17:53:36 -0500 (Wed, 06 Feb 2008) | 4 lines Fix hal policy file syntax. For some reason this blatantly incorrect file actually works on RHEL5 (hal-0.5.8). Thanks to Andrew Telford for correcting it. ------------------------------------------------------------------------ r1532 | adk0212 | 2008-02-03 16:37:01 -0500 (Sun, 03 Feb 2008) | 2 lines Revert ctime_r() change. It is not actually necessary. ------------------------------------------------------------------------ r1531 | adk0212 | 2008-02-03 15:48:14 -0500 (Sun, 03 Feb 2008) | 2 lines Fix gapcmon compile error on Solaris: Multiple variants of ctime_r(). ------------------------------------------------------------------------ r1530 | adk0212 | 2008-02-03 15:32:25 -0500 (Sun, 03 Feb 2008) | 2 lines Fix libapcnis.c compile error on Solaris. ------------------------------------------------------------------------ r1529 | fleetworks | 2008-02-03 12:22:31 -0500 (Sun, 03 Feb 2008) | 2 lines Add debug package to strip suse. ------------------------------------------------------------------------ r1528 | adk0212 | 2008-01-29 19:01:20 -0500 (Tue, 29 Jan 2008) | 2 lines Fix build on OpenBSD: Need to include netinet/in.h for struct sockaddr_in. ------------------------------------------------------------------------ r1527 | adk0212 | 2008-01-28 21:14:57 -0500 (Mon, 28 Jan 2008) | 3 lines Add fake (not thread-safe) gethostbyname_r() for platforms that don't have it. I'm looking at you, OpenBSD. ------------------------------------------------------------------------ r1526 | adk0212 | 2008-01-27 12:00:32 -0500 (Sun, 27 Jan 2008) | 3 lines Add POLLTIME directive to control UPS polling interval. NETTIME is accepted as a synonym for compatibility with old config files. ------------------------------------------------------------------------ r1525 | adk0212 | 2008-01-27 11:22:58 -0500 (Sun, 27 Jan 2008) | 4 lines Sanify net error handling. All net library functions now return -errno on failure. Kill off global net_errno and net_errmsg. Improve apcaccess error messages. ------------------------------------------------------------------------ r1523 | adk0212 | 2008-01-27 09:56:56 -0500 (Sun, 27 Jan 2008) | 2 lines Another missing update. ------------------------------------------------------------------------ r1522 | adk0212 | 2008-01-27 09:49:42 -0500 (Sun, 27 Jan 2008) | 2 lines Fix compile errors from incomplete input vs feature report conversion. ------------------------------------------------------------------------ r1514 | adk0212 | 2008-01-22 20:10:08 -0500 (Tue, 22 Jan 2008) | 3 lines Debian is now using the standard NIS port, 3551. Contributed by imacat ------------------------------------------------------------------------ r1513 | adk0212 | 2008-01-20 14:58:56 -0500 (Sun, 20 Jan 2008) | 2 lines Update web site for 3.14.3. ------------------------------------------------------------------------ r1511 | adk0212 | 2008-01-19 16:48:36 -0500 (Sat, 19 Jan 2008) | 2 lines Updates for 3.14.3 release. ------------------------------------------------------------------------ r1510 | adk0212 | 2008-01-19 13:43:52 -0500 (Sat, 19 Jan 2008) | 2 lines Merge gapcmon changes from HEAD 1.41. ------------------------------------------------------------------------ r1509 | adk0212 | 2007-12-02 11:38:02 -0500 (Sun, 02 Dec 2007) | 2 lines Fix compile warning. ------------------------------------------------------------------------ r1508 | adk0212 | 2007-11-29 19:49:02 -0500 (Thu, 29 Nov 2007) | 3 lines Update build instructions for XCode3/Leopard. Many thanks to Dennis Wurster for loaning me a Leopard-capable G4 to develop on. ------------------------------------------------------------------------ r1507 | adk0212 | 2007-11-21 17:09:30 -0500 (Wed, 21 Nov 2007) | 7 lines Fix bugs that could cause NIS-net driver to get stuck waiting for comms to be restored instead of shutting down. This included adding a timeout for connection attempts in net_open() and removing a wait-for-comms loop from the net driver. Also fix up fallout from apclibnis cleanups in apcaccess. Thanks to Daniel Born for reporting the issue and testing fixes. ------------------------------------------------------------------------ r1506 | adk0212 | 2007-11-21 17:05:03 -0500 (Wed, 21 Nov 2007) | 7 lines Add configure parameter to control location of HAL policy file. Install policy file to this path. By default, the policy file is only installed on Linux systems. Other platforms need to specify --with-halpolicydir=DIR to configure. Linux systems can use this same switch to change the default install path. (Files missed in last commit.) ------------------------------------------------------------------------ r1504 | fleetworks | 2007-11-18 10:25:13 -0500 (Sun, 18 Nov 2007) | 2 lines Add halpolicydir to configure statement. ------------------------------------------------------------------------ r1503 | fleetworks | 2007-11-18 10:18:49 -0500 (Sun, 18 Nov 2007) | 2 lines Make installs the hal policy file now. ------------------------------------------------------------------------ r1502 | adk0212 | 2007-11-17 14:09:23 -0500 (Sat, 17 Nov 2007) | 6 lines Add configure parameter to control location of HAL policy file. Install policy file to this path. By default, the policy file is only installed on Linux systems. Other platforms need to specify --with-halpolicydir=DIR to configure. Linux systems can use this same switch to change the default install path. ------------------------------------------------------------------------ r1501 | adk0212 | 2007-11-17 14:06:38 -0500 (Sat, 17 Nov 2007) | 2 lines Revert HAL policy file change. We'll do this at a higher level instead. ------------------------------------------------------------------------ r1500 | fleetworks | 2007-11-17 10:48:06 -0500 (Sat, 17 Nov 2007) | 2 lines Add hal policy file. ------------------------------------------------------------------------ r1499 | fleetworks | 2007-11-17 10:46:35 -0500 (Sat, 17 Nov 2007) | 2 lines Add hal policy file. ------------------------------------------------------------------------ r1498 | adk0212 | 2007-11-17 10:00:27 -0500 (Sat, 17 Nov 2007) | 2 lines Upgrade to nsis-2.33. ------------------------------------------------------------------------ r1497 | adk0212 | 2007-11-17 09:48:25 -0500 (Sat, 17 Nov 2007) | 2 lines Remove extraneous comment close tag. ------------------------------------------------------------------------ r1496 | adk0212 | 2007-11-17 09:34:46 -0500 (Sat, 17 Nov 2007) | 3 lines Add policy file to disable hald-addon-hid-ups. Automatically install and uninstall this policy on Redhat systems. ------------------------------------------------------------------------ r1495 | adk0212 | 2007-11-13 18:23:15 -0500 (Tue, 13 Nov 2007) | 2 lines Fix debian package URLs. Found by Chris Reeves . ------------------------------------------------------------------------ r1494 | fleetworks | 2007-11-10 08:17:46 -0500 (Sat, 10 Nov 2007) | 2 lines Update for suse 10.3 ------------------------------------------------------------------------ r1493 | adk0212 | 2007-11-09 18:34:48 -0500 (Fri, 09 Nov 2007) | 2 lines Update to nsis-2.32. ------------------------------------------------------------------------ r1492 | adk0212 | 2007-10-30 18:46:49 -0400 (Tue, 30 Oct 2007) | 2 lines Fix changelog links for 3.14.2. ------------------------------------------------------------------------ r1491 | adk0212 | 2007-10-27 13:15:14 -0400 (Sat, 27 Oct 2007) | 2 lines Missed part of write report conversion. ------------------------------------------------------------------------ r1490 | adk0212 | 2007-10-27 13:14:24 -0400 (Sat, 27 Oct 2007) | 2 lines Add support for reading/writing transfer voltage on USB models. ------------------------------------------------------------------------ r1489 | adk0212 | 2007-10-27 13:13:15 -0400 (Sat, 27 Oct 2007) | 5 lines When reading, use INPUT or FEATURE report (prefer INPUT). When writing, use FEATURE report only. This is necessary to properly support writes on UPSes that offer the same usage in both types of reports. ------------------------------------------------------------------------ r1481 | adk0212 | 2007-10-06 10:54:23 -0400 (Sat, 06 Oct 2007) | 4 lines Eliminate "warning: deprecated conversion from string constant to 'char*'" warnings emitted from gcc-4.2.1 (earlier versions with -Wwrite-strings). Contributed by Steve Yarmie . ------------------------------------------------------------------------ r1475 | adk0212 | 2007-09-30 15:45:37 -0400 (Sun, 30 Sep 2007) | 2 lines Merge gapcmon changes from HEAD. ------------------------------------------------------------------------ r1472 | adk0212 | 2007-09-22 13:35:27 -0400 (Sat, 22 Sep 2007) | 2 lines Add units to NOMINV, NOMOUTV, and NOMBATTV stats. ------------------------------------------------------------------------ r1471 | adk0212 | 2007-09-22 13:33:29 -0400 (Sat, 22 Sep 2007) | 3 lines Add support for Nominal Power (aka Configured Active Power) reading. Credit to Lars Randers for most of the code. ------------------------------------------------------------------------ r1470 | adk0212 | 2007-09-22 13:10:16 -0400 (Sat, 22 Sep 2007) | 2 lines Convert eleventy skillion CI_* defines to an enumeration. ------------------------------------------------------------------------ r1469 | adk0212 | 2007-09-22 08:48:35 -0400 (Sat, 22 Sep 2007) | 2 lines Update web site for 3.14.2 release. ------------------------------------------------------------------------ r1467 | adk0212 | 2007-09-15 17:07:10 -0400 (Sat, 15 Sep 2007) | 2 lines Update ChangeLog, ReleaseNotes, and date for 3.14.2 release. ------------------------------------------------------------------------ r1466 | adk0212 | 2007-09-15 10:48:35 -0400 (Sat, 15 Sep 2007) | 2 lines Remove commented-out code. ------------------------------------------------------------------------ r1465 | adk0212 | 2007-09-15 10:48:16 -0400 (Sat, 15 Sep 2007) | 2 lines Misc cleanup. ------------------------------------------------------------------------ r1464 | adk0212 | 2007-09-15 10:48:00 -0400 (Sat, 15 Sep 2007) | 2 lines Fix handle leaks when adding/deleting instances. ------------------------------------------------------------------------ r1463 | adk0212 | 2007-09-10 19:35:00 -0400 (Mon, 10 Sep 2007) | 2 lines Update NSIS to 2.30. ------------------------------------------------------------------------ r1462 | adk0212 | 2007-09-10 19:31:16 -0400 (Mon, 10 Sep 2007) | 2 lines Bump version to 3.14.2. ------------------------------------------------------------------------ r1461 | adk0212 | 2007-09-10 19:09:49 -0400 (Mon, 10 Sep 2007) | 5 lines Prefer FEATURE reports over INPUT reports when searching for usages. This will fix compatiblity with BackUPS LCD models which have present but non- functional INPUT reports. It may break compatibility with other models, so fingers are crossed. ------------------------------------------------------------------------ r1460 | adk0212 | 2007-09-10 19:08:12 -0400 (Mon, 10 Sep 2007) | 2 lines Minor cleanup and spelling fix. ------------------------------------------------------------------------ r1459 | adk0212 | 2007-08-28 19:57:51 -0400 (Tue, 28 Aug 2007) | 5 lines Address g++ linker vs. libsupc++ differently: Default linker to gcc if none is specified. This avoids overriding LD= passed to configure since if the user asks for an explicit LD we really should honor it (and it's needed for building universal binaries on OS X). ------------------------------------------------------------------------ r1458 | adk0212 | 2007-08-28 19:02:22 -0400 (Tue, 28 Aug 2007) | 3 lines Remove dependency on libc++ (again). Must use gcc as linker when using libsupc++ since g++ automatically links against full libc++. ------------------------------------------------------------------------ r1457 | adk0212 | 2007-08-25 15:01:34 -0400 (Sat, 25 Aug 2007) | 5 lines Fix race between attach_ups() and detach_ups() which could result in the UPSINFO structure being freed prematurely. Thanks to James Abbott for running many tests to help me find this bug. ------------------------------------------------------------------------ r1456 | adk0212 | 2007-08-23 18:43:08 -0400 (Thu, 23 Aug 2007) | 4 lines Correct multimon.conf humidity monitoring. Problem fixed by Patrick Frei. Reference: https://bugzilla.novell.com/show_bug.cgi?id=199834 ------------------------------------------------------------------------ r1455 | adk0212 | 2007-08-06 20:17:20 -0400 (Mon, 06 Aug 2007) | 2 lines Exit apctray if GetMessage() returns an error. ------------------------------------------------------------------------ r1454 | adk0212 | 2007-08-06 20:16:37 -0400 (Mon, 06 Aug 2007) | 2 lines Use enum for application-defined messages. ------------------------------------------------------------------------ r1453 | adk0212 | 2007-08-06 20:16:15 -0400 (Mon, 06 Aug 2007) | 2 lines Redraw tray icons politely after an Explorer crash. ------------------------------------------------------------------------ r1452 | adk0212 | 2007-08-05 17:31:56 -0400 (Sun, 05 Aug 2007) | 5 lines Fix bug with multi-threaded net_open() calls. net_open() was using a global buffer for the destination address. Yikes! Bug manifestied itself in apctray with multiple monitors occasionally (and timing-dependently) pointing to the wrong UPS. ------------------------------------------------------------------------ r1451 | adk0212 | 2007-08-03 15:08:59 -0400 (Fri, 03 Aug 2007) | 2 lines More argvalue to its primary user, apcconfig.c. ------------------------------------------------------------------------ r1450 | adk0212 | 2007-08-03 15:08:26 -0400 (Fri, 03 Aug 2007) | 4 lines Remove SO_REUSEADDR; we'd only need this for TCP. Set SO_BROADCAST since some platforms (Windows) seem to require it in order to receive broadcast packets. (Most platforms use it only to enable *sending* broadcasts.) ------------------------------------------------------------------------ r1449 | adk0212 | 2007-08-03 14:41:05 -0400 (Fri, 03 Aug 2007) | 2 lines Don't leak unnecessary descriptors to child when execing apccontrol. ------------------------------------------------------------------------ r1448 | adk0212 | 2007-08-03 13:52:05 -0400 (Fri, 03 Aug 2007) | 3 lines Documentation updates: Fix up udev info for modern Linux distros. Update Windows section for apctray. ------------------------------------------------------------------------ r1447 | adk0212 | 2007-08-03 11:49:24 -0400 (Fri, 03 Aug 2007) | 5 lines Wait 20 seconds before declaring COMMLOST. This is necessary when using a smart serial cable on an UPS with an SNMP monitoring card installed. The SNMP card appears to disrupt serial comms for several seconds when interesting events are in progress. ------------------------------------------------------------------------ r1446 | adk0212 | 2007-08-03 11:47:22 -0400 (Fri, 03 Aug 2007) | 2 lines Add command help key since I can never remember what the keycodes are. ------------------------------------------------------------------------ r1445 | adk0212 | 2007-08-03 11:20:29 -0400 (Fri, 03 Aug 2007) | 4 lines apccontrol cleanups: powerout and mainsback should not wall; that is done by onbattery/offbattery under the control of ONBATTERYDELAY. Also remove obsolete 'restartme' event from scripts and documentation. ------------------------------------------------------------------------ r1444 | adk0212 | 2007-08-03 11:17:38 -0400 (Fri, 03 Aug 2007) | 2 lines Remove lots of obsolete code. 'status' is now the only supported option. ------------------------------------------------------------------------ r1443 | adk0212 | 2007-08-01 19:05:51 -0400 (Wed, 01 Aug 2007) | 3 lines Enable SO_REUSEADDR on pcnet socket to prevent false EADDRINUSE after quick restarts. ------------------------------------------------------------------------ r1442 | adk0212 | 2007-07-26 16:36:28 -0400 (Thu, 26 Jul 2007) | 2 lines Remove duplicate line. Noticed by David P. Mott . ------------------------------------------------------------------------ r1441 | adk0212 | 2007-07-20 12:17:34 -0400 (Fri, 20 Jul 2007) | 2 lines Add support for simulating comm failure. ------------------------------------------------------------------------ r1440 | adk0212 | 2007-07-17 18:54:25 -0400 (Tue, 17 Jul 2007) | 2 lines Include /dev in hiddev search. ------------------------------------------------------------------------ r1439 | adk0212 | 2007-07-17 18:50:25 -0400 (Tue, 17 Jul 2007) | 3 lines Report time delta from start of program when displaying events. Contributed by David Fries . ------------------------------------------------------------------------ r1438 | adk0212 | 2007-07-16 20:28:09 -0400 (Mon, 16 Jul 2007) | 3 lines Add workaround for broken BackUPS Pro model that returns certain reports encoded in ASCII. Based on a patch from David Fries . ------------------------------------------------------------------------ r1437 | adk0212 | 2007-07-14 13:26:26 -0400 (Sat, 14 Jul 2007) | 2 lines Add/remove tray icons on the fly as instances are added or deleted. ------------------------------------------------------------------------ r1436 | adk0212 | 2007-07-14 13:05:22 -0400 (Sat, 14 Jul 2007) | 2 lines Add HOST field showing hostname:port to context menu. ------------------------------------------------------------------------ r1435 | adk0212 | 2007-07-14 13:04:52 -0400 (Sat, 14 Jul 2007) | 2 lines Update NSIS to version 2.29. ------------------------------------------------------------------------ r1434 | adk0212 | 2007-07-14 12:53:31 -0400 (Sat, 14 Jul 2007) | 2 lines Disable autorun when last instance removed. ------------------------------------------------------------------------ r1433 | adk0212 | 2007-07-01 14:30:32 -0400 (Sun, 01 Jul 2007) | 4 lines Fix SNMP port selection. Newer versions of Net-SNMP appear to ignore the session remote_port setting. The only way to override the default port is to include it in the peername string. ------------------------------------------------------------------------ r1432 | adk0212 | 2007-06-29 18:18:41 -0400 (Fri, 29 Jun 2007) | 4 lines Fix linux-usb device detection bug when multiple hiddev nodes are present. Fixes Fedora Bugzilla #245864: ------------------------------------------------------------------------ r1431 | adk0212 | 2007-06-19 20:43:23 -0400 (Tue, 19 Jun 2007) | 2 lines Update for 3.14.2-win32beta2 release. ------------------------------------------------------------------------ r1429 | adk0212 | 2007-06-18 20:23:41 -0400 (Mon, 18 Jun 2007) | 2 lines Regen ChangeLog after committing forgotten files. ------------------------------------------------------------------------ r1428 | adk0212 | 2007-06-18 19:49:45 -0400 (Mon, 18 Jun 2007) | 2 lines Change CMD* definitions to enumeration. ------------------------------------------------------------------------ r1427 | adk0212 | 2007-06-18 19:49:20 -0400 (Mon, 18 Jun 2007) | 2 lines Remove unused CMDDOREBOOT. ------------------------------------------------------------------------ r1426 | adk0212 | 2007-06-18 19:47:13 -0400 (Mon, 18 Jun 2007) | 2 lines Remove unused code. ------------------------------------------------------------------------ r1425 | adk0212 | 2007-06-18 19:45:52 -0400 (Mon, 18 Jun 2007) | 2 lines Regen ChangeLog for 3.14.2-win32beta2. ------------------------------------------------------------------------ r1424 | adk0212 | 2007-06-18 19:38:34 -0400 (Mon, 18 Jun 2007) | 2 lines Update for 3.14.2-win32beta2 release. ------------------------------------------------------------------------ r1423 | adk0212 | 2007-06-17 20:19:24 -0400 (Sun, 17 Jun 2007) | 2 lines Change StatMgr::Get() to return a managed string. ------------------------------------------------------------------------ r1422 | adk0212 | 2007-06-17 20:14:20 -0400 (Sun, 17 Jun 2007) | 2 lines Clean up apctray needless inlining and memory management. ------------------------------------------------------------------------ r1421 | adk0212 | 2007-06-17 19:49:45 -0400 (Sun, 17 Jun 2007) | 2 lines Cleanup. ------------------------------------------------------------------------ r1420 | adk0212 | 2007-06-17 19:47:08 -0400 (Sun, 17 Jun 2007) | 2 lines Gracefully handle unexpected return values from WaitForMultipleObjects(). ------------------------------------------------------------------------ r1419 | adk0212 | 2007-06-17 16:07:23 -0400 (Sun, 17 Jun 2007) | 5 lines Remove balloon notice support from popup utility. Furthermore, only display popup if we're on an ancient OS, apctray is not running, or balloon tips are disabled via a group policy. This way win98 and NT users will still get notifications of events, as will users not running apctray. ------------------------------------------------------------------------ r1418 | adk0212 | 2007-06-17 15:54:06 -0400 (Sun, 17 Jun 2007) | 4 lines Misc improvements: Detect self-test and set status string accordingly. Include UPS name in tool tip, when we know it. Change status string for NIS connection errors to distinguish that state from COMMLOST. ------------------------------------------------------------------------ r1417 | adk0212 | 2007-06-17 15:19:56 -0400 (Sun, 17 Jun 2007) | 2 lines Windows NT doesn't like the "Global\\" prefix on semaphore names. ------------------------------------------------------------------------ r1416 | adk0212 | 2007-06-17 13:19:54 -0400 (Sun, 17 Jun 2007) | 2 lines Fix bug where COMMLOST status transition was not reflected by icon. ------------------------------------------------------------------------ r1415 | adk0212 | 2007-06-17 13:15:08 -0400 (Sun, 17 Jun 2007) | 2 lines Suppress initial status balloon. ------------------------------------------------------------------------ r1414 | adk0212 | 2007-06-17 13:12:33 -0400 (Sun, 17 Jun 2007) | 2 lines Misc cleanup. ------------------------------------------------------------------------ r1413 | adk0212 | 2007-06-17 12:14:39 -0400 (Sun, 17 Jun 2007) | 10 lines Completely rewrite balloon tip handling. Balloon tips are posted automatically when the status text changes. This eliminates the need for the clunky "Receive local notifications" setting and allows us to post balloons for state changes on remote Apcupsd instances. Introduce the BalloonMgr to work around Windows one-balloon-at-a-time limitation. When monitoring multiple Apcupsd instances it will be common to need to post multiple balloon tips at once. The BalloonMgr handles posting the tips one at a time and timing the active balloon out early if new ones are waiting. This way all balloons will be shown, one after another. ------------------------------------------------------------------------ r1412 | adk0212 | 2007-06-17 09:42:54 -0400 (Sun, 17 Jun 2007) | 2 lines Add support for simulating battery attach/detach. ------------------------------------------------------------------------ r1411 | adk0212 | 2007-06-17 08:54:10 -0400 (Sun, 17 Jun 2007) | 2 lines Fix indentation. ------------------------------------------------------------------------ r1410 | adk0212 | 2007-06-13 20:07:45 -0400 (Wed, 13 Jun 2007) | 2 lines Reverse order of events in listbox so most recent is always at the top. ------------------------------------------------------------------------ r1409 | adk0212 | 2007-06-13 18:35:57 -0400 (Wed, 13 Jun 2007) | 3 lines Use NotifyUser when notifying about multiple instances so it obeys the /quiet flag. ------------------------------------------------------------------------ r1408 | adk0212 | 2007-06-13 18:34:08 -0400 (Wed, 13 Jun 2007) | 2 lines Prevent multiple instances of Apctray. ------------------------------------------------------------------------ r1407 | adk0212 | 2007-06-13 18:29:08 -0400 (Wed, 13 Jun 2007) | 2 lines Use some STL to simplify GetAll() and GetEvents() calls. ------------------------------------------------------------------------ r1406 | adk0212 | 2007-06-10 16:05:56 -0400 (Sun, 10 Jun 2007) | 2 lines Fix indentation. ------------------------------------------------------------------------ r1405 | adk0212 | 2007-06-10 16:05:43 -0400 (Sun, 10 Jun 2007) | 2 lines Add refresh button to events box. ------------------------------------------------------------------------ r1404 | adk0212 | 2007-06-10 16:04:55 -0400 (Sun, 10 Jun 2007) | 2 lines Add refresh button list stats now has. ------------------------------------------------------------------------ r1403 | adk0212 | 2007-06-10 14:03:31 -0400 (Sun, 10 Jun 2007) | 2 lines Update web site for 3.14.2-beta1 release. ------------------------------------------------------------------------ r1401 | adk0212 | 2007-06-10 10:13:19 -0400 (Sun, 10 Jun 2007) | 2 lines Final updates for apcupsd-3.14.2-win32beta1 release. ------------------------------------------------------------------------ r1400 | adk0212 | 2007-06-10 09:34:26 -0400 (Sun, 10 Jun 2007) | 2 lines Misc updates and small bug fixes. ------------------------------------------------------------------------ r1399 | adk0212 | 2007-06-10 09:33:18 -0400 (Sun, 10 Jun 2007) | 3 lines Updates for multi-instance apctray. Remove apctray parameter customization option for now. ------------------------------------------------------------------------ r1398 | adk0212 | 2007-06-09 21:34:12 -0400 (Sat, 09 Jun 2007) | 3 lines More multiple instance improvements. Also add refresh button to detailed status dialog. ------------------------------------------------------------------------ r1397 | adk0212 | 2007-06-09 20:02:35 -0400 (Sat, 09 Jun 2007) | 2 lines More changes for better multiple monitor support. ------------------------------------------------------------------------ r1396 | adk0212 | 2007-06-09 15:47:08 -0400 (Sat, 09 Jun 2007) | 4 lines Major rework to support monitoring multiple apcupsds with a single apctray instantiation. Includes basic management of monitoring instances. More fancy stuff to come. ------------------------------------------------------------------------ r1395 | adk0212 | 2007-06-07 19:43:08 -0400 (Thu, 07 Jun 2007) | 3 lines Updates for running multiple apctray instances simultaneously and properly shutting them down. ------------------------------------------------------------------------ r1394 | adk0212 | 2007-06-06 22:11:31 -0400 (Wed, 06 Jun 2007) | 2 lines Fix timeout bug. ------------------------------------------------------------------------ r1393 | adk0212 | 2007-06-06 22:06:47 -0400 (Wed, 06 Jun 2007) | 2 lines Shutdown status polling thread cleanly. ------------------------------------------------------------------------ r1392 | adk0212 | 2007-06-06 22:05:36 -0400 (Wed, 06 Jun 2007) | 3 lines Grab lock during destruction to prevent further operations. Also add copyright blocks. ------------------------------------------------------------------------ r1391 | adk0212 | 2007-06-06 21:26:12 -0400 (Wed, 06 Jun 2007) | 3 lines Reuse sockets in StatMgr. This prevents build-up of large numbers of sockets in the TIME_WAIT state. Also implement proper locking. ------------------------------------------------------------------------ r1390 | adk0212 | 2007-06-06 19:53:11 -0400 (Wed, 06 Jun 2007) | 2 lines Kill FillEventsBox function and associated grunge that is no longer used. ------------------------------------------------------------------------ r1389 | adk0212 | 2007-06-06 19:49:32 -0400 (Wed, 06 Jun 2007) | 2 lines Remove unused file. ------------------------------------------------------------------------ r1388 | adk0212 | 2007-06-06 19:48:05 -0400 (Wed, 06 Jun 2007) | 2 lines Remove unused files. ------------------------------------------------------------------------ r1387 | adk0212 | 2007-06-06 19:44:03 -0400 (Wed, 06 Jun 2007) | 2 lines Build object files in obj/ to reduce source dir clutter. ------------------------------------------------------------------------ r1386 | adk0212 | 2007-06-06 18:53:44 -0400 (Wed, 06 Jun 2007) | 3 lines Move installer files to installer/ directory. There are enough of them now that we should stop cluttering the main win32 source dir. ------------------------------------------------------------------------ r1385 | adk0212 | 2007-06-06 18:29:10 -0400 (Wed, 06 Jun 2007) | 2 lines Add back in the finish page with ReleaseNotes and apcupsd.org link. ------------------------------------------------------------------------ r1384 | adk0212 | 2007-06-06 18:28:46 -0400 (Wed, 06 Jun 2007) | 2 lines Increase sleep time to 2 seconds. 1 second was borderline. ------------------------------------------------------------------------ r1383 | adk0212 | 2007-06-05 20:42:45 -0400 (Tue, 05 Jun 2007) | 3 lines More start/stop rework. Add new common.nsh file to be shared between normal and uninstall context. ------------------------------------------------------------------------ r1382 | adk0212 | 2007-06-05 20:41:41 -0400 (Tue, 05 Jun 2007) | 3 lines Fix refresh again. Pretty soon I am going to run out of ways to screw this up. ------------------------------------------------------------------------ r1381 | adk0212 | 2007-06-05 18:43:24 -0400 (Tue, 05 Jun 2007) | 3 lines Many more installer updates. Move static text to page .ini files. Add code to handle polite start/stop of apcupsd and apctray. ------------------------------------------------------------------------ r1380 | adk0212 | 2007-06-05 18:39:37 -0400 (Tue, 05 Jun 2007) | 4 lines Maintain a registry flag to indicate if apcupsd is installed as a service. This used to be done by the installer, but would get out of sync if the user ran 'apcupsd /install' by hand. ------------------------------------------------------------------------ r1379 | adk0212 | 2007-06-05 18:34:29 -0400 (Tue, 05 Jun 2007) | 4 lines Maintain a registry flag to indicate if apcupsd is installed as a service. This used to be done by the installer, but would get out of sync if the user ran 'apcupsd /install' by hand. ------------------------------------------------------------------------ r1378 | adk0212 | 2007-06-05 18:33:06 -0400 (Tue, 05 Jun 2007) | 4 lines When installing, only add command line parameters if they were supplied by the user. Do not add them when using default settings. Also fix bug where default refresh was 1000 seconds (should be 1 second). ------------------------------------------------------------------------ r1377 | adk0212 | 2007-06-03 22:38:26 -0400 (Sun, 03 Jun 2007) | 2 lines Add custom page for installing Apctray and configuring its parameters. ------------------------------------------------------------------------ r1376 | adk0212 | 2007-06-03 13:05:20 -0400 (Sun, 03 Jun 2007) | 3 lines Add custom page for installing apcupsd as a service and optionally starting it instead of using popup dialogs during file install. ------------------------------------------------------------------------ r1375 | adk0212 | 2007-06-03 13:04:28 -0400 (Sun, 03 Jun 2007) | 2 lines Add definition for edit apcupsd.conf custom page. ------------------------------------------------------------------------ r1374 | adk0212 | 2007-06-03 12:38:26 -0400 (Sun, 03 Jun 2007) | 2 lines Suppress service-already-exists errors when in quiet mode. ------------------------------------------------------------------------ r1373 | adk0212 | 2007-06-03 12:31:53 -0400 (Sun, 03 Jun 2007) | 3 lines Move GetArg() to common library and use it from winmain and apctray. Add /quiet switch to winmain to suppress /install and /remove dialogs. ------------------------------------------------------------------------ r1372 | adk0212 | 2007-06-03 11:35:21 -0400 (Sun, 03 Jun 2007) | 3 lines Add custom installer page for editing apcupsd.conf instead of using a popup during file installation. ------------------------------------------------------------------------ r1371 | adk0212 | 2007-06-02 23:48:54 -0400 (Sat, 02 Jun 2007) | 2 lines Update NSIS to 2.27 for better x64 compatibility. ------------------------------------------------------------------------ r1370 | adk0212 | 2007-06-02 23:48:23 -0400 (Sat, 02 Jun 2007) | 3 lines Updates for apctray. Create -Startup and -Finish hidden sections for common operations. ------------------------------------------------------------------------ r1369 | adk0212 | 2007-06-02 23:45:27 -0400 (Sat, 02 Jun 2007) | 2 lines Tweak spacing in GetAll() to match apcaccess format for longer keys. ------------------------------------------------------------------------ r1368 | adk0212 | 2007-06-02 23:24:15 -0400 (Sat, 02 Jun 2007) | 2 lines Add /kill command line option for shutting down apctray instance. ------------------------------------------------------------------------ r1367 | adk0212 | 2007-06-02 19:07:11 -0400 (Sat, 02 Jun 2007) | 2 lines Update window name used by popup.exe so it finds apctray now. ------------------------------------------------------------------------ r1366 | adk0212 | 2007-06-02 18:57:02 -0400 (Sat, 02 Jun 2007) | 5 lines Rework sprintf_realloc_append() to account for the fact that on Win98 vsnprintf() returns -1 if the string will not fit rather than the number of characters required. Argh. Also remove unnecessary UpdateTrayIcon() calls from wintray.c. ------------------------------------------------------------------------ r1365 | adk0212 | 2007-06-02 18:22:48 -0400 (Sat, 02 Jun 2007) | 3 lines Add menu option to remove apctray from registry. All well-behaved tray applets should have this! ------------------------------------------------------------------------ r1364 | adk0212 | 2007-06-02 18:04:10 -0400 (Sat, 02 Jun 2007) | 3 lines Add command line options to install and remove apctray from autorun list in the registry. ------------------------------------------------------------------------ r1363 | adk0212 | 2007-06-02 17:34:04 -0400 (Sat, 02 Jun 2007) | 2 lines Add support for setting host, port, and refresh interval via command line. ------------------------------------------------------------------------ r1362 | adk0212 | 2007-06-02 16:28:46 -0400 (Sat, 02 Jun 2007) | 2 lines Update about box. ------------------------------------------------------------------------ r1361 | adk0212 | 2007-06-02 15:22:41 -0400 (Sat, 02 Jun 2007) | 4 lines Move status polling to a thread instead of a timer so we don't block the message loop while updating status. This fixes the annoying pauses in GUI response. More misc cleanups and small bug fixes. ------------------------------------------------------------------------ r1360 | adk0212 | 2007-06-02 13:46:29 -0400 (Sat, 02 Jun 2007) | 2 lines Misc fixes. apctray is working now. ------------------------------------------------------------------------ r1359 | adk0212 | 2007-06-02 13:23:00 -0400 (Sat, 02 Jun 2007) | 4 lines More refactoring. Add StatMgr class to handle fetching stats from the UPS using NIS. Kill global variables and move global stats and events code to their proper classes. ------------------------------------------------------------------------ r1358 | adk0212 | 2007-06-02 11:12:44 -0400 (Sat, 02 Jun 2007) | 2 lines Move modified tray menu code back to wintray.cpp. Misc cleanups to wintray. ------------------------------------------------------------------------ r1357 | adk0212 | 2007-06-01 20:12:56 -0400 (Fri, 01 Jun 2007) | 2 lines Cleanup of winabout, winevents, and winstat. Everthing compiles again. ------------------------------------------------------------------------ r1356 | adk0212 | 2007-05-31 20:11:52 -0400 (Thu, 31 May 2007) | 7 lines First step of major win32 service and tray icon code refactor/rewrite. This is part of the changes necessary for tray icon support on Vista. Clean up winservice and winmain. Eliminate lots of unused code. Simplify code where possible. Remove tray icon code from apcupsd itself. Add apctray.cpp for standalone tray icon module designed to gather status via NIS. ------------------------------------------------------------------------ r1355 | adk0212 | 2007-05-31 20:11:26 -0400 (Thu, 31 May 2007) | 2 lines Remove OpenGL and DirectX libraries, as they are not needed for Apcupsd. ------------------------------------------------------------------------ r1353 | fleetworks | 2007-05-28 07:03:11 -0400 (Mon, 28 May 2007) | 2 lines RHEL5 update. ------------------------------------------------------------------------ r1352 | adk0212 | 2007-05-27 13:20:34 -0400 (Sun, 27 May 2007) | 2 lines Add rhel5 to contrib-rpm. ------------------------------------------------------------------------ r1351 | adk0212 | 2007-05-27 13:17:02 -0400 (Sun, 27 May 2007) | 2 lines Fix changelog copy-n-paste error. ------------------------------------------------------------------------ r1350 | adk0212 | 2007-05-27 13:15:59 -0400 (Sun, 27 May 2007) | 2 lines Add rhel5 support in spec. ------------------------------------------------------------------------ r1349 | adk0212 | 2007-05-26 15:07:12 -0400 (Sat, 26 May 2007) | 2 lines Update website for 3.14.1 release. ------------------------------------------------------------------------ r1347 | adk0212 | 2007-05-04 19:18:47 -0400 (Fri, 04 May 2007) | 2 lines Update ChangeLog. ------------------------------------------------------------------------ r1346 | adk0212 | 2007-05-04 19:17:00 -0400 (Fri, 04 May 2007) | 2 lines Maybe this time... ------------------------------------------------------------------------ r1345 | adk0212 | 2007-05-03 18:31:47 -0400 (Thu, 03 May 2007) | 5 lines Do not attempt to cancel shutdowns. Once a shutdown has been started there is no way to cleanly stop it and recover. Plus deleting the powerfail file causes killpower to be skipped, leaving the server shutdown and not restarted. Reported by Yvon Lafaille . ------------------------------------------------------------------------ r1344 | adk0212 | 2007-05-01 20:26:52 -0400 (Tue, 01 May 2007) | 10 lines Rewrite device opening logic. The new logic works as follows: - If user specifies a DEVICE, we will open that device and that device only. There is no fallback to autodetect. This is generaly what users expect when they explicitly give DEVICE. - If no DEVICE is specified, we autodetect as before. Furthermore, if we lose the connection to the device, we prefer to re-open the same device again, but will restart autodetection if that fails. - If DEVICE is specified using the deprecated '[]' syntax, just do normal autodetection as if DEVICE had not been specified at all. ------------------------------------------------------------------------ r1343 | adk0212 | 2007-04-30 22:14:13 -0400 (Mon, 30 Apr 2007) | 2 lines Disable a few CIs that SNMP cards do not support. ------------------------------------------------------------------------ r1342 | adk0212 | 2007-04-30 21:37:55 -0400 (Mon, 30 Apr 2007) | 3 lines Increase self-test timeout to 40 seconds to accomodate the RS 800. Contributed by Lars Randers . ------------------------------------------------------------------------ r1341 | adk0212 | 2007-04-27 19:30:31 -0400 (Fri, 27 Apr 2007) | 5 lines Fix apctest crash. When in the EEPROM programming section of apctest, if you try to print EEPROM values (item 1) more than once during the same session, the program segfaults. Contributed by Ivaylo Haratcherev . ------------------------------------------------------------------------ r1340 | adk0212 | 2007-04-27 19:25:40 -0400 (Fri, 27 Apr 2007) | 2 lines Normalize shut remote message. ------------------------------------------------------------------------ r1339 | adk0212 | 2007-04-27 19:24:26 -0400 (Fri, 27 Apr 2007) | 4 lines Add support for PCNET remote shutdown (SD) signal. Contributed by Ivaylo Haratcherev and Moshe Hyzon . ------------------------------------------------------------------------ r1338 | adk0212 | 2007-04-23 19:47:58 -0400 (Mon, 23 Apr 2007) | 2 lines Rev ChangeLog. ------------------------------------------------------------------------ r1337 | adk0212 | 2007-04-23 19:45:24 -0400 (Mon, 23 Apr 2007) | 2 lines Did I say "final"? ------------------------------------------------------------------------ r1336 | adk0212 | 2007-04-23 19:37:52 -0400 (Mon, 23 Apr 2007) | 3 lines Fix typo in error message. Reported by Ashley M. Kirchner ------------------------------------------------------------------------ r1335 | adk0212 | 2007-04-23 19:35:33 -0400 (Mon, 23 Apr 2007) | 7 lines Update to match Fedora Extras packaging: - Add "force-reload" aliased to "restart" - "reload" outputs a not implemented error - "status" uses the status() function to return the proper LSB status code and runs apcaccess only if the daemon is running. Contributed by Orion Poplawski . ------------------------------------------------------------------------ r1334 | adk0212 | 2007-04-21 20:37:23 -0400 (Sat, 21 Apr 2007) | 2 lines Update ChangeLog for 3.14.1 (again). ------------------------------------------------------------------------ r1333 | adk0212 | 2007-04-21 20:35:15 -0400 (Sat, 21 Apr 2007) | 2 lines Final updates for 3.14.1. ------------------------------------------------------------------------ r1332 | adk0212 | 2007-04-21 20:24:56 -0400 (Sat, 21 Apr 2007) | 2 lines Clarify FreeBSD versions in USB kernel section. ------------------------------------------------------------------------ r1331 | adk0212 | 2007-04-21 19:59:46 -0400 (Sat, 21 Apr 2007) | 3 lines Add USB info for NetBSD 4.x (ugen binding can be forced on a particular port). Contributed by Curt Sampson . ------------------------------------------------------------------------ r1330 | adk0212 | 2007-04-21 19:27:47 -0400 (Sat, 21 Apr 2007) | 3 lines Fix link error with --disable-apcsmart (getline missing). Reported by Ashley M. Kirchner ------------------------------------------------------------------------ r1329 | adk0212 | 2007-04-18 19:33:19 -0400 (Wed, 18 Apr 2007) | 2 lines Updated changelog for 3.14.1. ------------------------------------------------------------------------ r1328 | adk0212 | 2007-04-18 19:30:48 -0400 (Wed, 18 Apr 2007) | 2 lines Prep for 3.14.1 release. ------------------------------------------------------------------------ r1327 | adk0212 | 2007-03-25 15:38:39 -0400 (Sun, 25 Mar 2007) | 4 lines Prevent infinite hang in read_nbytes() when server disappears. Many thanks to Jan Ceuleers for reporting the hanging and gathering data to track down the cause. ------------------------------------------------------------------------ r1326 | adk0212 | 2007-03-25 15:34:02 -0400 (Sun, 25 Mar 2007) | 2 lines Remove references to int8_t and int16_t. ------------------------------------------------------------------------ r1325 | adk0212 | 2007-03-05 22:41:46 -0500 (Mon, 05 Mar 2007) | 2 lines Kill stdint.h include since OpenBSD does not appear to have it. ------------------------------------------------------------------------ r1324 | adk0212 | 2007-03-03 16:40:44 -0500 (Sat, 03 Mar 2007) | 2 lines Hey, genius... Archive foo.bar.in, not foo.bar. ------------------------------------------------------------------------ r1323 | adk0212 | 2007-03-03 16:28:03 -0500 (Sat, 03 Mar 2007) | 2 lines Regen with Mac OS X installer changes. ------------------------------------------------------------------------ r1322 | adk0212 | 2007-03-03 16:23:42 -0500 (Sat, 03 Mar 2007) | 2 lines Add binary installer support for Mac OS X. ------------------------------------------------------------------------ r1321 | adk0212 | 2007-02-17 12:02:00 -0500 (Sat, 17 Feb 2007) | 3 lines Add missing newline at end of file. Discovered by Sergey Y. Afonin . ------------------------------------------------------------------------ r1320 | adk0212 | 2007-02-17 12:00:50 -0500 (Sat, 17 Feb 2007) | 3 lines Fix typo: "%sbindir\%popup" -> "%sbindir%\popup" Discovered by Stefan.Hegnauer@elektrobit.com. ------------------------------------------------------------------------ r1319 | adk0212 | 2007-02-13 19:02:55 -0500 (Tue, 13 Feb 2007) | 3 lines Detect when balloon tips have been disabled via a group policy and fall back on the standard popup message box. ------------------------------------------------------------------------ r1318 | (no author) | 2007-02-11 10:33:33 -0500 (Sun, 11 Feb 2007) | 1 line This commit was manufactured by cvs2svn to create branch 'Branch-3_14'. ------------------------------------------------------------------------ apcupsd-3.14.14/DISCLAIMER000066400000000000000000000021051274230402600146600ustar00rootroot00000000000000 Please see COPYING for the copyright and general disclaimer. IN NO EVENT SHALL ANY AND ALL PERSONS INVOLVED IN THE DEVELOPMENT OF THIS PACKAGE, NOW REFERRED TO AS "APCUPSD-Team" BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ANY OR ALL OF THE "APCUPSD-Team" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE "APCUPSD-Team" SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE "APCUPSD-Team" HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. THE "APCUPSD-Team" HAS ABSOLUTELY NO CONNECTION WITH THE COMPANY AMERICAN POWER CONVERSION, "APCC". THE "APCUPSD-Team" DID NOT AND HAS NOT SIGNED ANY NON-DISCLOSURE AGREEMENTS WITH "APCC". ANY AND ALL OF THE LOOK-A-LIKE ( UPSlink(tm) Language ) WAS DERIVED FROM THE SOURCES LISTED BELOW. apcupsd-3.14.14/Developers000066400000000000000000000034431274230402600153620ustar00rootroot00000000000000 Current Code Maintainer and Project Manager: Adam Kropelin RPM Packager: D. Scott Barninger Former Project Manager: Kern Sibbald Project Starter and Former Code Maintainer: Andre Hedrick Alpha Port: J. Rochate testing and machine loan HP-UX Port Carl Erhorn Robert K Nelson SOLARIS Port: Carl Erhorn OpenBSD Port: Devin Reade NetBSD Port: Neil Darlow Win32 Port: Kern Sibbald Paul Z. Stagner testing WEB Interfaces: Kern Sibbald Joseph Acosta Hard Core Coders: Kern Sibbald Adam Kropelin Distribution Maintainers: Alpha: J. Rochate ???? Debian: Leon Breedt FreeBSD/BSDi: Jeff Palmer NetBSD: Neil Darlow HP-UX: Carl Erhorn , Robert K Nelson OpenBSD: Devin Reade RedHat: Kern Sibbald Fedora: Kern Sibbald Slackware: Devin Reade Sparc Solaris: Carl Erhorn SuSE: None Win32: Kern Sibbald Project Discussions: APCUPSD Mailing List apcupsd-3.14.14/INSTALL000066400000000000000000000322001274230402600143510ustar00rootroot00000000000000Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Become root if not already with `su'. 4. Type `make install' to install the programs and any data files and documentation. If you have a previously installed version of this package, it is advisable to issue a `make uninstall' before doing the installation. This will clean the halt.local script for suse and any other old halt script for other distributions. We can not guarantee a good behaviour of the software if you install a new version over an older one without prior uninstall the older one. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. 6. You can remove the program from where it was installed with `make uninstall.' Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in /usr/local/sbin and /usr/local/man. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. Usually good installation paths are `--prefix=/usr' and `--sbindir=/sbin'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. Configure options for APC UPS Daemon ==================================== The apcupsd have a number of `configure' time options that can be enabled for additional features. These options are: `--enable-powerflute' Enable the compilation of `powerflute' an ncurses based program to monitor the UPS. `--enable-nls' Enable the support for Native Language Support. `--with-included-gettext' Enable the compilation of the GNU gettext library that is included in this package. Gettext is part of NLS support so there's no point enabling this option and with NLS support disabled. `--with-catgets' Enable the use of the `catgets' function if available. `--with-libwrap=yes or --with-libwrap=[DIR] Enable the use of libwrap. When set to yes enables libwrap system library. When set to [DIR] enables libwrap in DIR. For RedHat Linux 9 users, some useful configure options are: =========================================================== ./configure --enable-threads --enable-cgi --with-cgi-bin=/var/www/cgi-bin Adjust --with-cgi-bin argument to reflect the location of your web server pages. Prior to running configure, make sure the following to packages are installed on your system. gd-1.8.4-11 gd-devel-1.8.4-11 These packages are on the RedHat 9 distribution disks. If these packages are installed, the cgi code will use these libraries for generation of png images. If these are not installed, the version included with apcupsd will be used instead. Configuring Apache HTTP Server for use with cgi support ======================================================= If you configure apcupsd with the --enable-cgi support you may need to make configuration changes to the httpd.conf file. The changes you will need to make depend on what directory you choose install the cgi files in. There are five files which are installed in the cgi-bin directory. Four of these are .cgi files which are executable images and the fifth file is apcupsd.css which is a style sheet used to give a common style to all output. There are two ways of enabling cgi support for Apache. The first method is to add the following line to httpd.conf: ScriptAlias /cgi-bin /var/www/cgi-bin The second method is to add the following lines to httpd.conf: Alias /cgi-bin /var/www/cgi-bin Options +ExecCGI AddHandler cgi-script .cgi The first example tells Apache that all files in the cgi-bin directory are executable cgi programs. The second example tells Apache that programs in the cgi-bin directory may be executable cgi programs if the file extension is .cgi. You can also add extra extensions to the AddHandler directive if you have other files in the directory. For example, if you have perl files in your cgi-bin directory: AddHandler cgi-script .cgi .pl Using the first example, you will have a problem with trying to serve the file apcupsd.css. Since this file is installed in the cgi-bin directory, Apache will assume it is an executable program and will produce an error when trying to serve it. You must use the second method of enabling cgi support. If you are using the default Apache configuration file, you will need to remove (or comment out) the first example and replace it with the second. If you install the apcupsd cgi files in another directory, you will need to add the second example to your httpd.conf file and adjust the pathname accordingly. Customization of apcupsd events ================================ Note, this is somewhat out of date, please check the installed apccontrol script for exact details of these events. When apcupsd detects anomalies from your UPS device, it will make some decisions that usually result in one or more calls to the script located in `${sysconf}/apcupsd/apccontrol'. The apcaction file is a shell script that acts on the first argument that `apcupsd' passes to it. These actions are set up by default to sane behaviour for all possible situations apcupsd is likely to detect from the UPS. Nevertheless you can change the apccontrol behaviour for every single action. To do so create a file with the same name as the action, which is passed as the first argument (argv[1], or $1 for shell scripts). Put your script in `${sysconf}/apcupsd/' directory. At present the arguments that apcaction can recognize are: Keyword Default Action ============ ============================================================== `powerout' `wall' a message telling `There are power problems'. `onbattery' `wall' a message telling `System is on battery'. `offbattery' None `mainsback' Attempt to cancel a running `shutdown' sequence. `failing' `wall' a message telling `Battery power is failing'. `timeout' `wall' a message telling `Timeout on Battery reached'. `loadlimit' `wall' a message telling `Battery load limit reached'. `runlimit' `wall' a message telling `Battery runtime limit reached'. `doreboot' Begins the `shutdown -r' sequence. `doshutdown' Begins the `shutdown -h' sequence. `annoyme' `wall' a message telling `Power problems, logoff now'. `emergency' Begins an emercengy `shutdown' sequence. `changeme' `wall' a message telling `Battery failed, change them now'. `remotedown' Begins the `shutdown' sequence, called from remote. If for example you want to write your own routine for the `powerout' action, you can write your own shell script called `powerout' and put it in the lib directory. Doing so will _completely disable_ the `apcaction' default behaviour and enable your script. If you want to write your customized scripts you are encouraged to edit the `${libdir}/apcupsd/apccontrol' script and at least mimic its behaviour into your own script. Writing faulty scripts may cause your system to crash due to power failures. apcupsd-3.14.14/Makefile000066400000000000000000000005771274230402600147740ustar00rootroot00000000000000topdir:=. SUBDIRS=src platforms doc include autoconf/targets.mak # Force platforms/ to build after src/ platforms_DIR: src_DIR configure: autoconf/configure.in autoconf/aclocal.m4 -rm -f config.cache config.log config.out config.status include/config.h autoconf --prepend-include=autoconf autoconf/configure.in > configure autoheader autoconf/configure.in chmod 755 configure apcupsd-3.14.14/ReleaseNotes000066400000000000000000000611361274230402600156460ustar00rootroot00000000000000 Release Notes for Apcupsd 3.14.x Apcupsd 3.14.x is the latest STABLE release, containing many bug fixes and new features over the previous 3.12.x stable series. Users of all previous versions are encouraged to upgrade. IF YOU USE THE OLD STYLE MASTER/SLAVE NETWORKING MODE, BE SURE TO READ THE 3.14.0 RELEASE NOTES BELOW. 3.14.14 -- 31 May 2016 BUG FIXES * win32: Fix missing DLLs when installing only apctray * Fixes for socket error handling. Resolves apcaccess crash when connection fails as well as several other theoretical issues. * MODBUS/USB error handling (COMMLOST) improvements for faulty USB links * Fix hiddev binding when usbfs is mounted on /dev/bus/usb instead of /proc/bus/usb. This is necessary for switching between MODBUS/USB and USB/HID on Linux. * Update GPLv2 text and FSF address to match current versions from FSF. * Various fixes for potential issues suggested by Coverity Scan * MacOS X port support for El Capitan System Integrity Protection (SIP) aka "rootless" * Fix shutdown failure on Windows when UPSNAME includes spaces * Fix building bsd-usb driver (This was broken when modbus-usb support was added.) FEATURES * Add status display for output current as well as apparent power 3.14.13 -- 02 February 2015 NEW FEATURES * MODBUS USB support Previous releases supported MODBUS serial (RS232). This release adds support for MODBUS over USB. This protocol is preferable to the normal USB HID driver because it offers access to more UPS data readouts and controls. The only configuration file change needed versus MODBUS serial is to change UPSCABLE to usb and use an empty DEVICE setting. See the MODBUS section of the apcupsd manual for more details. * Support for Apple Notification Center on Mac OS X (replaces Growl) * Apple install packages and binaries are signed with an Apple Developer key for compatibility with Gate Keeper * Windows USB driver has been updated with additional USB identifiers to support future APC products. BUG FIXES * Use launchd for startup on Mac OS X as the old Startup Items mechanism is no longer supported in 10.10 and above * Fix apcaccess on ARM systems where char is unsigned by default * Fix several potential issues identified by Coverity static analysis * Numerous other fixes and improvements all over the code, many of them submitted by users...Thank you! MISC * Windows port now builds with the same configure and make system as the other targets, no need to maintain a special hardcoded Makefile. * Many cleanups to the Windows port codebase * Prebuilt binaries for Mac OS X no longer support PowerPC systems or Mac OS X 10.4 and older 3.14.12 -- 29 March 2014 (Maintenance Release) NEW FEATURES * apcaccess and apcupsd status format updates to ease parsing by scripts * UPS name is included in subject line of emails in default scripts * Default event scripts pull SYSADMIN and APCUPSD_MAIL definitions from a common config file so they can easily be configured in one place BUG FIXES * Fix issue with certain Back-UPS USB models repeatedly cycling power on/off after killpower is issued * Fix display of battery level during MODBUS calibration * Fix apctest EEPROM setting on various models * Close and reopen serial port during extended COMMLOST in apcsmart driver (helps recover connection when USB serial port dongles are reconnected) * Avoid probing non-APC USB devices as it can cause lockups * Fix issue with service failing to start on Windows during boot with USB UPS * Fix bogus lock file error when config file error forces early termination * Fix MODBUS NOMOUTV reading for voltages other than 120VAC * Fix LOADPCT (CI_LOAD) on MODBUS driver * Fix issue with net driver not reporting MODEL value 3.14.11 -- 31 January 2014 (Maintenance Release) NEW FEATURES * MODBUS protocol support Over the summer, APC publicly released documentation[1] on a new UPS control and monitoring protocol, loosely referred to as MODBUS (after the historic industrial control protocol it is based on). The new protocol operates over RS232 serial lines as well as USB connections and is intended to supplement APC's proprietary Microlink protocol. Microlink is not going away, but APC has realized that third parties require access to UPS status and control information. Rather than publicly open Microlink, they have created another protocol to operate along side it. Many existing Microlink UPSes can be upgraded to support MODBUS via a firmware update. See [2]. Certain older models are not upgradeable. APC support will be your best contact for determining if your UPS supports a MODBUS upgrade the information linked below does not make it clear. For now, apcupsd supports MODBUS over RS232 serial only. It DOES NOT yet support MODBUS over USB. See the apcupsd manual[3] for information on setting up apcupsd.conf for MODBUS UPSes. [1] http://www.apc.com/whitepaper/?an=176 [2] http://www.schneider-electric.us/support/index?page=content&country=ITB&lang=EN&id=FA164737 [3] http://www.apcupsd.com/manual/manual.html * Windows USB driver is now digitally signed thanks to Jernej Simoncic 3.14.10 -- 13 September 2011 (Maintenance Release) BUG FIXES * Fix missing status and spurrious incorrect status on newer BackUPS CS models using USB interface. * USB compatibility fixes for Mac OS X Lion * USB driver support for newer Microlink models on Mac OS X Lion and Windows * Ignore transitions to battery due to calibration (possible if user initiates calibration, then exits apctest and starts apcupsd before calibration completes. * Fix truncation of long UPS model names such as "Smart-UPS RT 5000 XL" * Fix MODEL vs. APCMODEL confusion. Remove APCMODEL and rename old MODEL aka 'mode' to DRIVER. 3.14.9 -- 22 July 2011 (Maintenance Release) NEW FEATURES * SNMP enhancements: - Autodetection of MIB and community if they are not specified in apcupsd.conf - Support for RFC1628 MIB - Support for MGE MIB (Contributed by Lars Taeuber ) * Windows USB support for 64-bit platforms * USB support for latest APC models such as SMT* and SMX* series - No support for Microlink, but basic USB interface should be detected and provide status now. * When using the generic USB driver (Windows, OS X, newer FreeBSD) DEVICE string in apcupsd.conf can be set as serial number of UPS to monitor. This is useful in order to "lock" apcupsd to a specific UPS if you have more than one connected to the server. * Ed Dondlinger's Windows email scripts are included in the Win32 install package now. Documentation includes information on how to hook them in. BUG FIXES * general: Rework signal handling to eliminate crashes and hangs. * general: Fix issue of overwriting pid file even when we failed to acquire the lock file * snmp: Add workaround for FreeBSD libsupc++.a issue (FreeBSD PR #99702) This will allow snmplite driver to compile/link on FreeBSD 5.x. * usb: Automatically use generic_usb driver on FreeBSD 8.0 and newer. FreeBSD USB API was changed in 8.0, so from now on we will use libusb. * usb: Add support for DALARM * usb: Fix BATTV and MANDATE on certain newer APC models * win32: Honor INSTDIR specified on command line via /D * win32: When running uninstaller in silent mode, always remove config and events files without prompting. * win32: When logging events, convert LOG_CRIT to a WARNING rather than an ERROR since apcupsd uses it for power events which aren't really daemon errors. 3.14.8 -- 16 January 2010 (Maintenance Release) NEW FEATURES * Mac OS X version of apctray (apcagent) for monitoring apcupsd instances. Same feature set as apctray on Windows (monitor multiple instances, get detailed status and events logs). Popup notifications delivered via Growl, if available. * Major update to win32 version of apctray. Includes many visual and usability improvements to match OS X version. * apctest now supports battery calibration and self-test interval control on USB models. Many thanks to James Belleau for contributing these features. * New SNMP driver that does not require libsnmp.so, thus eliminating issues with not finding the library during shutdown when /usr has been unmounted. The new driver is the default for 'UPSTYPE snmp'. The old driver is still available as "UPSTYPE netsnmp" if needed. BUG FIXES * Add missing NOMINV, NOMOUTV, and NOMPOWER to net clients * Fix missing WALL in apccontrol (debian bug #546019) http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=546019 * Change all time/date strings to simplified ISO format: "YYYY-MM-DD HH:MM:SS +/-UTC" * Fix battery voltage readout on "Back-UPS 500 FW: 6.3.I USB FW: c1" * Remove obsolete image files from source tree * Fix issues with popup.exe running when it shouldn't and sometimes hanging and/or generating an "Interactive Services Dialog Detected" error. * Use /kill switch from the installer to shut down running instances of apcupsd and apctray. This will provide more reliable termination on Vista/Win7. * Update apctest to use 'Q' to exit any menu instead of a number that is always changing. Contributed by James Belleau * apctest: Fix compiler warnings. Contributed by Andy O'Shaughnessy 3.14.7 -- 31 July 2009 (Maintenance Release) NEW FEATURES * Multimon CGI programs are included with the Windows binary package BUG FIXES * Windows COM ports above COM9 now work without user needing to manually add \\.\ UNC prefix in apcupsd.conf * Fix configure script not noticing when C++ compiler is missing * Fix for battery date (BATTDAT) displaying invalid values on USB models * Fix version reporting in cgi and examples * Misc documentation fixes for typos, etc. 3.14.6 -- 16 May 2009 (Maintenance Release) NEW FEATURES * Major updates to the User Manual. Rewritten battery maintenance section courtesy of Trevor Roydhouse . Many other updates including the SmartUPS protocol and OS support sections. Furthermore, the manual is now formatted in reStructuredText (http://docutils.sourceforge.net/rst.html) and as a result is very easy to update. (The only down side is the multi-page HTML version is no longer available; the HTML version is all on a single page.) * New manpages for apcupsd, apcupsd.conf, apctest, apcaccess, and apccontrol. Many thanks to Trevor Roydhouse for the hard work! * Support for QNX. Tested on QNX 6.3.2. Contributed by Mikhail Gruzdev * Add support for turning the UPS off completely. This complements existing hibernate (aka killpower) functionality. Turn-off is implemented for apcsmart and USB drivers, subject to support for the relevant commands in the UPS itself. Contributed by Keith Campbell . BUG FIXES * apcsmart: Deadlock fixes during comms failures. Contributed by Keith Campbell * linux-usb: Fix out-of-bounds array access. Contributed by David Fries * Fix build with gcc-4.4. Contributed by Michal Hlavinka * apcsmart: Fix crash during process shutdown (SIGTERM). Contributed by Andrey Sharandakov * Several other minor fixes and improvements. See ChangeLog for details. 3.14.5 -- 26 October 2008 (Maintenance Release) BUG FIXES * docs: Document the /refresh switch for apctray. * apctest: Do not create pid file. There is little reason for it since apctest is a command-line tool, not a daemon. Plus nothing ever deletes the file so it interferes with apcupsd operation. * gapcmon: Network connect timeout fix. * Fix a few unsafe uses of sprintf and strcat. * Makefile: Fix cgi build on OpenBSD. libgd on OpenBSD requires X_LIBS for libfreetype and libfontconfig. * gapcmon: Iconify fixes for KDE * Fix LOWBATT glitch handling bug that could cause us to act on a LOWBATT signal immediately instead of waiting for the debounce time. * apctray: Improve multiple instance behavior for /add, /del, and /kill on modern platforms (Win2K and newer). * Support shutting down apcupsd instances running in other sessions (such as terminal services or remote desktop sessions). * Makefile: 'make install' fixes for first install on RedHat/SuSE. * docs: PCNET minimum password length is 15 chars, default username is 'apc', no known way to change the username. * Makefile: Fix dependency build errors on Darwin and other platforms. ('echo -n' is not portable; use 'tr' to strip newline instead) * RPMs: Automatically restart apcupsd when upgrading 3.14.4 -- 18 May 2008 (Maintenance Release) MAJOR CHANGES * Build system rewrite: All Makefiles have been rewritten from scratch. Improvements include reliable dependencies, support for parallel make, elimination of Makefile.in -> Makefile conversion, consistent use of DESTDIR during 'make install', and pretty-printed output during builds. NEW BUILD SYSTEM NOTES - GNU make is required. The configure script checks for this and tells you how to invokve it (on some platforms it is 'gmake' instead of 'make'). - Output during build is pretty-printed by default. To see more details, use 'make VERBOSE=1' for output similar to the old build system. For even more verbosity, use 'make VERBOSE=2'. - Parallel builds work well. If you have a multiprocessor (or multicore) system, try 'make -j' for the fastest possible build. * Built-in version of libgd for multimon cgi has been removed. The version previously included in apcupsd was old and likely had security issues. It is safer to use libgd from the target system. Therefore, your system must provide libgd if you choose to build cgi now. Generally this is easy to achieve by installing a vendor-supplied package. * Removal of NLS support: The NLS code was terribly bit-rotted with many non-internationalized messages and almost every translated message was incorrect. At this point the maintenance burden of keeping NLS support building was deemed too high considering the small benefit it was able to provide. * Powerflute has been disabled. It has been broken for the last several releases because it relied on an untrushworthy source of UPS status (rawupsstats) which was itself removed. Powerflute could be converted to use the standard NIS status mechanism and its source code remains in the tree in case someone has the desire to contribute this code. NEW FEATURES * Add POLLTIME directive to control UPS polling interval. This directive specifies the number of seconds to delay between polling the UPS for status. Previously, NETTIME allowed this to be adjusted for network connections only (snmp, pcnet, nis-net). POLLTIME configures the delay for all connection types. NETTIME is accepted as a synonym for compatibility with old config files. BUG FIXES * gapcmon: Corrected the use of NOMPOWER and the calc of current usage amount. Thanks to James Scott Jr . * Add a heuristic to fix up incorrect NOMINV or NOMOUTV. Some UPSes (RS 500) report decivolts instead of volts. Reported by Kirill S. Bychkov . * Various build fixes on Solaris and OpenSolaris. Thanks to James Dean for loaning me an ssh login on his OpenSolaris box. * Fix hal policy file syntax. For some reason this blatantly incorrect file actually works on RHEL5 (hal-0.5.8). Thanks to Andrew Telford for correcting it. * Fix gapcmon build on OpenBSD. * Fix BSD USB driver build. * Fix default NIS port on Debian. Debian is now using the standard NIS port, 3551. Contributed by imacat 3.14.3 -- 20 January 2008 (Maintenance Release) NEW FEATURES * A HAL policy file is automatically installed on Linux systems to disable the hald-addon-hid-ups module which conflicts with apcupsd's control of USB UPSes. The file is automatically removed when apcupsd is uninstalled. BUG FIXES * Add support for Nominal Power (aka Configured Active Power) reading. Credit to Lars Randers for most of the code. * Add units to NOMINV, NOMOUTV, and NOMBATTV stats. * Eliminate "warning: deprecated conversion from string constant to 'char*'" warnings emitted from gcc-4.2.1 (earlier versions with -Wwrite-strings). Contributed by Steve Yarmie . * Fix killpower and eeprom settings bug on USB models introduced when INPUT reports were prioritized over FEATURE reports. * Fix bugs that could cause NIS-net driver to get stuck waiting for comms to be restored instead of shutting down. 3.14.2 -- 15 September 2007 (Maintenance Release) NEW FEATURES * Tray icon support on Vista. Vista does not allow background services to interact with the user's desktop, so winapcupsd's built-in tray icon did not work. * Tray icon is now a standalone application "apctray" which is capable of monitoring multiple Apcupsd instances via Apcupsd's NIS. Any Apcupsd running NIS can be monitored. By default the icon monitors a single apcupsd at 127.0.0.1:3551. See command line options below for adding additional monitors. * Tray icon can be installed individually (disable other packages in the installer) for users who want to use the icon only. * Apctray command line options: apctray.exe - No parameters: Start any instances listed in registry. If no instances in reg, start a default instance monitoring the local machine (127.0.0.1:3551). apctray.exe /host foo /port 3551 /add - Add a monitor for the given host and port. apctray.exe /host foo /port 3551 /del - Remove the given monitor. apctray.exe /del - Remove all monitors. apctray.exe /install - Configure apctray to start automatically. apctray.exe /remove - Do not start automatically. apctray.exe /kill - Shut down apctray BUG FIXES * The win32 portions of winapcupsd have been almost entirely rewritten. The code is cleaner (mostly) and lots of unused baggage has been removed. * USB fix for BackUPS LCD series. This fix carries a risk of breaking other models, but test results are positive so far. * Fix linux-usb device detection bug when multiple hiddev nodes are present. Fixes Fedora Bugzilla #245864: * Fix SNMP port selection when using SNMP driver * Add workaround for broken BackUPS Pro model that returns certain reports encoded in ASCII. Based on a patch from David Fries . * apcsmart: Wait 20 seconds before declaring COMMLOST. This is necessary when using a smart serial cable on an UPS with an SNMP monitoring card installed. The SNMP card appears to disrupt serial comms for several seconds when interesting events are in progress. * Documentation updates: Fix up udev info for modern Linux distros. Update Windows section for apctray. * Don't leak unnecessary descriptors to child when execing apccontrol. * Fix bug with multi-threaded net_open() calls. net_open() was using a global buffer for the destination address. Yikes! Bug manifestied itself in apctray with multiple monitors occasionally (and timing-dependently) pointing to the wrong UPS. * Correct multimon.conf humidity monitoring. Problem fixed by Patrick Frei. Reference: https://bugzilla.novell.com/show_bug.cgi?id=199834 * Fix race between attach_ups() and detach_ups() which could result in the UPSINFO structure being freed prematurely. Thanks to James Abbott for running many tests to help me find this bug. * Remove dependency on libc++ (again). Must use gcc as linker when using libsupc++ since g++ automatically links against full libc++. 3.14.1 -- 04 May 2007 (Maintenance Release) NEW FEATURES * MacOS X GUI installer * PCNET driver supports remote shutdown request from UPS web interface BUG FIXES * (win32) Detect when balloon tips have been disabled via a group policy and fall back on the standard popup message box. * (win32) Fix typo: "%sbindir\%popup" -> "%sbindir%\popup" in apccontrol.bat Discovered by Stefan.Hegnauer@elektrobit.com. * (all) Fix potential NIS client lockup when server disappears. Many thanks to Jan Ceuleers for reporting the problem and gathering data to track down the cause. * (apctest) Fix link error after configuring with --disable-apcsmart. * (doc) Document how to force ugen binding on NetBSD 4.x. Contributed by Curt Sampson . * (apctest) Fix crash when displaying EEPROM values more than once. Contributed by Ivaylo Haratcherev . * Increase self-test timeout to 40 seconds to accomodate the RS 800. Contributed by Lars Randers . * (linux-usb) Rewrite device opening logic to be more reliable. See ChangeLog for details. * (apcupsd) Do not attempt to cancel shutdowns. 3.14.0 -- 09 February 2007 (Feature Release) NEW FEATURES * USB support for 3 new platforms: - Windows (Win98SE, WinME, Win2000, Win2003 Server, WinXP) - Mac OS X (Darwin) - Solaris 10 (x86 and SPARC) Please see the Apcupsd manual for details on USB configuration for the new platforms. * Native Windows port The winapcupsd port has been completely rewritten to use native Win32 libraries (based on MinGW32). It no longer relies on a Cygwin translation layer, thus improving compatibility and performance. * PowerChute Network Shutdown driver Apcupsd now supports the PowerChute Network Shutdown protocol (PCNET) offered by the AP9617 family of smart slot modules. This protocol is much lighter-weight than SNMP and offers better security. Please see the Apcupsd manual for details on PCNET configuration. * GAPCMON GUI monitoring tool Apcupsd is now packaged with the GAPCMON GUI monitoring application thanks to James Scott, Jr. This is a Gnome/GTK based application which integrates into most desktop panels (not just Gnome). It monitors one or more Apcupsd instances using Apcupsd's NIS networking server. The status of each UPS is shown with a icon similar to the Win32 tray icon in winapcupsd. Enable building of gapcmon at compile time via --enable-gapcmon or install the apcupsd-gapcmon RPM. * Unreliable MASTER/SLAVE networking mode is removed Yes, this is a feature. The old MASTER/SLAVE mode for shutting down multiple servers from one UPS has historically been unreliable and prone to loss of communications or lockups. Apcupsd has long had a replacement networking mode using the NIS server (NIS stands for Network Information Server, and has nothing to do with Sun's NIS/YP protocol). The NIS net mode is very reliable and has none of the lockup bugs that have plagued MASTER/SLAVE mode. In 3.14.x, MASTER/SLAVE mode has been removed and the associated configuration directives are now obsolete. Please see the Apcupsd manual for a very simple NIS networking configuration to replace MASTER/SLAVE. * New configuration directives to set paths at runtime Several new (optional) configuration directives have been added to allow overriding compiled-in paths at runtime. The directives are: - SCRIPTDIR (sets location of apccontrol and event scripts) - PWRFAILDIR (sets location where powerfail file will be written) - NOLOGINDIR (set location where nologin file will be written) These directives can be used to rearrange the Apcupsd installation after compiling, or to run multiple Apcupsd instances on the same machine without compiling separate copies. See the Apcupsd manual for details on these new directives. apcupsd-3.14.14/VERIFYING000066400000000000000000000027161274230402600146160ustar00rootroot00000000000000 All apcupsd packages released on Source Forge after 24 July 2003 will be signed with the apcupsd Distribution Verification Key. By obtaining a copy of the apcupsd Distribution Verification Public key from either the home site (www.apcupsd.com) or from the Source Forge project page, (www.sourceforge.net/projects/apcupsd). you can verify that the code you have is complete, unaltered, and packaged by myself (Kern Sibbald) or D. Scott Barninger. Putting the apcupsd Key in your Keyring: Once you download the apcupsd public key, you must insert it in your keyring. The procedure will differ depending on whether you are using PGP or GPG. For GPG, assuming you have put the key in apcupsd.k, the procedure is: gpg --import apcupsd.key Verifying an RPM: The procedure for verification differs slightly if you are using rpms or tar.gz files. For rpms, the signature becomes part of the rpm package, and once the apcupsd public key is in your keyring you check the package with: rpm --checksig apcupsd-3.10.xx.rpm Verifying tar files: Tar files are distributed as they always have been in the past, unchanged. However, for each xxxx.tar.gz file that is released there will be a second file released with the same name but with .sig appended, for example xxxx.tar.gz.sig. To verify the apcupsd distribution, you download both the files and put them in the same directory, then for GPG, you use the following command to do the verification: gpg --verify xxxx.tar.gz.sig apcupsd-3.14.14/autoconf/000077500000000000000000000000001274230402600151415ustar00rootroot00000000000000apcupsd-3.14.14/autoconf/aclocal.m4000066400000000000000000000345251274230402600170120ustar00rootroot00000000000000# Search path for a program which passes the given test. # Ulrich Drepper , 1996. # # This file can be copied and used freely without restrictions. It can # be used in projects which are not available under the GNU Public License # but which still want to provide support for the GNU gettext functionality. # Please note that the actual code is *not* freely available. # Define a conditional. AC_DEFUN(AM_CONDITIONAL, [AC_SUBST($1_TRUE) AC_SUBST($1_FALSE) if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi]) AC_DEFUN(AC_TYPE_SOCKETLEN_T, [ dnl check for socklen_t (in Unix98) AC_MSG_CHECKING(for socklen_t) AC_TRY_COMPILE([ #include #include socklen_t x; ],[],[AC_MSG_RESULT(yes)],[ AC_TRY_COMPILE([ #include #include int accept (int, struct sockaddr *, size_t *); ],[],[ AC_MSG_RESULT(size_t) AC_DEFINE(socklen_t,size_t,[Define base type for socklen_t if needed])], [ AC_MSG_RESULT(int) AC_DEFINE(socklen_t,int)])]) ]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # # Copyright © 2004 Scott James Remnant . # # 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_PATH)?$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # # Similar to PKG_CHECK_MODULES, make sure that the first instance of # this or PKG_CHECK_MODULES is called, or make sure to call # PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_ifval([$2], [$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$PKG_CONFIG"; then if test -n "$$1"; then pkg_cv_[]$1="$$1" else PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`], [pkg_failed=yes]) fi else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags-only-I], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"` else $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD ifelse([$4], , [AC_MSG_ERROR(dnl [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT ])], [$4]) elif test $pkg_failed = untried; then ifelse([$4], , [AC_MSG_FAILURE(dnl [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])], [$4]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) ifelse([$3], , :, [$3]) fi[]dnl ])# PKG_CHECK_MODULES dnl @synopsis AX_FUNC_WHICH_GETHOSTBYNAME_R dnl dnl Determines which historical variant of the gethostbyname_r() call dnl (taking three, five, or six arguments) is available on the system dnl and defines one of the following macros accordingly: dnl dnl HAVE_FUNC_GETHOSTBYNAME_R_6 dnl HAVE_FUNC_GETHOSTBYNAME_R_5 dnl HAVE_FUNC_GETHOSTBYNAME_R_3 dnl dnl If used in conjunction with gethostname.c, the API demonstrated in dnl test.c can be used regardless of which gethostbyname_r() is dnl available. These example files can be found at dnl http://www.csn.ul.ie/~caolan/publink/gethostbyname_r dnl dnl based on David Arnold's autoconf suggestion in the threads faq dnl dnl Originally named "AC_caolan_FUNC_WHICH_GETHOSTBYNAME_R". Rewritten dnl for Autoconf 2.5x by Daniel Richard G. dnl dnl @category InstalledPackages dnl @author Caolan McNamara dnl @author Daniel Richard G. dnl @version 2005-01-21 dnl @license GPLWithACException AC_DEFUN([AX_FUNC_WHICH_GETHOSTBYNAME_R], [ AC_LANG_PUSH(C) AC_MSG_CHECKING([how many arguments gethostbyname_r() takes]) AC_CACHE_VAL(ac_cv_func_which_gethostbyname_r, [ ################################################################ ac_cv_func_which_gethostbyname_r=unknown # # ONE ARGUMENT (sanity check) # # This should fail, as there is no variant of gethostbyname_r() that takes # a single argument. If it actually compiles, then we can assume that # netdb.h is not declaring the function, and the compiler is thereby # assuming an implicit prototype. In which case, we're out of luck. # AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [[ char *name = "www.gnu.org"; (void)gethostbyname_r(name) /* ; */ ]])], ac_cv_func_which_gethostbyname_r=no) # # SIX ARGUMENTS # (e.g. Linux) # if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [[ char *name = "www.gnu.org"; struct hostent ret, *retp; char buf@<:@1024@:>@; int buflen = 1024; int my_h_errno; (void)gethostbyname_r(name, &ret, buf, buflen, &retp, &my_h_errno) /* ; */ ]])], ac_cv_func_which_gethostbyname_r=six) fi # # FIVE ARGUMENTS # (e.g. Solaris) # if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [[ char *name = "www.gnu.org"; struct hostent ret; char buf@<:@1024@:>@; int buflen = 1024; int my_h_errno; (void)gethostbyname_r(name, &ret, buf, buflen, &my_h_errno) /* ; */ ]])], ac_cv_func_which_gethostbyname_r=five) fi # # THREE ARGUMENTS # (e.g. AIX, HP-UX, Tru64) # if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then AC_COMPILE_IFELSE( [AC_LANG_PROGRAM( [[#include ]], [[ char *name = "www.gnu.org"; struct hostent ret; struct hostent_data data; (void)gethostbyname_r(name, &ret, &data) /* ; */ ]])], ac_cv_func_which_gethostbyname_r=three) fi ################################################################ ]) dnl end AC_CACHE_VAL case "$ac_cv_func_which_gethostbyname_r" in three) AC_MSG_RESULT([three]) AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_3) ;; five) AC_MSG_RESULT([five]) AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_5) ;; six) AC_MSG_RESULT([six]) AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_6) ;; no) AC_MSG_RESULT([cannot find function declaration in netdb.h]) ;; unknown) AC_MSG_RESULT([can't tell]) ;; *) AC_MSG_ERROR([internal error]) ;; esac AC_LANG_POP(C) ]) dnl end AC_DEFUN dnl dnl Find GNU make dnl AC_DEFUN( [AC_PROG_GMAKE], [AC_CACHE_CHECK(for GNU make,_cv_gnu_make_command, _cv_gnu_make_command='' ; dnl Search all the common names for GNU make for a in "$MAKE" make gmake gnumake ; do if test -z "$a" ; then continue ; fi ; if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then _cv_gnu_make_command=$a ; break; fi done ; ) ; MAKE=$_cv_gnu_make_command; if test -z "$_cv_gnu_make_command" ; then AC_MSG_ERROR([Could not find GNU make]) ; fi ; ] ) dnl dnl AC_PATH_PROGS but fail with an error if none can be found dnl AC_DEFUN( [AC_REQ_PATH_PROGS], [AC_PATH_PROGS($1,$2,) if test "$$1" = "" ; then AC_ERROR(Missing required tool; need any one of: $2) fi ]) dnl dnl AC_PATH_PROG but fail with an error if it cannot be found dnl AC_DEFUN( [AC_REQ_PATH_PROG], [AC_PATH_PROG($1,$2,) if test "$$1" = "" ; then AC_ERROR(Missing required tool: $2) fi ]) dnl dnl AC_CHECK_TOOL but fail with an error if it cannot be found dnl AC_DEFUN( [AC_REQ_TOOL], [AC_CHECK_TOOL($1,$2,) if test "$$1" = "" ; then AC_ERROR(Missing required tool: $2) fi ]) dnl dnl Adds a compile flag if the compiler supports it dnl AC_DEFUN( [AX_ADD_COMPILE_FLAG], [AX_CHECK_COMPILE_FLAG([$1],[CXXFLAGS="$CXXFLAGS $1"])]) # =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html # =========================================================================== # # SYNOPSIS # # AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) # # DESCRIPTION # # Check whether the given FLAG works with the current language's compiler # or gives an error. (Warnings, however, are ignored) # # ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on # success/failure. # # If EXTRA-FLAGS is defined, it is added to the current language's default # flags (e.g. CFLAGS) when the check is done. The check is thus made with # the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to # force the compiler to issue an error when a bad flag is given. # # INPUT gives an alternative input source to AC_COMPILE_IFELSE. # # NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this # macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. # # LICENSE # # Copyright (c) 2008 Guido U. Draheim # Copyright (c) 2011 Maarten Bosmans # # 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 3 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, see . # # As a special exception, the respective Autoconf Macro's copyright owner # gives unlimited permission to copy, distribute and modify the configure # scripts that are the output of Autoconf when processing the Macro. You # need not follow the terms of the GNU General Public License when using # or distributing such scripts, even though portions of the text of the # Macro appear in them. The GNU General Public License (GPL) does govern # all other use of the material that constitutes the Autoconf Macro. # # This special exception to the GPL applies to versions of the Autoconf # Macro released by the Autoconf Archive. When you make and distribute a # modified version of the Autoconf Macro, you may extend this special # exception to the GPL to apply to your modified version as well. #serial 3 AC_DEFUN([AX_CHECK_COMPILE_FLAG], [AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], [AS_VAR_SET(CACHEVAR,[yes])], [AS_VAR_SET(CACHEVAR,[no])]) _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes], [m4_default([$2], :)], [m4_default([$3], :)]) AS_VAR_POPDEF([CACHEVAR])dnl ])dnl AX_CHECK_COMPILE_FLAGS apcupsd-3.14.14/autoconf/config.guess000066400000000000000000001235501274230402600174640ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2014 Free Software Foundation, Inc. timestamp='2014-03-23' # This file 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 3 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: apcupsd-3.14.14/autoconf/config.h.in000066400000000000000000000214671274230402600171760ustar00rootroot00000000000000/* autoconf/config.h.in. Generated from autoconf/configure.in by autoheader. */ /* Define to the type of elements in the array set by `getgroups'. Usually this is either `int' or `gid_t'. */ #undef GETGROUPS_T /* Define to 1 if you have the `abort' function. */ #undef HAVE_ABORT /* Define to 1 if you have the `accept4' function. */ #undef HAVE_ACCEPT4 /* Define if building for AIX */ #undef HAVE_AIX_OS /* Define if building apcsmart driver */ #undef HAVE_APCSMART_DRIVER /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_NAMESER_H /* Define if building for BSDi */ #undef HAVE_BSDI_OS /* Define to 1 if you have the `calloc' function. */ #undef HAVE_CALLOC /* Define to 1 if you have the header file. */ #undef HAVE_CTYPE_H /* Define if building for Darwin */ #undef HAVE_DARWIN_OS /* Define to 1 if you have the declaration of `tzname', and to 0 if you don't. */ #undef HAVE_DECL_TZNAME /* Define if building simple signaling driver */ #undef HAVE_DUMB_DRIVER /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define if building for FreeBSD */ #undef HAVE_FREEBSD_OS /* Define if system does not have gethostbyname_r */ #undef HAVE_FUNC_GETHOSTBYNAME_R_0 /* Define for 3 argument version of gethostbyname_r */ #undef HAVE_FUNC_GETHOSTBYNAME_R_3 /* Define for 5 argument version of gethostbyname_r */ #undef HAVE_FUNC_GETHOSTBYNAME_R_5 /* Define for 6 argument version of gethostbyname_r */ #undef HAVE_FUNC_GETHOSTBYNAME_R_6 /* Define if you have getoptlong */ #undef HAVE_GETOPTLONG /* Define to 1 if you have the `getpid' function. */ #undef HAVE_GETPID /* Define if building for HPUX */ #undef HAVE_HPUX_OS /* Define if you have inetpton */ #undef HAVE_INETPTON /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `ioctl' function. */ #undef HAVE_IOCTL /* Define to 1 if you have the `kill' function. */ #undef HAVE_KILL /* Define to 1 if you have the `socket' library (-lsocket). */ #undef HAVE_LIBSOCKET /* Define if you have libwrap */ #undef HAVE_LIBWRAP /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define if building for Linux */ #undef HAVE_LINUX_OS /* Define if you have localtime_r */ #undef HAVE_LOCALTIME_R /* Define if you have memmove */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define if building for MINGW */ #undef HAVE_MINGW /* Define if building MODBUS driver */ #undef HAVE_MODBUS_DRIVER /* Define if building MODBUS/USB driver */ #undef HAVE_MODBUS_USB_DRIVER /* Define if you have nameser.h */ #undef HAVE_NAMESER_H /* Define if you have the nanosleep function. */ #undef HAVE_NANOSLEEP /* Define if building for NetBSD */ #undef HAVE_NETBSD_OS /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define if building net driver */ #undef HAVE_NET_DRIVER /* Define if apcupsd NIS library is being built */ #undef HAVE_NISLIB /* Define if apcupsd NIS server is being built */ #undef HAVE_NISSERVER /* Define if building for OpenBSD */ #undef HAVE_OPENBSD_OS /* Define if building for OSF1 */ #undef HAVE_OSF1_OS /* Define if building PCNET driver */ #undef HAVE_PCNET_DRIVER /* Define if you have pthreads */ #undef HAVE_PTHREADS /* Define if building for QNX */ #undef HAVE_QNX_OS /* Define to 1 if you have the `rewind' function. */ #undef HAVE_REWIND /* Define to 1 if you have the `select' function. */ #undef HAVE_SELECT /* Define to 1 if you have the `setsid' function. */ #undef HAVE_SETSID /* Define if building for IRIX */ #undef HAVE_SGI_OS /* Define to 1 if you have the `signal' function. */ #undef HAVE_SIGNAL /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H /* Define if building snmplite driver */ #undef HAVE_SNMPLITE_DRIVER /* Define to 1 if you have the `snprintf' function. */ #undef HAVE_SNPRINTF /* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDIO_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define if you have strcasecmp */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the `strftime' function. */ #undef HAVE_STRFTIME /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strlcat' function. */ #undef HAVE_STRLCAT /* Define to 1 if you have the `strlcpy' function. */ #undef HAVE_STRLCPY /* Define to 1 if you have the `strncmp' function. */ #undef HAVE_STRNCMP /* Define to 1 if you have the `strncpy' function. */ #undef HAVE_STRNCPY /* Define if you have strstr */ #undef HAVE_STRSTR /* Define to 1 if `tm_zone' is member of `struct tm'. */ #undef HAVE_STRUCT_TM_TM_ZONE /* Define if building for SunOS */ #undef HAVE_SUN_OS /* Define to 1 if you have the header file. */ #undef HAVE_SYSLOG_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the `tcgetattr' function. */ #undef HAVE_TCGETATTR /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H /* Define if building test driver */ #undef HAVE_TEST_DRIVER /* Define to 1 if your `struct tm' has `tm_zone'. Deprecated, use `HAVE_STRUCT_TM_TM_ZONE' instead. */ #undef HAVE_TM_ZONE /* Define to 1 if you don't have `tm_zone' but do have the external array `tzname'. */ #undef HAVE_TZNAME /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define if building USB driver */ #undef HAVE_USB_DRIVER /* Define to 1 if you have the `vfprintf' function. */ #undef HAVE_VFPRINTF /* Define to 1 if you have the `vsnprintf' function. */ #undef HAVE_VSNPRINTF /* Define to 1 if you have the `wait' function. */ #undef HAVE_WAIT /* Define to 1 if you have the `wait3' function. */ #undef HAVE_WAIT3 /* Define to 1 if you have the `waitpid' function. */ #undef HAVE_WAITPID /* Name of system on which apcupsd will run */ #undef HOST /* Default directory in which log is written */ #undef LOGDIR /* Default port number for NIS server */ #undef NISPORT /* Default directory in which nologin file is written */ #undef NOLOGDIR /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Default directory in which pid file is written */ #undef PIDDIR /* Default directory in which powerfail flag file is written */ #undef PWRFAILDIR /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* Define to 1 if the `S_IS*' macros in do not work properly. */ #undef STAT_MACROS_BROKEN /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Default directory in which apcupsd config files are stored */ #undef SYSCONFDIR /* Define if you have gdImageGif in libgd */ #undef SYS_IMGFMT_GIF /* Define if you have gdImagePng in libgd */ #undef SYS_IMGFMT_PNG /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Define to 1 if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING /* Define to `int' if doesn't define. */ #undef gid_t /* Define to `int' if does not define. */ #undef mode_t /* Define to `long int' if does not define. */ #undef off_t /* Define to `int' if does not define. */ #undef pid_t /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if doesn't define. */ #undef uid_t apcupsd-3.14.14/autoconf/config.sub000066400000000000000000001054051274230402600171260ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2014 Free Software Foundation, Inc. timestamp='2014-03-23' # This file 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 3 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, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: apcupsd-3.14.14/autoconf/configure.in000066400000000000000000001222721274230402600174600ustar00rootroot00000000000000dnl Autoconfigure input file for apcupsd (derived from fetchmail-4.7.4). dnl dnl Copyright (C) 1999-2000 Riccardo Facchetti dnl Copyright (C) 2003-2014 Adam Kropelin dnl dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoheader to produce a config.h.in dnl dnl A distinctive file to look for in srcdir. AC_INIT(Developers) dnl Config header file. AC_CONFIG_HEADER(include/apcconfig.h:autoconf/config.h.in) topdir=`pwd` AC_CONFIG_AUX_DIR(${topdir}/autoconf) dnl dnl Absolute srcdir ABSSRCDIR=`pwd` AC_SUBST(ABSSRCDIR) AC_SUBST(topdir) dnl go up one more level cd .. TOP_DIR=`pwd` cd ${topdir} AC_SUBST(TOP_DIR) VERSION=`sed -n -e 's/^.*VERSION.*"\(.*\)"$/\1/p' ${srcdir}/include/version.h` AC_SUBST(VERSION) DATE=`sed -n -e 's/^.*[ \t]*ADATE.*"\(.*\)"$/\1/p' ${srcdir}/include/version.h` AC_SUBST(DATE) dnl Executable extension, if any (e.g., .exe) AC_EXEEXT dnl dnl These need to be searched before. dnl AC_PATH_PROGS(TRUEPRG, true, :) AC_PATH_PROGS(FALSEPRG, false, :) dnl dnl Create a new path statement starting with what the user has and dnl adding directories we might need. dnl PATH=$PATH:/bin:/sbin:/etc:/usr/bin:/usr/bin/X11:/usr/sbin:/usr/local/bin:/usr/local/sbin export PATH dnl dnl Sets `host_cpu', `host_vendor', and `host_os' to the current host type. dnl AC_CANONICAL_HOST dnl Interesting things are often in /usr/local dnl But not if we're cross compiling! if test "$cross_compiling" = "no" ; then for incdir in /usr/local/include ; do if test -d "$incdir" ; then CPPFLAGS="${CPPFLAGS} -I$incdir" fi done for libdir in /usr/local/lib64 /usr/local/lib ; do if test -d "$libdir" ; then LDFLAGS="${LDFLAGS} -L$libdir" fi done fi dnl Special considerations when cross-compiling for win32 if test "$host_os" = "mingw32" ; then if test -z "$CROSSTOOLS" ; then CROSSTOOLS=${topdir}/../cross-tools fi if test -z "$DEPKGS"; then DEPKGS=${topdir}/../depkgs-win32 fi CPPFLAGS="-I${topdir}/src/win32/compat -I$DEPKGS/libroot/include -I$DEPKGS/libroot/include/pthread ${CPPFLAGS}" PATH=$CROSSTOOLS/mingw32/bin:$PATH LDFLAGS="-L$DEPKGS/libroot/lib ${LDFLAGS}" BG=-mwindows fi AC_SUBST(BG) AC_SUBST(CROSSTOOLS) AC_SUBST(DEPKGS) if test $HAVE_UNAME=yes -a x`uname -s` = xSunOS then dnl ---------------------------------------- dnl SunOS defaults dnl ---------------------------------------- AC_PREFIX_DEFAULT(/opt/apcupsd) dnl --exec-prefix == eprefix == prefix dnl --bindir == eprefix/bin dnl --sbindir == eprefix/sbin dnl dnl If the user has not set -sysconfdir, we set our default as dnl /etc/opt/apcupsd dnl if test x$sysconfdir = x'${prefix}/etc' ; then sysconfdir='/etc/opt/apcupsd' fi dnl dnl If the user has not set -sbindir, we set our default as /sbin dnl if test x$sbindir = x'${exec_prefix}/sbin' ; then sbindir='/etc/opt/apcupsd/sbin' fi dnl Solaris often has interesting things in /usr/sfw CPPFLAGS="${CPPFLAGS} -I/usr/sfw/include" LDFLAGS="${LDFLAGS} -L/usr/sfw/lib" else dnl ------------------------------------------- dnl non Sun defaults (i.e. all other platforms dnl ------------------------------------------- AC_PREFIX_DEFAULT(/usr) dnl dnl If the user has not set -sysconfdir, we set our default as /etc/apcupsd dnl if test x$sysconfdir = x'${prefix}/etc' ; then sysconfdir='/etc/apcupsd' fi dnl dnl If the user has not set -sbindir, we set our default as /sbin dnl if test x$sbindir = x'${exec_prefix}/sbin' ; then sbindir='/sbin' fi fi dnl dnl Check for programs. dnl AC_PROG_CXX dnl We require a C++ compiler now AC_PROG_CC dnl Determine a C compiler to use. AC_PROG_CPP dnl Determine a C pre-processor to use. AC_PROG_INSTALL dnl Determine a BSD install program. AC_PROG_AWK AC_ISC_POSIX dnl Default linker is gcc if test x$LD = x ; then LD="$CC" fi AC_SUBST(DEBUG) AC_SUBST(CFLAGS) AC_SUBST(CPPFLAGS) AC_SUBST(CXXFLAGS) AC_SUBST(LDFLAGS) AC_SUBST(LIBS) AC_SUBST(DRVLIBS) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/libdrivers.a" AC_SUBST(APCDRVLIBS) dnl Initialize pthreads inclusion: warn PTHREAD_LFLAGS must contain only dnl the pthreads libraries, if needed. For linker flags, add them to dnl LDFLAGS. PTHREAD_CFLAGS="" PTHREAD_LFLAGS="-lpthread" with_pthreads=yes AC_DEFINE(HAVE_PTHREADS, [1], [Define if you have pthreads]) AC_SUBST(PTHREAD_CFLAGS) AC_SUBST(PTHREAD_LFLAGS) APCACCESS=apcaccess SMTP=smtp APCTEST=apctest AC_SUBST(APCACCESS) AC_SUBST(SMTP) AC_SUBST(APCTEST) dnl Now check for programs AC_REQ_PATH_PROGS(SHUTDOWN, shutdown shutdown.bsd) AC_PATH_PROGS(APCUPSD_MAIL, mail, no) if test "$APCUPSD_MAIL" = "no" then AC_MSG_WARN([mail program not found !]) APCUPSD_MAIL=mail fi AC_REQ_PATH_PROGS(WALL, wall) AC_REQ_PATH_PROGS(SCRIPTSHELL, sh bash) AC_PROG_GMAKE AC_REQ_TOOL(RANLIB, ranlib) AC_REQ_PATH_PROG(RM, rm) AC_REQ_PATH_PROG(CP, cp) AC_REQ_PATH_PROG(ECHO, echo) AC_REQ_PATH_PROG(LN, ln) AC_REQ_PATH_PROG(SED, sed) AC_REQ_TOOL(AR, ar) AC_REQ_PATH_PROG(MV, mv) AC_CHECK_TOOL(WINDRES, windres) AC_CHECK_TOOLS(STRP, strip true) AC_PATH_PROG(RST2HTML, rst2html,) AC_PATH_PROG(RST2HTML, rst2html.py,) AC_PATH_PROG(RST2PDF, rst2pdf,) # ------------------------------------------------------------------------- # If the user has not set --mandir, we default to /usr/share/man # ------------------------------------------------------------------------- if test x$mandir = x'${prefix}/man' ; then mandir=/usr/share/man fi dnl dnl Check for library functions. dnl dnl Mandatory on all builds AC_CHECK_FUNCS( abort calloc getpid \ rewind signal strerror strncmp \ strncpy vfprintf ,, [AC_MSG_ERROR([cannot find required function.])] ) dnl Optional on all builds dnl We will provide our own implementations if needed AC_CHECK_FUNCS(snprintf vsnprintf strlcpy strlcat accept4) dnl Mandatory except for WIN32 builds where we provide our own if test "$host_os" != "mingw32" ; then AC_CHECK_FUNCS( fork ioctl kill select setsid tcgetattr ,, [AC_MSG_ERROR([cannot find required function.])] ) AC_MSG_CHECKING([for syslog]) AC_TRY_LINK( [#include ], [syslog(0, "%s", "test");], AC_MSG_RESULT([yes]), AC_CHECK_LIB(socket, std_syslog,, [AC_MSG_ERROR([cannot find required function.])]) AC_TRY_LINK( [#include ], [syslog(0, "%s", "test");], AC_MSG_RESULT([yes]), [AC_MSG_ERROR([cannot find required function.])]) ) fi dnl Solaris hides nanosleep in one of two libraries depending on version dnl If we can't find it at all we'll just use our own substitute. AC_SEARCH_LIBS(nanosleep, [rt posix4], AC_DEFINE(HAVE_NANOSLEEP, 1, [Define if you have the nanosleep function.]), [LIBEXTRAOBJ="$LIBEXTRAOBJ nanosleep.c"]) AC_FUNC_STRFTIME dnl check for strftime. # Under sysV68, socket and friends are provided by the C library. # -linet does not provide socket, but causes multiple definition # errors at link-time. It is thus better to only use the C library. # So don't add -linet to the link list unless it's necessary # # With Solaris socket and friends seem not to be in C library. # I hope that if socket is found, all the BSD friends are in the same library # # - RF # AC_SEARCH_LIBS(socket, [xnet socket inet]) AC_SEARCH_LIBS(gethostname, [xnet socket inet]) AC_SEARCH_LIBS(gethostbyname, [nsl resolv]) AC_SEARCH_LIBS(gethostbyname_r, [nsl resolv]) # The condition in this test copes with the presence of inet_addr in libc6. AC_SEARCH_LIBS(inet_addr, nsl) dnl Needed by Interactive UNIX System V/386 Release 3.2 AC_CHECK_FUNC(strchr, AC_MSG_RESULT([using libc's strchr]), AC_CHECK_LIB(cposix,strchr, [EXTRADEFS="$EXTRADEFS -D_SYSV3" LIBS="$LIBS -lcposix"])) AC_CHECK_FUNC(strstr, AC_DEFINE(HAVE_STRSTR,, [Define if you have strstr]), [LIBEXTRAOBJ="$LIBEXTRAOBJ strstr.c"]) AC_CHECK_FUNC(strcasecmp, AC_DEFINE(HAVE_STRCASECMP,, [Define if you have strcasecmp]), [LIBEXTRAOBJ="$LIBEXTRAOBJ strcasecmp.c"]) AC_CHECK_FUNC(memmove, AC_DEFINE(HAVE_MEMMOVE,, [Define if you have memmove]), [LIBEXTRAOBJ="$LIBEXTRAOBJ memmove.c"]) AC_CHECK_FUNC(getopt_long, AC_DEFINE(HAVE_GETOPTLONG,, [Define if you have getoptlong]), [LIBEXTRAOBJ="$LIBEXTRAOBJ getopt.c getopt1.c"]) AC_CHECK_FUNC(inet_pton, AC_DEFINE(HAVE_INETPTON,, [Define if you have inetpton]), [LIBEXTRAOBJ="$LIBEXTRAOBJ inet_pton.c"]) dnl dnl Check for presence of localtime_r dnl AC_CHECK_FUNC(localtime_r, AC_DEFINE(HAVE_LOCALTIME_R,, [Define if you have localtime_r]), [LIBEXTRAOBJ="$LIBEXTRAOBJ localtime_r.c"]) dnl dnl Check for header files. dnl AC_CHECK_HEADERS( arpa/inet.h ctype.h errno.h fcntl.h \ limits.h netdb.h netinet/in.h signal.h \ stdarg.h stdio.h stdlib.h string.h strings.h sys/ioctl.h \ sys/socket.h sys/types.h syslog.h termios.h \ unistd.h ,,[AC_MSG_WARN([at least 1 header file is missing. This may not compile.])]) AC_CHECK_HEADERS(arpa/nameser.h,AC_DEFINE(HAVE_NAMESER_H,, [Define if you have nameser.h])) AC_HEADER_STAT dnl Check for S_ISDIR and S_ISREG macros. AC_HEADER_TIME dnl Check for time.h and sys/time.h. AC_HEADER_SYS_WAIT dnl Check for dnl dnl Check for structures. dnl AC_STRUCT_TM dnl Check if time.h don't define struct tm. AC_STRUCT_TIMEZONE dnl Check how to have current timezone. dnl dnl Check for types. dnl AC_TYPE_GETGROUPS AC_TYPE_MODE_T AC_TYPE_OFF_T AC_TYPE_PID_T AC_TYPE_SIGNAL AC_TYPE_SIZE_T AC_TYPE_UID_T AC_TYPE_SOCKETLEN_T dnl dnl Check for system services. dnl AC_PATH_XTRA dnl Is X Window System interesting ?. **GAPCMON** AC_SYS_INTERPRETER dnl Check for '#!' in shell scripts. dnl dnl UNIX variants dnl case $host in *-*-sunos*) AC_DEFINE(HAVE_SUN_OS,, [Define if building for SunOS]) ;; *-*-solaris*) AC_DEFINE(HAVE_SUN_OS,, [Define if building for SunOS]) ;; *-*-osf*) AC_DEFINE(HAVE_OSF1_OS,, [Define if building for OSF1]) ;; *-*-aix*) AC_DEFINE(HAVE_AIX_OS,, [Define if building for AIX]) ;; *-*-hpux*) AC_DEFINE(HAVE_HPUX_OS,, [Define if building for HPUX]) ;; *-*-linux*) AC_DEFINE(HAVE_LINUX_OS,, [Define if building for Linux]) ;; *-*-freebsd*) AC_DEFINE(HAVE_FREEBSD_OS,, [Define if building for FreeBSD]) ;; *-*-netbsd*) AC_DEFINE(HAVE_NETBSD_OS,, [Define if building for NetBSD]) ;; *-*-openbsd*) AC_DEFINE(HAVE_OPENBSD_OS,, [Define if building for OpenBSD]) ;; *-*-bsdi*) AC_DEFINE(HAVE_BSDI_OS,, [Define if building for BSDi]) ;; *-*-irix*) AC_DEFINE(HAVE_SGI_OS,, [Define if building for IRIX]) ;; *-*-darwin*) AC_DEFINE(HAVE_DARWIN_OS,, [Define if building for Darwin]) ;; *-*-nto*) AC_DEFINE(HAVE_QNX_OS,, [Define if building for QNX]) ;; *-*-mingw*) AC_DEFINE(HAVE_MINGW,, [Define if building for MINGW]) ;; esac dnl dnl Check for enable particular features. dnl AC_ARG_ENABLE(all, [ AC_HELP_STRING([--enable-all], [Enable all optional modules])], [ if test "$enableval" = "yes" ; then enable_usb=yes enable_net=yes enable_snmp=yes enable_test=yes enable_pcnet=yes enable_modbus=yes enable_modbus_usb=yes enable_cgi=yes if test "$host_os" != "mingw32" ; then enable_gapcmon=yes fi fi], []) dnl dnl halpolicydir configuration dnl dnl Establish default case $host in *-*-linux*) HALPOLICYDIR="/usr/share/hal/fdi/policy/20thirdparty" ;; *) HALPOLICYDIR="" ;; esac dnl Allow user override AC_ARG_WITH(halpolicydir, [AC_HELP_STRING([--with-halpolicydir=DIR], [HAL policy directory (default is platform dependent)])], HALPOLICYDIR=$withval) dnl Report result if test "x$HALPOLICYDIR" != "x" ; then AC_MSG_RESULT([Using halpolicydir=$HALPOLICYDIR]) else AC_MSG_RESULT([Will not install HAL policy file]) fi AC_SUBST(HALPOLICYDIR) #-------------------------------------------------------------------- # Check for TCP wrapper support, code taken from Bacula KES-7Nov03 #-------------------------------------------------------------------- AC_ARG_WITH(libwrap, [AC_HELP_STRING([--with-libwrap=DIR], [Compile in libwrap (tcp_wrappers) support])], [ if test "x$withval" != "xno" ; then saved_LIBS="$LIBS" LIBS="$saved_LIBS -lwrap" AC_MSG_CHECKING([for libwrap]) AC_TRY_LINK( [ #include int deny_severity = 0; int allow_severity = 0; struct request_info *req; ], [ hosts_access(req); ], [ AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_LIBWRAP,, [Define if you have libwrap]) TCPW_MSG="yes" ], [ LIBS="$saved_LIBS -lwrap -lnsl" AC_TRY_LINK( [ #include int deny_severity = 0; int allow_severity = 0; struct request_info *req; ], [ hosts_access(req); ], [ AC_MSG_RESULT([yes]) AC_DEFINE(HAVE_LIBWRAP) TCPW_MSG="yes" ], [AC_MSG_ERROR([*** libwrap missing]) ] ] ) ) fi ] ) dnl dnl Check for enable of cgi program builds dnl ENABLE_CGI="no" CGI= GD_LIBS= SYS_GD_FOUND=no AC_ARG_ENABLE(cgi, [AC_HELP_STRING([--enable-cgi], [Compile CGI programs])], [ if test "$enableval" = "yes" then ENABLE_CGI="yes" CGI=cgi dnl dnl First search for system library that defines gdImagePng AC_CHECK_LIB(gd, gdImagePng, [ AC_MSG_RESULT([using PNG file format.]) AC_DEFINE(SYS_IMGFMT_PNG,, [Define if you have gdImagePng in libgd]) GD_LIBS="-lgd" SYS_GD_FOUND=yes ], [$as_unset ac_cv_lib_gd_gdImagePng], []) dnl dnl How about with libpng and libz dependencies? if test "${SYS_GD_FOUND}" = "no" then AC_CHECK_LIB(gd, gdImagePng, [ AC_MSG_RESULT([using PNG file format.]) AC_DEFINE(SYS_IMGFMT_PNG,, [Define if you have gdImagePng in libgd]) GD_LIBS="-lgd -lpng12 -lz" SYS_GD_FOUND=yes ], [], [-lpng12 -lz]) fi dnl dnl Second search for system library that defines gdImageGif if test "${SYS_GD_FOUND}" = "no" then AC_CHECK_LIB(gd, gdImageGif, [ AC_MSG_RESULT([using GIF file format.]) AC_DEFINE(SYS_IMGFMT_GIF,, [Define if you have gdImageGif in libgd]) GD_LIBS="-lgd" SYS_GD_FOUND=yes ], [], []) fi if test "${SYS_GD_FOUND}" = "no" then AC_MSG_ERROR([Your system lacks the GD library which is needed for compiling the apcupsd CGI programs. Please install libgd and re-run the ./configure script. Alternatively you can disable the CGI support.]) fi AC_CHECK_HEADER(gd.h, [ GDHEAD= ], [ AC_CHECK_HEADER(gd/gd.h, [ GDHEAD="gd/" ], [ AC_CHECK_HEADER(gd2/gd.h, [ GDHEAD="gd2/" ], [ AC_MSG_ERROR([Found system GD library but no header file. Please find the file gd.h in your system include directories and report its location to apcupsd-users@lists.sourceforge.net]) ]) ]) ]) AC_SUBST(GDHEAD) fi ]) dnl dnl Check for enable of drivers dnl AC_ARG_ENABLE(apcsmart, [ AC_HELP_STRING([--enable-apcsmart], [Compile APC SmartUPS serial driver (default)]) AC_HELP_STRING([--disable-apcsmart], [No APC SmartUPS serial driver])], [ if test "$enableval" = "yes" ; then dnl This is for C code inclusion AC_DEFINE(HAVE_APCSMART_DRIVER,, [Define if building apcsmart driver]) dnl This is for Makefile.in inside src/drivers/ APCSMART_DRIVER="apcsmart" AC_SUBST(APCSMART_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/apcsmart/libapcsmartdrv.a" fi ], [ AC_DEFINE(HAVE_APCSMART_DRIVER) APCSMART_DRIVER="apcsmart" AC_SUBST(APCSMART_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/apcsmart/libapcsmartdrv.a" ]) AC_ARG_ENABLE(dumb, [ AC_HELP_STRING([--enable-dumb], [Compile dumb UPS driver (default)]) AC_HELP_STRING([--disable-dumb], [No dumb UPS driver])], [ if test "$enableval" = "yes" ; then AC_DEFINE(HAVE_DUMB_DRIVER,, [Define if building simple signaling driver]) DUMB_DRIVER="dumb" AC_SUBST(DUMB_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/dumb/libdumbdrv.a" fi], [ AC_DEFINE(HAVE_DUMB_DRIVER) DUMB_DRIVER="dumb" AC_SUBST(DUMB_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/dumb/libdumbdrv.a" ]) dnl Allow user to force USB type to generic GENERICUSB="no" AC_ARG_WITH(generic-usb, [AC_HELP_STRING([--with-generic-usb], [Force use of generic USB driver]) ], [GENERICUSB="yes" ]) AC_ARG_ENABLE(usb, [ AC_HELP_STRING([--enable-usb], [Compile USB UPS code]) AC_HELP_STRING([--disable-usb], [No USB UPS code (default)])], [ if test "$enableval" = "yes" ; then dnl USB driver is usually determined by host system. dnl But if user forces generic_usb then fake it out. if test $GENERICUSB = "yes" ; then usbhost=forcegeneric else usbhost=$host fi AC_DEFINE(HAVE_USB_DRIVER,, [Define if building USB driver]) USB_DRIVER="usb" AC_SUBST(USB_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/usb/libusbdrv.a" case $usbhost in *-*-linux*) USB_TYPE="linux" AC_MSG_RESULT([Using Linux USB driver.]) ;; *) needlibusb=true USB_TYPE="generic" ;; esac AC_SUBST(USB_TYPE) DISPLAY_USB_DRIVER=$USB_TYPE-$USB_DRIVER fi ], []) AC_ARG_ENABLE(net, [ AC_HELP_STRING([--enable-net], [Compile networking driver for slaves (default)]) AC_HELP_STRING([--disable-net], [No network driver for slaves])], [ if test "$enableval" = "yes" ; then AC_DEFINE(HAVE_NET_DRIVER,, [Define if building net driver]) NET_DRIVER="net" AC_SUBST(NET_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/net/libnetdrv.a" fi ], [ AC_DEFINE(HAVE_NET_DRIVER) NET_DRIVER="net" AC_SUBST(NET_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/net/libnetdrv.a" ]) AC_ARG_ENABLE(snmp, [ AC_HELP_STRING([--enable-snmp], [Compile SNMP driver (default)]) AC_HELP_STRING([--disable-snmp], [No SNMP driver])], [ if test "$enableval" = "yes" ; then AC_DEFINE(HAVE_SNMPLITE_DRIVER,, [Define if building snmplite driver]) SNMPLITE_DRIVER="snmplite" DISPLAY_SNMP_DRIVER="snmp" AC_SUBST(SNMPLITE_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/snmplite/libsnmplitedrv.a" fi ], [ AC_DEFINE(HAVE_SNMPLITE_DRIVER) SNMPLITE_DRIVER="snmplite" DISPLAY_SNMP_DRIVER="snmp" AC_SUBST(SNMPLITE_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/snmplite/libsnmplitedrv.a" ]) dnl Enable test driver AC_ARG_ENABLE(test, [ AC_HELP_STRING([--enable-test], [Compile TEST driver code]) AC_HELP_STRING([--disable-test], [No TEST driver (default)])], [ if test "$enableval" = "yes" ; then AC_DEFINE(HAVE_TEST_DRIVER,, [Define if building test driver]) TEST_DRIVER="test" AC_SUBST(TEST_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/test/libtestdrv.a" fi], []) dnl Enable pcnet driver AC_ARG_ENABLE(pcnet, [ AC_HELP_STRING([--enable-pcnet], [Compile PCNET driver code (default)]) AC_HELP_STRING([--disable-pcnet], [No PCNET driver])], [ if test "$enableval" = "yes" ; then AC_DEFINE(HAVE_PCNET_DRIVER,, [Define if building PCNET driver]) PCNET_DRIVER="pcnet" AC_SUBST(PCNET_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/pcnet/libpcnetdrv.a" fi], [ AC_DEFINE(HAVE_PCNET_DRIVER) PCNET_DRIVER="pcnet" AC_SUBST(PCNET_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/pcnet/libpcnetdrv.a" ]) dnl Enable modbus USB support AC_ARG_ENABLE(modbus-usb, [ AC_HELP_STRING([--enable-modbus-usb], [Compile MODBUS/USB driver code]) AC_HELP_STRING([--disable-modbus-usb], [No MODBUS/USB driver (default)])], [ if test "$enableval" = "yes" ; then AC_DEFINE(HAVE_MODBUS_USB_DRIVER,, [Define if building MODBUS/USB driver]) MODBUS_USB_DRIVER="modbus-usb" AC_SUBST(MODBUS_USB_DRIVER) enable_modbus=yes needlibusb=true fi], []) dnl Enable modbus driver AC_ARG_ENABLE(modbus, [ AC_HELP_STRING([--enable-modbus], [Compile MODBUS driver code (default)]) AC_HELP_STRING([--disable-modbus], [No MODBUS driver])], [ if test "$enableval" = "yes" ; then AC_DEFINE(HAVE_MODBUS_DRIVER,, [Define if building MODBUS driver]) MODBUS_DRIVER="modbus" AC_SUBST(MODBUS_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/modbus/libmodbusdrv.a" fi], [ AC_DEFINE(HAVE_MODBUS_DRIVER) MODBUS_DRIVER="modbus" AC_SUBST(MODBUS_DRIVER) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/modbus/libmodbusdrv.a" ]) dnl If USB or MODBUS driver need libusb, handle it now if test "$needlibusb" = "true" ; then case $host in *-*-mingw*) LIBUSBH=libusb-winusb-bridge.h DRVLIBS="$DRVLIBS -lsetupapi" AC_MSG_RESULT([Using generic winusb USB driver.]) ;; *) dnl Use libusb-config if found, otherwise fall back on AC_CHECK_LIB AC_PATH_PROG(usbcfg, libusb-config) if test x$usbcfg != x ; then LIBUSB=`$usbcfg --libs` LIBUSBH=`$usbcfg --prefix`/include/usb.h else AC_CHECK_LIB(usb, usb_init, [LIBUSB=-lusb LIBUSBH=usb.h], [AC_MSG_ERROR(Unable to find libusb)], [$DRVLIBS]) fi DRVLIBS="$DRVLIBS $LIBUSB" AC_MSG_RESULT([Using generic libusb USB driver.]) ;; esac AC_SUBST(LIBUSBH) LIBUSBHID=libusbhid AC_SUBST(LIBUSBHID) APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/libusbhid/libusbhid.a" CPPFLAGS="$CPPFLAGS -I\$(topdir)/src/libusbhid" fi dnl Force NIS to enabled since libnis is required by apcaccess. dnl Users may still disable NIS at runtime in apcupsd.conf. AC_DEFINE(HAVE_NISSERVER,, [Define if apcupsd NIS server is being built]) AC_DEFINE(HAVE_NISLIB,, [Define if apcupsd NIS library is being built]) NISSRV_ENABLED=yes dnl Allow setting of NISIP value NISIP="0.0.0.0" AC_ARG_WITH(nisip, [AC_HELP_STRING([--with-nisip=IP-ADDRESS], [Specify the IP address to bind to (default=0.0.0.0)])], [NISIP="$withval";]) AC_SUBST(NISIP) CGIBIN="/etc/apcupsd" AC_ARG_WITH(cgi-bin, [AC_HELP_STRING([--with-cgi-bin=DIR], [Specify cgi-bin directory (default=/etc/apcupsd)])], [CGIBIN="$withval";]) dnl dnl Check for enable of gapcmon dnl GAPCMON= GAPCMON_ENABLED=no AC_ARG_ENABLE(gapcmon, [AC_HELP_STRING([--enable-gapcmon], [Build GTK/GUI front-end to apcupsd (default=no)])], [ if test "$enableval" = "yes" ; then GAPCMON=gapcmon GAPCMON_ENABLED=yes dnl dnl Check for Gnome packages dnl PKG_CHECK_MODULES(GAPCMON, gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0) GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DVERSION=\\\"$VERSION\\\"" fi], []) AC_SUBST(GAPCMON) dnl dnl Check for enable of apcagent dnl APCAGENT= APCAGENT_ENABLED=no AC_ARG_ENABLE(apcagent, [AC_HELP_STRING([--enable-apcagent], [Build menubar app for Mac OS X (default=no)])], [ if test "$enableval" = "yes" ; then case $host in *-*-darwin*) APCAGENT=apcagent APCAGENT_ENABLED=yes ;; *) AC_MSG_ERROR([apcagent can only be built on Mac OS X]) ;; esac fi], [case $host in *-*-darwin*) APCAGENT=apcagent APCAGENT_ENABLED=yes ;; esac]) AC_SUBST(APCAGENT) dnl dnl Figure out which gethostbyname_r() variant we have dnl AX_FUNC_WHICH_GETHOSTBYNAME_R case "$ac_cv_func_which_gethostbyname_r" in three) AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_3,, [Define for 3 argument version of gethostbyname_r]) GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DHAVE_FUNC_GETHOSTBYNAME_R_3" ;; five) AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_5,, [Define for 5 argument version of gethostbyname_r]) GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DHAVE_FUNC_GETHOSTBYNAME_R_5" ;; six) AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_6,, [Define for 6 argument version of gethostbyname_r]) GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DHAVE_FUNC_GETHOSTBYNAME_R_6" ;; no) AC_DEFINE(HAVE_FUNC_GETHOSTBYNAME_R_0,, [Define if system does not have gethostbyname_r]) GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DHAVE_FUNC_GETHOSTBYNAME_R_0" ;; *) AC_MSG_ERROR([gethostbyname_r is required]) ;; esac if test -n "$GCC"; then # Starting with GCC 3.0, you must link C++ programs against either # libstdc++ (shared by default), or libsupc++ (always static). If # you care about binary portability between Linux distributions, # you need to either 1) build your own GCC with static C++ libraries # or 2) link using gcc and libsupc++. We choose the latter since # CUPS doesn't (currently) use any of the stdc++ library. # # Previous versions of GCC do not have the reliance on the stdc++ # or g++ libraries, so the extra supc++ library is not needed. AC_MSG_CHECKING(if libsupc++ is required) SUPC="`$CXX -print-file-name=libsupc++.a 2>/dev/null`" case "$SUPC" in libsupc++.a*) # Library not found, so this is an older GCC... LD="$CXX" AC_MSG_RESULT(no) ;; *) # This is gcc 3.x, and it knows of libsupc++, so we need it LIBS="$LIBS -lsupc++" LD="$CC" AC_MSG_RESULT(yes) # See if this system has a broken libsupc++ that requires # a workaround (FreeBSD 5.x, 6.x) case $host in *-*-freebsd*) AC_MSG_CHECKING(if libsupc++ is missing __terminate_handler) nm -C --defined-only "$SUPC" 2>/dev/null | grep __terminate_handler > /dev/null if test $? -eq 0 ; then AC_MSG_RESULT(no) else AC_MSG_RESULT(yes -- will attempt workaround) LIBEXTRAOBJ="$LIBEXTRAOBJ libsupc++fix.cpp" fi ;; esac ;; esac fi dnl Disable exceptions and RTTI if compiler supports it AX_ADD_COMPILE_FLAG(-fno-exceptions) AX_ADD_COMPILE_FLAG(-fno-rtti) dnl Configure compile warnings AX_ADD_COMPILE_FLAG(-Wall) AX_ADD_COMPILE_FLAG(-Wno-unused-result) AC_SUBST(MAKE) AC_SUBST(CP) AC_SUBST(MV) AC_SUBST(ECHO) AC_SUBST(LN) AC_SUBST(SED) AC_SUBST(AR) AC_SUBST(RM) AC_SUBST(CC) AC_SUBST(CXX) AC_SUBST(LD) AC_SUBST(CGI) AC_SUBST(GD_LIBS) AC_SUBST(CGIBIN) AC_DEFINE_UNQUOTED(SYSCONFDIR, "$sysconfdir", [Default directory in which apcupsd config files are stored]) AC_SUBST(SYSCONFDIR) AC_SUBST(RST2HTML) AC_SUBST(RST2PDF) dnl If the AC_CONFIG_AUX_DIR macro for autoconf is used we will probably dnl find the mkinstalldirs script in another subdir than ($topdir). dnl Try to locate it. MKINSTALLDIRS= if test -n "$ac_aux_dir"; then MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" fi if test x$MKINSTALLDIRS = x ; then MKINSTALLDIRS="\$(topdir)/autoconf/mkinstalldirs" fi AC_SUBST(MKINSTALLDIRS) dnl AC_CHECK_FUNC calls that might hack the Makefile must precede dnl the following AC_SUBSTs AC_SUBST(EXTRADEFS) AC_SUBST(LIBEXTRAOBJ) AC_SUBST(EXTRAOBJ) dnl Check out the wait reality. We have to assume sys/wait.h is present. AC_CHECK_FUNCS(wait waitpid wait3) if test "$ENABLE_CGI" = "yes" then AC_CHECK_FUNCS( snprintf,, [AC_MSG_ERROR([cannot find required function.])]) echo 'Enabling cgi program support...' else echo 'Disabling cgi support...' fi dnl dnl Find out the distribution. NOTE!!! Only determine the dnl distribution here. Do all additional work below. dnl # now allow user to specify DISTNAME AC_ARG_WITH(distname, [AC_HELP_STRING([--with-distname=NAME], [Specify DISTNAME])], [DISTNAME=$withval]) if test "x$DISTNAME" != "x" then echo "distname set to $DISTNAME" elif test "$host_os" = "mingw32" ; then DISTNAME=mingw elif test $HAVE_UNAME=yes -a x`uname -s` = xOSF1 then DISTNAME=alpha elif test $HAVE_UNAME=yes -a x`uname -s` = xHP-UX then DISTNAME=hpux elif test $HAVE_UNAME=yes -a x`uname -s` = xSunOS then DISTNAME=sun elif test $HAVE_UNAME=yes -a x`uname -s` = xFreeBSD then DISTNAME=freebsd elif test $HAVE_UNAME=yes -a x`uname -s` = xNetBSD then DISTNAME=netbsd elif test $HAVE_UNAME=yes -a x`uname -s` = xOpenBSD then DISTNAME=openbsd elif test $HAVE_UNAME=yes -a x`uname -s` = xBSD/OS then DISTNAME=bsdi elif test $HAVE_UNAME=yes -a x`uname -s` = xDarwin then DISTNAME=darwin elif test $HAVE_UNAME=yes -a x`uname -s` = xQNX then DISTNAME=qnx elif test -f /etc/SuSE-release then DISTNAME=suse elif test -d /etc/SuSEconfig then DISTNAME=suse5 elif test -f /etc/mandrake-release then DISTNAME=mandrake elif test -f /etc/whitebox-release then DISTNAME=redhat elif test -f /etc/redhat-release then DISTNAME=redhat elif test -f /etc/yellowdog-release then DISTNAME=yellowdog elif test -f /etc/debian_version then DISTNAME=debian elif test -f /etc/slackware-version then DISTNAME=slackware elif test -f /etc/gentoo-release then DISTNAME=gentoo elif test -f /etc/engarde-version then DISTNAME=engarde else DISTNAME=unknown fi dnl dnl Check for enable install of distdir dnl DISTDIR=$DISTNAME with_distdir="yes" AC_ARG_ENABLE(install-distdir, [AC_HELP_STRING([--enable-install-distdir], [Install distribution])], [ if test "$enableval" = "no" ; then DISTDIR="" with_distdir="no" fi ]) AC_SUBST(DISTDIR) dnl dnl At this point, we define the apcupsd defaults for a dnl number of different values (directories, ports, etc) dnl When the distribution is determined a bit lower, the dnl default can be reset to correspond to the standard for dnl that system. dnl Finally, after that any value that the user has set via dnl command line options will apply. dnl # Define the default UPS UPSTYPE=apcsmart # Define the default Cable UPSCABLE=smart # set the default nologin directory nologdir=/etc # Find the default directory to put the root-mode PID file in for PIDDIR in "/var/run" "/etc/apcupsd" do if test -d $PIDDIR then break; fi done # Find the default directory to put the apcupsd.events and apcupsd.status files for LOGDIR in "/var/log" "/etc/apcupsd" do if test -d $LOGDIR then break; fi done # set the default serial port lock director for LOCKDIR in "/var/lock" "/var/spool/locks" "/etc/apcupsd" do if test -d $LOCKDIR then break; fi done # set the default PWRFAILDIR PWRFAILDIR=${sysconfdir} # define the default serial port device SERIALDEV=/dev/ttyS0 # define the default NIS (Network Information Server -- CGI) port NISPORT=3551 # # Now we set appropriate distribution specific # variables and defaults # case "$DISTNAME" in alpha) PTHREAD_LFLAGS="-lpthread -lexc" DISTVER=`uname -r` SERIALDEV=/dev/tty01 LOCKDIR=/var/spool/locks LOGDIR=/etc/apcupsd DFILES="\ platforms/alpha/apcupsd \ platforms/alpha/awkhaltprog" ;; bsdi) DISTVER=`uname -a |awk '{print $3}'` ;; debian) DISTVER=`cat /etc/debian_version` DFILES="\ platforms/debian/apcupsd \ platforms/debian/ups-monitor" ;; freebsd) DISTVER=`uname -a |awk '{print $3}'` SERIALDEV=/dev/cuaa0 nologdir=/var/run PWRFAILDIR=/var/run LOCKDIR=/var/spool/lock PTHREAD_CFLAGS="-pthread" PTHREAD_LFLAGS="" LDFLAGS="$LDFLAGS -pthread" DFILES="\ platforms/freebsd/apcupsd \ platforms/freebsd/apccontrol" ;; gentoo) DISTVER=`awk '/version / {print $5}' < /etc/gentoo-release` DFILES="\ platforms/gentoo/apcupsd \ platforms/gentoo/halt" ;; hpux) DISTVER=`uname -r` SERIALDEV=/dev/tty0p0 PTHREAD_CFLAGS="-D_XOPEN_SOURCE_EXTENDED -D_REENTRANT" DFILES="\ platforms/hpux/apcupsd \ platforms/hpux/halt" ;; netbsd) DISTVER=`uname -a |awk '{print $3}'` SERIALDEV=/dev/cua01 PTHREAD_CFLAGS="-pthread" PTHREAD_LFLAGS="" LDFLAGS="$LDFLAGS -pthread" DFILES="\ platforms/netbsd/apcupsd" ;; openbsd) DISTVER=`uname -a |awk '{print $3}'` SERIALDEV=/dev/cua01 LOCKDIR=/var/spool/lock PTHREAD_CFLAGS="-pthread" PTHREAD_LFLAGS="" LDFLAGS="$LDFLAGS -pthread" DFILES="\ platforms/openbsd/apcupsd \ platforms/openbsd/apccontrol" ;; mandrake) DISTVER=`cat /etc/mandrake-release | grep release | cut -f 5 -d ' '` DFILES="\ platforms/mandrake/apcupsd \ platforms/mandrake/apcupsd.spec \ platforms/mandrake/awkhaltprog" ;; redhat) if test -f /etc/whitebox-release ; then f=/etc/whitebox-release else f=/etc/redhat-release fi if test `cat $f | grep release | cut -f 3 -d ' '`x = "Enterprise"x ; then DISTVER="Enterprise "`cat $f | grep release | cut -f 6 -d ' '` else DISTVER=`cat /etc/redhat-release | grep release | cut -f 5 -d ' '` fi DFILES="\ platforms/redhat/apcupsd \ platforms/redhat/apcupsd.spec \ platforms/redhat/awkhaltprog" ;; yellowdog) if test `cat /etc/yellowdog-release | grep release | cut -f 3 -d ' '`x = "Enterprise"x ; then DISTVER="Enterprise "`cat /etc/yellowdog-release | grep release | cut -f 6 -d ' '` else DISTVER=`cat /etc/yellowdog-release | grep release | cut -f 5 -d ' '` fi DFILES="\ platforms/yellowdog/apcupsd \ platforms/yellowdog/apcupsd.spec \ platforms/yellowdog/awkhaltprog" ;; engarde) DISTVER=`cat /etc/engarde-release | grep ersion | cut -f 5 -d ' '` DFILES="\ platforms/engarde/apcupsd \ platforms/engarde/apcupsd.spec \ platforms/engarde/awkhaltprog" ;; slackware) DISTVER=`cat /etc/slackware-version` DFILES="\ platforms/slackware/apcupsd \ platforms/slackware/rc6.patch" ;; sun) DISTVER=Solaris SERIALDEV=/dev/ttya PWRFAILDIR=/etc PIDDIR=/var/run LOCKDIR=/var/spool/locks LOGDIR=${sysconfdir} APCUPSD_MAIL=/usr/bin/mailx PTHREAD_CFLAGS="-D_POSIX_PTHREAD_SEMANTICS" DFILES="\ platforms/sun/apcupsd \ platforms/sun/rc0.solaris \ platforms/sun/apccontrol" ;; suse) DISTVER=`cat /etc/SuSE-release |grep VERSION| cut -f 3 -d ' '` DFILES="\ platforms/suse/apcupsd \ platforms/suse/awkhaltprog" ;; suse5) DISTNAME=suse DISTVER=5.x DFILES="\ platforms/suse/apcupsd \ platforms/suse/halt-setup.sh \ platforms/suse/halt" ;; darwin) DISTVER=`uname -r` SERIALDEV= UPSTYPE=usb UPSCABLE=usb PIDDIR=/var/run LOCKDIR=/var/tmp DFILES="\ platforms/darwin/apccontrol \ platforms/darwin/apcupsd-start \ platforms/darwin/apcupsd-uninstall \ platforms/darwin/org.apcupsd.apcupsd.plist" ;; qnx) PTHREAD_LFLAGS="" DISTVER=`uname -r` SERIALDEV=/dev/ser1 DFILES="\ platforms/qnx/apcupsd \ platforms/qnx/apccontrol" ;; mingw) PTHREAD_LFLAGS="-lpthreadGCE" LIBS="${LIBS} -luser32 -lgdi32 -lwsock32 -lnetapi32" CPPFLAGS="${CPPFLAGS} -D_WIN32_IE=0x0500" WIN32=win32 AC_SUBST(WIN32) ;; unknown) DISTVER=unknown DFILES="\ platforms/unknown/apcupsd \ platforms/unknown/halt" ;; *) AC_MSG_WARN([Something went wrong. Unknown DISTNAME $DISTNAME]) ;; esac dnl dnl Allow user to set nologdir dnl AC_ARG_WITH(nologin, [AC_HELP_STRING([--with-nologin=DIR], [Specify nologin file directory (default /etc)])], [ nologdir="$withval"; ]) # now allow the user to specify the PID directory AC_ARG_WITH(pid-dir, [AC_HELP_STRING([--with-pid-dir=DIR], [Specify PIDDIR directory (default is OS dependent)])], [PIDDIR="$withval";]) # now allow user to specify LOGDIR AC_ARG_WITH(log-dir, [AC_HELP_STRING([--with-log-dir=DIR], [Specify EVENTS and STATUS directory (default is OS dependent)])], [LOGDIR="$withval";]) # now allow user to specify LOCKDIR AC_ARG_WITH(lock-dir, [AC_HELP_STRING([--with-lock-dir=DIR], [Specify serial port lock directory (default is OS dependent)])], [LOCKDIR="$withval";]) # now allow user to specify PWRFAILDIR AC_ARG_WITH(pwrfail-dir, [AC_HELP_STRING([--with-pwrfail-dir=DIR], [Specify power failure file directory (default is OS dependent)])], [PWRFAILDIR="$withval";]) # now allow user to specify SERIALDEV AC_ARG_WITH(serial-dev, [AC_HELP_STRING([--with-serial-dev=DEV], [Specify serial port device])], [SERIALDEV="$withval";]) AC_ARG_WITH(dev, [AC_HELP_STRING([--with-dev=DEV], [Specify port or device])], [SERIALDEV="$withval";]) # now allow user to specify NISPORT AC_ARG_WITH(nis-port, [AC_HELP_STRING([--with-nis-port=PORT], [Specify NIS (CGI) port (default 3551 except Debian)])], [NISPORT="$withval";]) # now allow user to specify UPSTYPE AC_ARG_WITH(upstype, [AC_HELP_STRING([--with-upstype=TYPE], [Specify the UPS type])], [UPSTYPE="$withval";]) # now allow user to specify UPSCABLE AC_ARG_WITH(upscable, [AC_HELP_STRING([--with-upscable=CABLE], [Specify the UPS cable])], [UPSCABLE="$withval";]) AC_SUBST(DISTNAME) AC_SUBST(DISTVER) AC_SUBST(SERIALDEV) AC_DEFINE_UNQUOTED(PIDDIR, "$PIDDIR", [Default directory in which pid file is written]) AC_SUBST(PIDDIR) AC_DEFINE_UNQUOTED(LOGDIR, "$LOGDIR", [Default directory in which log is written]) AC_SUBST(LOGDIR) AC_DEFINE_UNQUOTED(NOLOGDIR, "$nologdir", [Default directory in which nologin file is written]) AC_SUBST(nologdir) AC_DEFINE_UNQUOTED(PWRFAILDIR, "$PWRFAILDIR", [Default directory in which powerfail flag file is written]) AC_SUBST(PWRFAILDIR) AC_SUBST(LOCKDIR) AC_SUBST(NISPORT) AC_DEFINE_UNQUOTED(NISPORT, $NISPORT, [Default port number for NIS server]) AC_SUBST(UPSTYPE) AC_SUBST(UPSCABLE) HOST=$DISTNAME AC_DEFINE_UNQUOTED(HOST, "$HOST", [Name of system on which apcupsd will run]) AC_SUBST(HOST) dnl dnl Find out gcc's installation directory and include files. Used in dnl configure. dnl dnl Make sure a gccinclude variable exist. dnl '.' is innocuous. gccinclude="." if test "$CC" = "gcc" then rm -f $srcdir/gcc.v $CC -v 2> $srcdir/gcc.v gccinclude=`cat $srcdir/gcc.v|grep specs|awk '{print $4}'| \ sed -e 's|specs|include|g'` echo "gcc private include directory found." rm -f $srcdir/gcc.v fi dnl dnl First entry must always be "variables.mak" dnl GENERATE_FILES="\ autoconf/variables.mak \ platforms/apccontrol \ platforms/etc/changeme \ platforms/etc/commfailure \ platforms/etc/commok \ platforms/etc/offbattery \ platforms/etc/onbattery \ platforms/etc/apcupsd.conf \ examples/safe.apccontrol \ $DFILES" if test "$needlibusb"x = "true"x then GENERATE_FILES="$GENERATE_FILES \ include/libusb.h" fi if test "$ENABLE_CGI" = "yes" then GENERATE_FILES="$GENERATE_FILES src/cgi/cgiconfig.h" fi AC_OUTPUT([ ${GENERATE_FILES} ], []) chmod 755 examples/safe.apccontrol $MAKE clean # # A whole lot of hand springs to get the compiler version. # This is because gcc changed the output in version 3.0 # CXXVERSION=`${CXX} --version | tr '\n' ' ' | cut -f 3 -d ' '` if test "x${CXXVERSION}" = "x" ; then CXXVERSION=`${CXX} --version | tr '\n' ' ' | cut -f 1 -d ' '` fi eval srcdir=${srcdir} eval sbindir=${sbindir} eval sysconfdir=${sysconfdir} eval mandir=${mandir} echo " Configuration on `date`: Host: $host -- ${DISTNAME} ${DISTVER} Apcupsd version: ${VERSION} (${DATE}) Source code location: ${srcdir} Install binaries: ${sbindir} Install config files: ${sysconfdir} Install man files: ${mandir} Nologin file in: ${nologdir} PID directory: ${PIDDIR} LOG dir (events, status) ${LOGDIR} LOCK dir (for serial port) ${LOCKDIR} Power Fail dir ${PWRFAILDIR} Compiler: ${CXX} ${CXXVERSION} Preprocessor flags: ${CPPFLAGS} Compiler flags: ${CXXFLAGS} ${PTHREAD_FLAGS} Linker: ${LD} Linker flags: ${LDFLAGS} Host and version: ${DISTNAME} ${DISTVER} Shutdown Program: ${SHUTDOWN} Port/Device: ${SERIALDEV} Network Info Port (CGI): ${NISPORT} UPSTYPE ${UPSTYPE} UPSCABLE ${UPSCABLE} drivers (no-* are disabled): ${APCSMART_DRIVER:-no-apcsmart} ${DUMB_DRIVER:-no-dumb} ${NET_DRIVER:-no-net} ${DISPLAY_USB_DRIVER:-no-usb} ${DISPLAY_SNMP_DRIVER:-no-snmp} ${PCNET_DRIVER:-no-pcnet} ${MODBUS_DRIVER:-no-modbus} ${MODBUS_USB_DRIVER:-no-modbus-usb} ${TEST_DRIVER:-no-test} enable-nis: ${NISSRV_ENABLED} with-nisip: ${NISIP} enable-cgi: ${ENABLE_CGI} with-cgi-bin: ${CGIBIN} with-libwrap: ${with_libwrap} enable-pthreads: ${with_pthreads} enable-dist-install: ${with_distdir} enable-gapcmon: ${GAPCMON_ENABLED} enable-apcagent: ${APCAGENT_ENABLED} " > config.out cat config.out echo Configuration complete: Run \'$MAKE\' to build apcuspd. echo echo $PATH | grep /usr/ucb >/dev/null if test $? = 0 ; then AC_MSG_WARN([ WARNING! You have /usr/ucb on your path. We STRONGLY recommend that you remove it and rerun configure. Otherwise apcupsd may be unable to shutdown your system. ]); fi apcupsd-3.14.14/autoconf/install-sh000077500000000000000000000112441274230402600171470ustar00rootroot00000000000000#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. # # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" tranformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 apcupsd-3.14.14/autoconf/mkinstalldirs000077500000000000000000000012121274230402600177430ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy # Author: Noah Friedman # Created: 1993-05-16 # Last modified: 1994-03-25 # Public domain errstatus=0 for file in ${1+"$@"} ; do set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` shift pathcomp= for d in ${1+"$@"} ; do pathcomp="$pathcomp$d" case "$pathcomp" in -* ) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then # echo "mkdir $pathcomp" 1>&2 mkdir "$pathcomp" || errstatus=$? fi pathcomp="$pathcomp/" done done exit $errstatus # mkinstalldirs ends here apcupsd-3.14.14/autoconf/targets.mak000066400000000000000000000223071274230402600173100ustar00rootroot00000000000000# Pull in autoconf variables -include $(topdir)/autoconf/variables.mak # Now that we have autoconf vars, overwrite $(topdir) with absolute path # version instead of relative version we inherited. The easy way to do this # would be to use $(abspath $(topdir)), but abspath is a gmake-3.81 feature. # So we let autoconf figure it out for us. topdir := $(abstopdir) # Older (pre-3.79) gmake does not have $(CURDIR) ifeq ($(CURDIR),) CURDIR := $(shell pwd) endif # By default we do pretty-printing only V := @ VV := @ NPD := --no-print-directory # Check verbose flag ifeq ($(strip $(VERBOSE)),1) V := NPD := endif ifeq ($(strip $(VERBOSE)),2) V := VV := NPD := endif # Relative path to this dir from $(topdir) RELDIR := $(patsubst /%,%,$(subst $(topdir),,$(CURDIR))) ifneq ($(strip $(RELDIR)),) RELDIR := $(RELDIR)/ endif # Strip extensions STRIPEXT = $(foreach file,$(1),$(basename $(file))) # Convert a list of sources to a list of objects in OBJDIR SRC2OBJ = $(foreach obj,$(call STRIPEXT,$(1)),$(dir $(obj))$(OBJDIR)/$(notdir $(obj)).o) # All objects, derived from all sources OBJS = $(call SRC2OBJ,$(SRCS)) # Dependency files, derived from all sources DEPS = $(foreach dep,$(call STRIPEXT,$(SRCS)),$(DEPDIR)/$(dep).P) # Default target: Build all subdirs, then reinvoke make to build local # targets. This is a little gross, but necessary to force make to build # subdirs first when running in parallel via 'make -jN'. Hopefully I will # discover a cleaner way to solve this someday. .PHONY: all all: all-subdirs $(VV)+$(MAKE) $(NPD) all-targets # 'all-targets' is supplied by lower level Makefile. It represents # all targets to be built at that level. We list it here with a do-nothing # action in order to suppress the "Nothing to do for all-targets" message # when all targets are up to date. .PHONY: all-targets all-targets: @# # standard install target: Same logic as 'all'. .PHONY: install install: all-subdirs $(VV)+$(MAKE) $(NPD) all-targets $(VV)+$(MAKE) $(NPD) all-install # 'all-install' is extended by lower-level Makefile to perform any # required install actions. .PHONY: all-install all-install: @# # no-op targets for use by lower-level Makefiles when a particular # component is not being installed. .PHONY: install- uninstall- install-: uninstall-: # standard uninstall target: Depends on subdirs to force recursion, # then reinvokes make to uninstall local targets. Same logic as 'install'. .PHONY: uninstall uninstall: all-subdirs $(VV)+$(MAKE) $(NPD) all-uninstall # 'all-uninstall' is extended by lower-level Makefiles to perform # any required uninstall actions. .PHONY: all-uninstall all-uninstall: @# # Typical clean target: Remove all objects and dependency files. .PHONY: clean clean: $(V)find . -depth \ \( -name $(OBJDIR) -o -name $(DEPDIR) -o -name \*.a \) \ -exec $(ECHO) " CLEAN" \{\} \; -exec $(RMF) \{\} \; # Remove all files that show as unversioned in svn .PHONY: svnclean svnclean: $(V)rm -rfv `svn status --no-ignore 2>/dev/null | sed -e '/^[?I]/ s/^[?I] *//p' -e d` # Template rule to build a subdirectory .PHONY: %_DIR %_DIR: @$(ECHO) " " $(RELDIR)$* $(VV)+$(MAKE) -C $* $(NPD) $(MAKECMDGOALS) # Collective all-subdirs target depends on subdir rule .PHONY: all-subdirs all-subdirs: $(foreach subdir,$(SUBDIRS),$(subdir)_DIR) # Echo with no newline # Pipline here is silly, but should be more portable # than 'echo -n' or 'echo ...\c'. Cannot use autoconf # to figure this out since 'make install' may be run # with root's shell when ./configure was run with user's # shell. Could also use 'printf' but not certain how # universal that is. define ECHO_N $(ECHO) $(1) | tr -d '\n' endef # How to build dependencies MAKEDEPEND = $(CC) -M $(CPPFLAGS) $< > $(df).d ifeq ($(strip $(NODEPS)),) define DEPENDS if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi; \ $(MAKEDEPEND); \ $(call ECHO_N,$(OBJDIR)/) > $(df).P; \ $(SED) -e 's/#.*//' -e '/^$$/ d' < $(df).d >> $(df).P; \ $(SED) -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \ -e '/^$$/ d' -e 's/$$/ :/' < $(df).d >> $(df).P; \ $(RMF) $(df).d endef else DEPENDS := endif # Rule to build *.o from *.c and generate dependencies for it $(OBJDIR)/%.o: %.c @$(ECHO) " CXX " $(RELDIR)$< $(VV)if test ! -d $(OBJDIR); then mkdir -p $(OBJDIR); fi $(V)$(CXX) $(CXXFLAGS) -c -o $@ $< $(VV)$(DEPENDS) # Rule to build *.o from *.cpp and generate dependencies for it $(OBJDIR)/%.o: %.cpp @$(ECHO) " CXX " $(RELDIR)$< $(VV)if test ! -d $(OBJDIR); then mkdir -p $(OBJDIR); fi $(V)$(CXX) $(CXXFLAGS) -c -o $@ $< $(VV)$(DEPENDS) # Rule to build *.o from *.m and generate dependencies for it $(OBJDIR)/%.o: %.m @$(ECHO) " OBJC " $(RELDIR)$< $(VV)if test ! -d $(OBJDIR); then mkdir -p $(OBJDIR); fi $(V)$(OBJC) $(OBJCFLAGS) -c -o $@ $< $(VV)$(DEPENDS) # Rule to link an executable define LINK @$(ECHO) " LD " $(RELDIR)$@ $(V)$(LD) $(LDFLAGS) $+ -o $@ $(LIBS) endef # Rule to generate an archive (library) MAKELIB=$(call ARCHIVE,$@,$(OBJS)) define ARCHIVE @$(ECHO) " AR " $(RELDIR)$(1) $(VV)$(RMF) $(1) $(V)$(AR) rc $(1) $(2) $(V)$(RANLIB) $(1) endef # How to generate a *.nib from a *.xib %.nib: %.xib @$(ECHO) " NIB " $(RELDIR)$< $(VV)if test ! -d $(OBJDIR); then mkdir -p $(OBJDIR); fi $(V)$(NIB) $(NIBFLAGS) --compile $@ $< # Rule to create a directory during install define MKDIR $(if $(wildcard $(DESTDIR)$(1)),, \ @$(ECHO) " MKDIR" $(DESTDIR)$(1)) $(if $(wildcard $(DESTDIR)$(1)),, \ $(V)$(MKINSTALLDIRS) $(DESTDIR)$(1)) endef # Install a program file, given mode, src, and dest define INSTPROG @$(ECHO) " COPY " $(2) =\> $(DESTDIR)$(3) $(V)$(INSTALL_PROGRAM) $(STRIP) -m $(1) $(2) $(DESTDIR)$(3) endef # Install a data file, given mode, src, and dest define INSTDATA @$(ECHO) " COPY " $(2) =\> $(DESTDIR)$(3) $(V)$(INSTALL_DATA) -m $(1) $(2) $(DESTDIR)$(3) endef # Install a data file, given mode, src, and dest. # Existing dest file is preserved; new file is named *.new if dest exists. define INSTNEW @$(ECHO) " COPY " $(notdir $(2)) =\> $(DESTDIR)$(3)/$(notdir $(2))$(if $(wildcard $(DESTDIR)$(3)/$(notdir $(2))),.new,) $(V)$(INSTALL_DATA) -m $(1) $(2) $(DESTDIR)$(3)/$(notdir $(2))$(if $(wildcard $(DESTDIR)$(3)/$(notdir $(2))),.new,) endef # Install a data file, given mode, src, and dest. # Existing dest file is renamed to *.orig if it exists. define INSTORIG $(if $(wildcard $(DESTDIR)$(3)/$(notdir $(2))), \ @$(ECHO) " MV " $(DESTDIR)$(3)/$(notdir $(2)) =\> \ $(DESTDIR)$(3)/$(notdir $(2)).orig,) $(if $(wildcard $(DESTDIR)$(3)/$(notdir $(2))), \ $(V)$(MV) $(DESTDIR)$(3)/$(notdir $(2)) $(DESTDIR)$(3)/$(notdir $(2)).orig,) @$(ECHO) " COPY " $(notdir $(2)) =\> $(DESTDIR)$(3)/$(notdir $(2)) $(V)$(INSTALL_SCRIPT) -m $(1) $(2) $(DESTDIR)$(3) endef # Make a symlink define SYMLINK @$(ECHO) " LN " $(DESTDIR)/$(2) -\> $(1) $(V)$(LN) -sf $(1) $(DESTDIR)/$(2) endef # Copy a file define COPY @$(ECHO) " CP " $(1) =\> $(DESTDIR)/$(2) $(V)$(CP) -fR $(1) $(DESTDIR)/$(2) endef # Uninstall a file define UNINST @$(ECHO) " RM " $(DESTDIR)$(1) $(V)$(RMF) $(DESTDIR)$(1) endef # Announce distro install define DISTINST @$(ECHO) " ------------------------------------------------------------" @$(ECHO) " $(1) distribution installation" @$(ECHO) " ------------------------------------------------------------" endef # Announce distro uninstall define DISTUNINST @$(ECHO) " ------------------------------------------------------------" @$(ECHO) " $(1) distribution uninstall" @$(ECHO) " ------------------------------------------------------------" endef # If DESTDIR is set, we do no chkconfig processing ifeq ($(DESTDIR),) define CHKCFG $(if $(wildcard $(2)),@$(ECHO) " CKCFG" $(1):$(2)) $(if $(wildcard $(2)),$(V)$(CHKCONFIG) --$(1) apcupsd) endef endif # How to massage dependency list from rst2html ifeq ($(strip $(NODEPS)),) define RSTDEPENDS $(ECHO) $@: $< \\ > $(df).P; \ $(SED) -e '$$q' -e 's/^.*$$/& \\/' < $(df).d >> $(df).P; \ $(ECHO) $<: >> $(df).P; \ $(SED) -e 's/^.*$$/&:/' < $(df).d >> $(df).P; \ $(RMF) $(df).d endef else RSTDEPENDS := endif # Build *.html from *.rst and generate dependencies for it %.html: %.rst @$(ECHO) " HTML " $< ifneq ($(strip $(RST2HTML)),) $(VV)if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi; $(V)$(RST2HTML) $(RST2HTMLOPTS) $< $@ $(VV)$(RSTDEPENDS) else @$(ECHO) "--> Not building HTML due to missing rst2html" endif # Build *.pdf from *.rst %.pdf: %.rst @$(ECHO) " PDF " $< ifneq ($(strip $(RST2PDF)),) $(V)$(RST2PDF) $(RST2PDFOPTS) -o $@ $< else @$(ECHO) "--> Not building PDF due to missing rst2pdf" endif # Format a manpage into plain text define MANIFY @$(ECHO) " MAN " $(1) -\> $(2) $(V)man ./$(1) | col -b > $(2) endef # Rule to build a Windows resource object from the source RC file # Includes substitution of version strings, if needed comma := , RCVERSION = $(subst .,$(comma),$(firstword $(subst -, ,$(VERSION))).0) $(OBJDIR)/%.o: %.rc @$(ECHO) " RES " $(RELDIR)$< $(V)sed -e "s/\$$VERSION/$(VERSION)/" \ -e "s/FILEVERSION.*/FILEVERSION $(RCVERSION)/" \ -e "s/PRODUCTVERSION.*/PRODUCTVERSION $(RCVERSION)/" $< | \ $(RES) -I$(dir $<) -O coff -o $@ apcupsd-3.14.14/autoconf/variables.mak.in000066400000000000000000000051301274230402600202070ustar00rootroot00000000000000# General rules for Makefile(s) subsystem. # In this file we will put everything that need to be # shared betweek all the Makefile(s). # This file must be included at the beginning of every Makefile # # Copyright (C) 1999-2002 Riccardo Facchetti # # package version PACKAGE = apcupsd DISTNAME = @DISTNAME@ DISTVER = @DISTVER@ VERSION = @VERSION@ # # programs needed by compilation CP = @CP@ MV = @MV@ ECHO = @ECHO@ RM = @RM@ RMF = $(RM) -rf LN = @LN@ SED = @SED@ MAKE = @MAKE@ SHELL = @SHELL@ RANLIB = @RANLIB@ AR = @AR@ STRP = @STRP@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ MKINSTALLDIRS = @MKINSTALLDIRS@ CHKCONFIG = /sbin/chkconfig RST2HTML := @RST2HTML@ RST2PDF := @RST2PDF@ # Files and directories (paths) prefix = @prefix@ exec_prefix = @exec_prefix@ sysconfdir = @sysconfdir@ cgibin = @CGIBIN@ VPATH = /usr/lib:/usr/local/lib srcdir = @srcdir@ abstopdir = @ABSSRCDIR@ sbindir = @sbindir@ piddir = @PIDDIR@ mandir=@mandir@ bindir = @bindir@ datadir = @datadir@ HALPOLICYDIR = @HALPOLICYDIR@ DISTDIR = @DISTDIR@ PWRFAILDIR = @PWRFAILDIR@ LOCKDIR = @LOCKDIR@ CROSSTOOLS = @CROSSTOOLS@ DEPKGS = @DEPKGS@ # Compilation macros. CC = @CC@ CXX = @CXX@ -x c++ OBJC = $(CC) -x objective-c++ NIB = ibtool LD = @LD@ RES = @WINDRES@ DEFS = @EXTRADEFS@ $(LOCALDEFS) EXE = @EXEEXT@ # Libraries APCLIBS = $(topdir)/src/lib/libapc.a $(if $(WIN32),$(topdir)/src/win32/compat/libwin32compat.a) APCDRVLIBS = @APCDRVLIBS@ DRVLIBS = @PTHREAD_LFLAGS@ @DRVLIBS@ X_LIBS = @X_LIBS@ X_EXTRA_LIBS = @X_EXTRA_LIBS@ CPPFLAGS = @CPPFLAGS@ -I$(topdir)/include $(EXTRAINCS) CFLAGS = $(CPPFLAGS) @CFLAGS@ @PTHREAD_CFLAGS@ CXXFLAGS = $(CPPFLAGS) @CXXFLAGS@ @PTHREAD_CFLAGS@ OBJCFLAGS = $(CPPFLAGS) $(CFLAGS) LDFLAGS = @LDFLAGS@ LIBS = @LIBS@ LIBGD = @GD_LIBS@ GAPCMON_CFLAGS = @GAPCMON_CFLAGS@ GAPCMON_LIBS = @GAPCMON_LIBS@ LIBEXTRAOBJ = @LIBEXTRAOBJ@ RST2HTMLOPTS = --field-name-limit=0 --generator --time --no-footnote-backlinks --record-dependencies=$(df).d RST2PDFOPTS = --no-footnote-backlinks --real-footnotes NIBFLAGS = BG = @BG@ # Driver and package enable flags SMARTDRV := @APCSMART_DRIVER@ DUMBDRV := @DUMB_DRIVER@ USBDRV := @USB_DRIVER@ NETDRV := @NET_DRIVER@ PCNETDRV := @PCNET_DRIVER@ MODBUSDRV := @MODBUS_DRIVER@ MODBUSUSB := @MODBUS_USB_DRIVER@ SNMPLTDRV := @SNMPLITE_DRIVER@ TESTDRV := @TEST_DRIVER@ USBTYPE := @USB_TYPE@ CGIDIR := @CGI@ USBHIDDIR := @LIBUSBHID@ GAPCMON := @GAPCMON@ APCAGENT := @APCAGENT@ WIN32 := @WIN32@ OBJDIR = .obj DEPDIR = .deps df = $(DEPDIR)/$(*F) DEVNULL := >/dev/null 2>&1 apcupsd-3.14.14/c000066400000000000000000000012711274230402600134710ustar00rootroot00000000000000/* Copyright (C) 2000-2005 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA. */ apcupsd-3.14.14/configure000077500000000000000000014136321274230402600152440ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.63. # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH if test "x$CONFIG_SHELL" = x; then if (eval ":") 2>/dev/null; then as_have_required=yes else as_have_required=no fi if test $as_have_required = yes && (eval ": (as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=\$LINENO as_lineno_2=\$LINENO test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } ") 2> /dev/null; then : else as_candidate_shells= as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. case $as_dir in /*) for as_base in sh bash ksh sh5; do as_candidate_shells="$as_candidate_shells $as_dir/$as_base" done;; esac done IFS=$as_save_IFS for as_shell in $as_candidate_shells $SHELL; do # Try only shells that exist, to save several forks. if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { ("$as_shell") 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : _ASEOF }; then CONFIG_SHELL=$as_shell as_have_required=yes if { "$as_shell" 2> /dev/null <<\_ASEOF if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi : (as_func_return () { (exit $1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = "$1" ); then : else exitcode=1 echo positional parameters were not saved. fi test $exitcode = 0) || { (exit 1); exit 1; } ( as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } _ASEOF }; then break fi fi done if test "x$CONFIG_SHELL" != x; then for as_var in BASH_ENV ENV do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test $as_have_required = no; then echo This script requires a shell more modern than all the echo shells that I found on your system. Please install a echo modern shell, or manually run the script under such a echo shell if you do have one. { (exit 1); exit 1; } fi fi fi (eval "as_func_return () { (exit \$1) } as_func_success () { as_func_return 0 } as_func_failure () { as_func_return 1 } as_func_ret_success () { return 0 } as_func_ret_failure () { return 1 } exitcode=0 if as_func_success; then : else exitcode=1 echo as_func_success failed. fi if as_func_failure; then exitcode=1 echo as_func_failure succeeded. fi if as_func_ret_success; then : else exitcode=1 echo as_func_ret_success failed. fi if as_func_ret_failure; then exitcode=1 echo as_func_ret_failure succeeded. fi if ( set x; as_func_ret_success y && test x = \"\$1\" ); then : else exitcode=1 echo positional parameters were not saved. fi test \$exitcode = 0") || { echo No shell found that supports shell functions. echo Please tell bug-autoconf@gnu.org about your system, echo including any error possibly output before this message. echo This can help us improve future autoconf versions. echo Configuration will now proceed without shell functions. } as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= ac_unique_file="Developers" ac_default_prefix=/opt/apcupsd ac_default_prefix=/usr # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS HOST UPSCABLE UPSTYPE NISPORT LOCKDIR PWRFAILDIR nologdir LOGDIR PIDDIR SERIALDEV DISTVER DISTNAME WIN32 DISTDIR EXTRAOBJ LIBEXTRAOBJ EXTRADEFS MKINSTALLDIRS SYSCONFDIR CGIBIN GD_LIBS CGI LD MAKE APCAGENT GAPCMON GAPCMON_LIBS GAPCMON_CFLAGS PKG_CONFIG NISIP LIBUSBHID LIBUSBH usbcfg MODBUS_DRIVER MODBUS_USB_DRIVER PCNET_DRIVER TEST_DRIVER SNMPLITE_DRIVER NET_DRIVER USB_TYPE USB_DRIVER DUMB_DRIVER APCSMART_DRIVER GDHEAD HALPOLICYDIR X_EXTRA_LIBS X_LIBS X_PRE_LIBS X_CFLAGS XMKMF EGREP GREP RST2PDF RST2HTML ac_ct_STRP STRP WINDRES MV AR SED LN ECHO CP RM RANLIB SCRIPTSHELL WALL APCUPSD_MAIL SHUTDOWN APCTEST SMTP APCACCESS PTHREAD_LFLAGS PTHREAD_CFLAGS APCDRVLIBS DRVLIBS DEBUG AWK INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM CPP ac_ct_CC CFLAGS CC OBJEXT EXEEXT ac_ct_CXX CPPFLAGS LDFLAGS CXXFLAGS CXX DEPKGS CROSSTOOLS BG host_os host_vendor host_cpu host build_os build_vendor build_cpu build FALSEPRG TRUEPRG DATE VERSION TOP_DIR topdir ABSSRCDIR target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking with_x enable_all with_halpolicydir with_libwrap enable_cgi enable_apcsmart enable_dumb with_generic_usb enable_usb enable_net enable_snmp enable_test enable_pcnet enable_modbus_usb enable_modbus with_nisip with_cgi_bin enable_gapcmon enable_apcagent with_distname enable_install_distdir with_nologin with_pid_dir with_log_dir with_lock_dir with_pwrfail_dir with_serial_dev with_dev with_nis_port with_upstype with_upscable ' ac_precious_vars='build_alias host_alias target_alias CXX CXXFLAGS LDFLAGS LIBS CPPFLAGS CCC CC CFLAGS CPP XMKMF PKG_CONFIG GAPCMON_CFLAGS GAPCMON_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid feature name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid package name: $ac_useropt" >&2 { (exit 1); exit 1; }; } ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) { $as_echo "$as_me: error: unrecognized option: $ac_option Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && { $as_echo "$as_me: error: invalid variable name: $ac_envvar" >&2 { (exit 1); exit 1; }; } eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` { $as_echo "$as_me: error: missing argument to $ac_option" >&2 { (exit 1); exit 1; }; } fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) { $as_echo "$as_me: error: unrecognized options: $ac_unrecognized_opts" >&2 { (exit 1); exit 1; }; } ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac { $as_echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 { (exit 1); exit 1; }; } done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || { $as_echo "$as_me: error: working directory cannot be determined" >&2 { (exit 1); exit 1; }; } test "X$ac_ls_di" = "X$ac_pwd_ls_di" || { $as_echo "$as_me: error: pwd does not report name of working directory" >&2 { (exit 1); exit 1; }; } # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." { $as_echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 { (exit 1); exit 1; }; } fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || { $as_echo "$as_me: error: $ac_msg" >&2 { (exit 1); exit 1; }; } pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-all Enable all optional modules --enable-cgi Compile CGI programs --enable-apcsmart Compile APC SmartUPS serial driver (default) --disable-apcsmart No APC SmartUPS serial driver --enable-dumb Compile dumb UPS driver (default) --disable-dumb No dumb UPS driver --enable-usb Compile USB UPS code --disable-usb No USB UPS code (default) --enable-net Compile networking driver for slaves (default) --disable-net No network driver for slaves --enable-snmp Compile SNMP driver (default) --disable-snmp No SNMP driver --enable-test Compile TEST driver code --disable-test No TEST driver (default) --enable-pcnet Compile PCNET driver code (default) --disable-pcnet No PCNET driver --enable-modbus-usb Compile MODBUS/USB driver code --disable-modbus-usb No MODBUS/USB driver (default) --enable-modbus Compile MODBUS driver code (default) --disable-modbus No MODBUS driver --enable-gapcmon Build GTK/GUI front-end to apcupsd (default=no) --enable-apcagent Build menubar app for Mac OS X (default=no) --enable-install-distdir Install distribution Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-x use the X Window System --with-halpolicydir=DIR HAL policy directory (default is platform dependent) --with-libwrap=DIR Compile in libwrap (tcp_wrappers) support --with-generic-usb Force use of generic USB driver --with-nisip=IP-ADDRESS Specify the IP address to bind to (default=0.0.0.0) --with-cgi-bin=DIR Specify cgi-bin directory (default=/etc/apcupsd) --with-distname=NAME Specify DISTNAME --with-nologin=DIR Specify nologin file directory (default /etc) --with-pid-dir=DIR Specify PIDDIR directory (default is OS dependent) --with-log-dir=DIR Specify EVENTS and STATUS directory (default is OS dependent) --with-lock-dir=DIR Specify serial port lock directory (default is OS dependent) --with-pwrfail-dir=DIR Specify power failure file directory (default is OS dependent) --with-serial-dev=DEV Specify serial port device --with-dev=DEV Specify port or device --with-nis-port=PORT Specify NIS (CGI) port (default 3551 except Debian) --with-upstype=TYPE Specify the UPS type --with-upscable=CABLE Specify the UPS cable Some influential environment variables: CXX C++ compiler command CXXFLAGS C++ compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if you have headers in a nonstandard directory CC C compiler command CFLAGS C compiler flags CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System PKG_CONFIG path to pkg-config utility GAPCMON_CFLAGS C compiler flags for GAPCMON, overriding pkg-config GAPCMON_LIBS linker flags for GAPCMON, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.63 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.63. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; 2) ac_configure_args1="$ac_configure_args1 '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac done done $as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } $as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then ac_site_file1=$CONFIG_SITE elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test -r "$ac_site_file"; then { $as_echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special # files actually), so we avoid doing that. if test -f "$cache_file"; then { $as_echo "$as_me:$LINENO: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:$LINENO: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:$LINENO: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:$LINENO: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:$LINENO: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} { { $as_echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 $as_echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} { (exit 1); exit 1; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers include/apcconfig.h:autoconf/config.h.in" topdir=`pwd` ac_aux_dir= for ac_dir in ${topdir}/autoconf "$srcdir"/${topdir}/autoconf; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then { { $as_echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in ${topdir}/autoconf \"$srcdir\"/${topdir}/autoconf" >&5 $as_echo "$as_me: error: cannot find install-sh or install.sh in ${topdir}/autoconf \"$srcdir\"/${topdir}/autoconf" >&2;} { (exit 1); exit 1; }; } fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ABSSRCDIR=`pwd` cd .. TOP_DIR=`pwd` cd ${topdir} VERSION=`sed -n -e 's/^.*VERSION.*"\(.*\)"$/\1/p' ${srcdir}/include/version.h` DATE=`sed -n -e 's/^.* \t*ADATE.*"\(.*\)"$/\1/p' ${srcdir}/include/version.h` for ac_prog in true do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_TRUEPRG+set}" = set; then $as_echo_n "(cached) " >&6 else case $TRUEPRG in [\\/]* | ?:[\\/]*) ac_cv_path_TRUEPRG="$TRUEPRG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_TRUEPRG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi TRUEPRG=$ac_cv_path_TRUEPRG if test -n "$TRUEPRG"; then { $as_echo "$as_me:$LINENO: result: $TRUEPRG" >&5 $as_echo "$TRUEPRG" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$TRUEPRG" && break done test -n "$TRUEPRG" || TRUEPRG=":" for ac_prog in false do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_FALSEPRG+set}" = set; then $as_echo_n "(cached) " >&6 else case $FALSEPRG in [\\/]* | ?:[\\/]*) ac_cv_path_FALSEPRG="$FALSEPRG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_FALSEPRG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi FALSEPRG=$ac_cv_path_FALSEPRG if test -n "$FALSEPRG"; then { $as_echo "$as_me:$LINENO: result: $FALSEPRG" >&5 $as_echo "$FALSEPRG" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$FALSEPRG" && break done test -n "$FALSEPRG" || FALSEPRG=":" PATH=$PATH:/bin:/sbin:/etc:/usr/bin:/usr/bin/X11:/usr/sbin:/usr/local/bin:/usr/local/sbin export PATH # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || { { $as_echo "$as_me:$LINENO: error: cannot run $SHELL $ac_aux_dir/config.sub" >&5 $as_echo "$as_me: error: cannot run $SHELL $ac_aux_dir/config.sub" >&2;} { (exit 1); exit 1; }; } { $as_echo "$as_me:$LINENO: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if test "${ac_cv_build+set}" = set; then $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && { { $as_echo "$as_me:$LINENO: error: cannot guess build type; you must specify one" >&5 $as_echo "$as_me: error: cannot guess build type; you must specify one" >&2;} { (exit 1); exit 1; }; } ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&5 $as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $ac_build_alias failed" >&2;} { (exit 1); exit 1; }; } fi { $as_echo "$as_me:$LINENO: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical build" >&5 $as_echo "$as_me: error: invalid value of canonical build" >&2;} { (exit 1); exit 1; }; };; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:$LINENO: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if test "${ac_cv_host+set}" = set; then $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || { { $as_echo "$as_me:$LINENO: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&5 $as_echo "$as_me: error: $SHELL $ac_aux_dir/config.sub $host_alias failed" >&2;} { (exit 1); exit 1; }; } fi fi { $as_echo "$as_me:$LINENO: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) { { $as_echo "$as_me:$LINENO: error: invalid value of canonical host" >&5 $as_echo "$as_me: error: invalid value of canonical host" >&2;} { (exit 1); exit 1; }; };; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac if test "$cross_compiling" = "no" ; then for incdir in /usr/local/include ; do if test -d "$incdir" ; then CPPFLAGS="${CPPFLAGS} -I$incdir" fi done for libdir in /usr/local/lib64 /usr/local/lib ; do if test -d "$libdir" ; then LDFLAGS="${LDFLAGS} -L$libdir" fi done fi if test "$host_os" = "mingw32" ; then if test -z "$CROSSTOOLS" ; then CROSSTOOLS=${topdir}/../cross-tools fi if test -z "$DEPKGS"; then DEPKGS=${topdir}/../depkgs-win32 fi CPPFLAGS="-I${topdir}/src/win32/compat -I$DEPKGS/libroot/include -I$DEPKGS/libroot/include/pthread ${CPPFLAGS}" PATH=$CROSSTOOLS/mingw32/bin:$PATH LDFLAGS="-L$DEPKGS/libroot/lib ${LDFLAGS}" BG=-mwindows fi if test $HAVE_UNAME=yes -a x`uname -s` = xSunOS then if test x$sysconfdir = x'${prefix}/etc' ; then sysconfdir='/etc/opt/apcupsd' fi if test x$sbindir = x'${exec_prefix}/sbin' ; then sbindir='/etc/opt/apcupsd/sbin' fi CPPFLAGS="${CPPFLAGS} -I/usr/sfw/include" LDFLAGS="${LDFLAGS} -L/usr/sfw/lib" else if test x$sysconfdir = x'${prefix}/etc' ; then sysconfdir='/etc/apcupsd' fi if test x$sbindir = x'${exec_prefix}/sbin' ; then sbindir='/sbin' fi fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:$LINENO: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:$LINENO: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 { (ac_try="$ac_compiler --version >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler --version >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -v >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler -v >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -V >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler -V >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5 $as_echo_n "checking for C++ compiler default output file name... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { (ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi { $as_echo "$as_me:$LINENO: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } if test -z "$ac_file"; then $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: C++ compiler cannot create executables See \`config.log' for more details." >&5 $as_echo "$as_me: error: C++ compiler cannot create executables See \`config.log' for more details." >&2;} { (exit 77); exit 77; }; }; } fi ac_exeext=$ac_cv_exeext # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5 $as_echo_n "checking whether the C++ compiler works... " >&6; } # FIXME: These cross compiler hacks should be removed for Autoconf 3.0 # If not cross compiling, check that we can run a simple program. if test "$cross_compiling" != yes; then if { ac_try='./$ac_file' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&5 $as_echo "$as_me: error: cannot run C++ compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } fi fi fi { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } { $as_echo "$as_me:$LINENO: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } { $as_echo "$as_me:$LINENO: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&5 $as_echo "$as_me: error: cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } fi rm -f conftest$ac_cv_exeext { $as_echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT { $as_echo "$as_me:$LINENO: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&5 $as_echo "$as_me: error: cannot compute suffix of object files: cannot compile See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_compiler_gnu=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cxx_g=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 CXXFLAGS="" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cxx_g=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:$LINENO: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:$LINENO: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:$LINENO: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:$LINENO: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&5 $as_echo "$as_me: error: no acceptable C compiler found in \$PATH See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } # Provide some information about the compiler. $as_echo "$as_me:$LINENO: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 { (ac_try="$ac_compiler --version >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler --version >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -v >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler -v >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { (ac_try="$ac_compiler -V >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compiler -V >&5") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } { $as_echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_compiler_gnu=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_g=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 CFLAGS="" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_g=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_prog_cc_c89=$ac_arg else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:$LINENO: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:$LINENO: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then # Broken: success on invalid input. continue else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:$LINENO: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then # Broken: success on invalid input. continue else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&5 $as_echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in ./ | .// | /cC/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:$LINENO: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AWK+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:$LINENO: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:$LINENO: checking for library containing strerror" >&5 $as_echo_n "checking for library containing strerror... " >&6; } if test "${ac_cv_search_strerror+set}" = set; then $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strerror (); int main () { return strerror (); ; return 0; } _ACEOF for ac_lib in '' cposix; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_search_strerror=$ac_res else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_strerror+set}" = set; then break fi done if test "${ac_cv_search_strerror+set}" = set; then : else ac_cv_search_strerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_search_strerror" >&5 $as_echo "$ac_cv_search_strerror" >&6; } ac_res=$ac_cv_search_strerror if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi if test x$LD = x ; then LD="$CC" fi APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/libdrivers.a" PTHREAD_CFLAGS="" PTHREAD_LFLAGS="-lpthread" with_pthreads=yes cat >>confdefs.h <<\_ACEOF #define HAVE_PTHREADS 1 _ACEOF APCACCESS=apcaccess SMTP=smtp APCTEST=apctest for ac_prog in shutdown shutdown.bsd do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_SHUTDOWN+set}" = set; then $as_echo_n "(cached) " >&6 else case $SHUTDOWN in [\\/]* | ?:[\\/]*) ac_cv_path_SHUTDOWN="$SHUTDOWN" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_SHUTDOWN="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SHUTDOWN=$ac_cv_path_SHUTDOWN if test -n "$SHUTDOWN"; then { $as_echo "$as_me:$LINENO: result: $SHUTDOWN" >&5 $as_echo "$SHUTDOWN" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$SHUTDOWN" && break done if test "$SHUTDOWN" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool; need any one of: shutdown shutdown.bsd" >&5 $as_echo "$as_me: error: Missing required tool; need any one of: shutdown shutdown.bsd" >&2;} { (exit 1); exit 1; }; } fi for ac_prog in mail do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_APCUPSD_MAIL+set}" = set; then $as_echo_n "(cached) " >&6 else case $APCUPSD_MAIL in [\\/]* | ?:[\\/]*) ac_cv_path_APCUPSD_MAIL="$APCUPSD_MAIL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_APCUPSD_MAIL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi APCUPSD_MAIL=$ac_cv_path_APCUPSD_MAIL if test -n "$APCUPSD_MAIL"; then { $as_echo "$as_me:$LINENO: result: $APCUPSD_MAIL" >&5 $as_echo "$APCUPSD_MAIL" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$APCUPSD_MAIL" && break done test -n "$APCUPSD_MAIL" || APCUPSD_MAIL="no" if test "$APCUPSD_MAIL" = "no" then { $as_echo "$as_me:$LINENO: WARNING: mail program not found !" >&5 $as_echo "$as_me: WARNING: mail program not found !" >&2;} APCUPSD_MAIL=mail fi for ac_prog in wall do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_WALL+set}" = set; then $as_echo_n "(cached) " >&6 else case $WALL in [\\/]* | ?:[\\/]*) ac_cv_path_WALL="$WALL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_WALL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi WALL=$ac_cv_path_WALL if test -n "$WALL"; then { $as_echo "$as_me:$LINENO: result: $WALL" >&5 $as_echo "$WALL" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$WALL" && break done if test "$WALL" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool; need any one of: wall" >&5 $as_echo "$as_me: error: Missing required tool; need any one of: wall" >&2;} { (exit 1); exit 1; }; } fi for ac_prog in sh bash do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_SCRIPTSHELL+set}" = set; then $as_echo_n "(cached) " >&6 else case $SCRIPTSHELL in [\\/]* | ?:[\\/]*) ac_cv_path_SCRIPTSHELL="$SCRIPTSHELL" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_SCRIPTSHELL="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SCRIPTSHELL=$ac_cv_path_SCRIPTSHELL if test -n "$SCRIPTSHELL"; then { $as_echo "$as_me:$LINENO: result: $SCRIPTSHELL" >&5 $as_echo "$SCRIPTSHELL" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$SCRIPTSHELL" && break done if test "$SCRIPTSHELL" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool; need any one of: sh bash" >&5 $as_echo "$as_me: error: Missing required tool; need any one of: sh bash" >&2;} { (exit 1); exit 1; }; } fi { $as_echo "$as_me:$LINENO: checking for GNU make" >&5 $as_echo_n "checking for GNU make... " >&6; } if test "${_cv_gnu_make_command+set}" = set; then $as_echo_n "(cached) " >&6 else _cv_gnu_make_command='' ; for a in "$MAKE" make gmake gnumake ; do if test -z "$a" ; then continue ; fi ; if ( sh -c "$a --version" 2> /dev/null | grep GNU 2>&1 > /dev/null ) ; then _cv_gnu_make_command=$a ; break; fi done ; fi { $as_echo "$as_me:$LINENO: result: $_cv_gnu_make_command" >&5 $as_echo "$_cv_gnu_make_command" >&6; } ; MAKE=$_cv_gnu_make_command; if test -z "$_cv_gnu_make_command" ; then { { $as_echo "$as_me:$LINENO: error: Could not find GNU make" >&5 $as_echo "$as_me: error: Could not find GNU make" >&2;} { (exit 1); exit 1; }; } ; fi ; if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:$LINENO: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi if test "$RANLIB" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool: ranlib" >&5 $as_echo "$as_me: error: Missing required tool: ranlib" >&2;} { (exit 1); exit 1; }; } fi # Extract the first word of "rm", so it can be a program name with args. set dummy rm; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_RM+set}" = set; then $as_echo_n "(cached) " >&6 else case $RM in [\\/]* | ?:[\\/]*) ac_cv_path_RM="$RM" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_RM="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RM=$ac_cv_path_RM if test -n "$RM"; then { $as_echo "$as_me:$LINENO: result: $RM" >&5 $as_echo "$RM" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "$RM" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool: rm" >&5 $as_echo "$as_me: error: Missing required tool: rm" >&2;} { (exit 1); exit 1; }; } fi # Extract the first word of "cp", so it can be a program name with args. set dummy cp; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_CP+set}" = set; then $as_echo_n "(cached) " >&6 else case $CP in [\\/]* | ?:[\\/]*) ac_cv_path_CP="$CP" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_CP="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi CP=$ac_cv_path_CP if test -n "$CP"; then { $as_echo "$as_me:$LINENO: result: $CP" >&5 $as_echo "$CP" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "$CP" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool: cp" >&5 $as_echo "$as_me: error: Missing required tool: cp" >&2;} { (exit 1); exit 1; }; } fi # Extract the first word of "echo", so it can be a program name with args. set dummy echo; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_ECHO+set}" = set; then $as_echo_n "(cached) " >&6 else case $ECHO in [\\/]* | ?:[\\/]*) ac_cv_path_ECHO="$ECHO" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ECHO="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ECHO=$ac_cv_path_ECHO if test -n "$ECHO"; then { $as_echo "$as_me:$LINENO: result: $ECHO" >&5 $as_echo "$ECHO" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "$ECHO" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool: echo" >&5 $as_echo "$as_me: error: Missing required tool: echo" >&2;} { (exit 1); exit 1; }; } fi # Extract the first word of "ln", so it can be a program name with args. set dummy ln; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_LN+set}" = set; then $as_echo_n "(cached) " >&6 else case $LN in [\\/]* | ?:[\\/]*) ac_cv_path_LN="$LN" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_LN="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi LN=$ac_cv_path_LN if test -n "$LN"; then { $as_echo "$as_me:$LINENO: result: $LN" >&5 $as_echo "$LN" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "$LN" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool: ln" >&5 $as_echo "$as_me: error: Missing required tool: ln" >&2;} { (exit 1); exit 1; }; } fi # Extract the first word of "sed", so it can be a program name with args. set dummy sed; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_SED+set}" = set; then $as_echo_n "(cached) " >&6 else case $SED in [\\/]* | ?:[\\/]*) ac_cv_path_SED="$SED" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_SED="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi SED=$ac_cv_path_SED if test -n "$SED"; then { $as_echo "$as_me:$LINENO: result: $SED" >&5 $as_echo "$SED" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "$SED" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool: sed" >&5 $as_echo "$as_me: error: Missing required tool: sed" >&2;} { (exit 1); exit 1; }; } fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. set dummy ${ac_tool_prefix}ar; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_AR+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_AR="${ac_tool_prefix}ar" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:$LINENO: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_AR"; then ac_ct_AR=$AR # Extract the first word of "ar", so it can be a program name with args. set dummy ar; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_AR+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_AR="ar" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_AR" = x; then AR="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi else AR="$ac_cv_prog_AR" fi if test "$AR" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool: ar" >&5 $as_echo "$as_me: error: Missing required tool: ar" >&2;} { (exit 1); exit 1; }; } fi # Extract the first word of "mv", so it can be a program name with args. set dummy mv; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_MV+set}" = set; then $as_echo_n "(cached) " >&6 else case $MV in [\\/]* | ?:[\\/]*) ac_cv_path_MV="$MV" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_MV="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi MV=$ac_cv_path_MV if test -n "$MV"; then { $as_echo "$as_me:$LINENO: result: $MV" >&5 $as_echo "$MV" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "$MV" = "" ; then { { $as_echo "$as_me:$LINENO: error: Missing required tool: mv" >&5 $as_echo "$as_me: error: Missing required tool: mv" >&2;} { (exit 1); exit 1; }; } fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}windres", so it can be a program name with args. set dummy ${ac_tool_prefix}windres; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_WINDRES+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$WINDRES"; then ac_cv_prog_WINDRES="$WINDRES" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_WINDRES="${ac_tool_prefix}windres" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi WINDRES=$ac_cv_prog_WINDRES if test -n "$WINDRES"; then { $as_echo "$as_me:$LINENO: result: $WINDRES" >&5 $as_echo "$WINDRES" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_WINDRES"; then ac_ct_WINDRES=$WINDRES # Extract the first word of "windres", so it can be a program name with args. set dummy windres; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_WINDRES+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_WINDRES"; then ac_cv_prog_ac_ct_WINDRES="$ac_ct_WINDRES" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_WINDRES="windres" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_WINDRES=$ac_cv_prog_ac_ct_WINDRES if test -n "$ac_ct_WINDRES"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_WINDRES" >&5 $as_echo "$ac_ct_WINDRES" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_WINDRES" = x; then WINDRES="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac WINDRES=$ac_ct_WINDRES fi else WINDRES="$ac_cv_prog_WINDRES" fi if test -n "$ac_tool_prefix"; then for ac_prog in strip true do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_STRP+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$STRP"; then ac_cv_prog_STRP="$STRP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_STRP="$ac_tool_prefix$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRP=$ac_cv_prog_STRP if test -n "$STRP"; then { $as_echo "$as_me:$LINENO: result: $STRP" >&5 $as_echo "$STRP" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$STRP" && break done fi if test -z "$STRP"; then ac_ct_STRP=$STRP for ac_prog in strip true do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_STRP+set}" = set; then $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRP"; then ac_cv_prog_ac_ct_STRP="$ac_ct_STRP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_STRP="$ac_prog" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRP=$ac_cv_prog_ac_ct_STRP if test -n "$ac_ct_STRP"; then { $as_echo "$as_me:$LINENO: result: $ac_ct_STRP" >&5 $as_echo "$ac_ct_STRP" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_STRP" && break done if test "x$ac_ct_STRP" = x; then STRP="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRP=$ac_ct_STRP fi fi # Extract the first word of "rst2html", so it can be a program name with args. set dummy rst2html; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_RST2HTML+set}" = set; then $as_echo_n "(cached) " >&6 else case $RST2HTML in [\\/]* | ?:[\\/]*) ac_cv_path_RST2HTML="$RST2HTML" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_RST2HTML="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RST2HTML=$ac_cv_path_RST2HTML if test -n "$RST2HTML"; then { $as_echo "$as_me:$LINENO: result: $RST2HTML" >&5 $as_echo "$RST2HTML" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rst2html.py", so it can be a program name with args. set dummy rst2html.py; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_RST2HTML+set}" = set; then $as_echo_n "(cached) " >&6 else case $RST2HTML in [\\/]* | ?:[\\/]*) ac_cv_path_RST2HTML="$RST2HTML" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_RST2HTML="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RST2HTML=$ac_cv_path_RST2HTML if test -n "$RST2HTML"; then { $as_echo "$as_me:$LINENO: result: $RST2HTML" >&5 $as_echo "$RST2HTML" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "rst2pdf", so it can be a program name with args. set dummy rst2pdf; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_RST2PDF+set}" = set; then $as_echo_n "(cached) " >&6 else case $RST2PDF in [\\/]* | ?:[\\/]*) ac_cv_path_RST2PDF="$RST2PDF" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_RST2PDF="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi RST2PDF=$ac_cv_path_RST2PDF if test -n "$RST2PDF"; then { $as_echo "$as_me:$LINENO: result: $RST2PDF" >&5 $as_echo "$RST2PDF" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi # ------------------------------------------------------------------------- # If the user has not set --mandir, we default to /usr/share/man # ------------------------------------------------------------------------- if test x$mandir = x'${prefix}/man' ; then mandir=/usr/share/man fi for ac_func in abort calloc getpid \ rewind signal strerror strncmp \ strncpy vfprintf do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 $as_echo_n "checking for $ac_func... " >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then eval "$as_ac_var=yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } as_val=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else { { $as_echo "$as_me:$LINENO: error: cannot find required function." >&5 $as_echo "$as_me: error: cannot find required function." >&2;} { (exit 1); exit 1; }; } fi done for ac_func in snprintf vsnprintf strlcpy strlcat accept4 do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 $as_echo_n "checking for $ac_func... " >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then eval "$as_ac_var=yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } as_val=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "$host_os" != "mingw32" ; then for ac_func in fork ioctl kill select setsid tcgetattr do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 $as_echo_n "checking for $ac_func... " >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then eval "$as_ac_var=yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } as_val=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else { { $as_echo "$as_me:$LINENO: error: cannot find required function." >&5 $as_echo "$as_me: error: cannot find required function." >&2;} { (exit 1); exit 1; }; } fi done { $as_echo "$as_me:$LINENO: checking for syslog" >&5 $as_echo_n "checking for syslog... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { syslog(0, "%s", "test"); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { $as_echo "$as_me:$LINENO: checking for std_syslog in -lsocket" >&5 $as_echo_n "checking for std_syslog in -lsocket... " >&6; } if test "${ac_cv_lib_socket_std_syslog+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char std_syslog (); int main () { return std_syslog (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_socket_std_syslog=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_socket_std_syslog=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_std_syslog" >&5 $as_echo "$ac_cv_lib_socket_std_syslog" >&6; } if test "x$ac_cv_lib_socket_std_syslog" = x""yes; then cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" else { { $as_echo "$as_me:$LINENO: error: cannot find required function." >&5 $as_echo "$as_me: error: cannot find required function." >&2;} { (exit 1); exit 1; }; } fi cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { syslog(0, "%s", "test"); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:$LINENO: error: cannot find required function." >&5 $as_echo "$as_me: error: cannot find required function." >&2;} { (exit 1); exit 1; }; } fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: checking for library containing nanosleep" >&5 $as_echo_n "checking for library containing nanosleep... " >&6; } if test "${ac_cv_search_nanosleep+set}" = set; then $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char nanosleep (); int main () { return nanosleep (); ; return 0; } _ACEOF for ac_lib in '' rt posix4; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_search_nanosleep=$ac_res else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_nanosleep+set}" = set; then break fi done if test "${ac_cv_search_nanosleep+set}" = set; then : else ac_cv_search_nanosleep=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_search_nanosleep" >&5 $as_echo "$ac_cv_search_nanosleep" >&6; } ac_res=$ac_cv_search_nanosleep if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" cat >>confdefs.h <<\_ACEOF #define HAVE_NANOSLEEP 1 _ACEOF else LIBEXTRAOBJ="$LIBEXTRAOBJ nanosleep.c" fi for ac_func in strftime do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 $as_echo_n "checking for $ac_func... " >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then eval "$as_ac_var=yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } as_val=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else # strftime is in -lintl on SCO UNIX. { $as_echo "$as_me:$LINENO: checking for strftime in -lintl" >&5 $as_echo_n "checking for strftime in -lintl... " >&6; } if test "${ac_cv_lib_intl_strftime+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lintl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strftime (); int main () { return strftime (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_intl_strftime=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_intl_strftime=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_intl_strftime" >&5 $as_echo "$ac_cv_lib_intl_strftime" >&6; } if test "x$ac_cv_lib_intl_strftime" = x""yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_STRFTIME 1 _ACEOF LIBS="-lintl $LIBS" fi fi done # Under sysV68, socket and friends are provided by the C library. # -linet does not provide socket, but causes multiple definition # errors at link-time. It is thus better to only use the C library. # So don't add -linet to the link list unless it's necessary # # With Solaris socket and friends seem not to be in C library. # I hope that if socket is found, all the BSD friends are in the same library # # - RF # { $as_echo "$as_me:$LINENO: checking for library containing socket" >&5 $as_echo_n "checking for library containing socket... " >&6; } if test "${ac_cv_search_socket+set}" = set; then $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char socket (); int main () { return socket (); ; return 0; } _ACEOF for ac_lib in '' xnet socket inet; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_search_socket=$ac_res else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_socket+set}" = set; then break fi done if test "${ac_cv_search_socket+set}" = set; then : else ac_cv_search_socket=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_search_socket" >&5 $as_echo "$ac_cv_search_socket" >&6; } ac_res=$ac_cv_search_socket if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:$LINENO: checking for library containing gethostname" >&5 $as_echo_n "checking for library containing gethostname... " >&6; } if test "${ac_cv_search_gethostname+set}" = set; then $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostname (); int main () { return gethostname (); ; return 0; } _ACEOF for ac_lib in '' xnet socket inet; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_search_gethostname=$ac_res else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_gethostname+set}" = set; then break fi done if test "${ac_cv_search_gethostname+set}" = set; then : else ac_cv_search_gethostname=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_search_gethostname" >&5 $as_echo "$ac_cv_search_gethostname" >&6; } ac_res=$ac_cv_search_gethostname if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:$LINENO: checking for library containing gethostbyname" >&5 $as_echo_n "checking for library containing gethostbyname... " >&6; } if test "${ac_cv_search_gethostbyname+set}" = set; then $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF for ac_lib in '' nsl resolv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_search_gethostbyname=$ac_res else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_gethostbyname+set}" = set; then break fi done if test "${ac_cv_search_gethostbyname+set}" = set; then : else ac_cv_search_gethostbyname=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_search_gethostbyname" >&5 $as_echo "$ac_cv_search_gethostbyname" >&6; } ac_res=$ac_cv_search_gethostbyname if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:$LINENO: checking for library containing gethostbyname_r" >&5 $as_echo_n "checking for library containing gethostbyname_r... " >&6; } if test "${ac_cv_search_gethostbyname_r+set}" = set; then $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname_r (); int main () { return gethostbyname_r (); ; return 0; } _ACEOF for ac_lib in '' nsl resolv; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_search_gethostbyname_r=$ac_res else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_gethostbyname_r+set}" = set; then break fi done if test "${ac_cv_search_gethostbyname_r+set}" = set; then : else ac_cv_search_gethostbyname_r=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_search_gethostbyname_r" >&5 $as_echo "$ac_cv_search_gethostbyname_r" >&6; } ac_res=$ac_cv_search_gethostbyname_r if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi # The condition in this test copes with the presence of inet_addr in libc6. { $as_echo "$as_me:$LINENO: checking for library containing inet_addr" >&5 $as_echo_n "checking for library containing inet_addr... " >&6; } if test "${ac_cv_search_inet_addr+set}" = set; then $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_addr (); int main () { return inet_addr (); ; return 0; } _ACEOF for ac_lib in '' nsl; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_search_inet_addr=$ac_res else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext if test "${ac_cv_search_inet_addr+set}" = set; then break fi done if test "${ac_cv_search_inet_addr+set}" = set; then : else ac_cv_search_inet_addr=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_search_inet_addr" >&5 $as_echo "$ac_cv_search_inet_addr" >&6; } ac_res=$ac_cv_search_inet_addr if test "$ac_res" != no; then test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi { $as_echo "$as_me:$LINENO: checking for strchr" >&5 $as_echo_n "checking for strchr... " >&6; } if test "${ac_cv_func_strchr+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define strchr to an innocuous variant, in case declares strchr. For example, HP-UX 11i declares gettimeofday. */ #define strchr innocuous_strchr /* System header to define __stub macros and hopefully few prototypes, which can conflict with char strchr (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef strchr /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strchr (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_strchr || defined __stub___strchr choke me #endif int main () { return strchr (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_strchr=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_strchr=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_strchr" >&5 $as_echo "$ac_cv_func_strchr" >&6; } if test "x$ac_cv_func_strchr" = x""yes; then { $as_echo "$as_me:$LINENO: result: using libc's strchr" >&5 $as_echo "using libc's strchr" >&6; } else { $as_echo "$as_me:$LINENO: checking for strchr in -lcposix" >&5 $as_echo_n "checking for strchr in -lcposix... " >&6; } if test "${ac_cv_lib_cposix_strchr+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcposix $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strchr (); int main () { return strchr (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_cposix_strchr=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_cposix_strchr=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_cposix_strchr" >&5 $as_echo "$ac_cv_lib_cposix_strchr" >&6; } if test "x$ac_cv_lib_cposix_strchr" = x""yes; then EXTRADEFS="$EXTRADEFS -D_SYSV3" LIBS="$LIBS -lcposix" fi fi { $as_echo "$as_me:$LINENO: checking for strstr" >&5 $as_echo_n "checking for strstr... " >&6; } if test "${ac_cv_func_strstr+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define strstr to an innocuous variant, in case declares strstr. For example, HP-UX 11i declares gettimeofday. */ #define strstr innocuous_strstr /* System header to define __stub macros and hopefully few prototypes, which can conflict with char strstr (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef strstr /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strstr (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_strstr || defined __stub___strstr choke me #endif int main () { return strstr (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_strstr=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_strstr=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_strstr" >&5 $as_echo "$ac_cv_func_strstr" >&6; } if test "x$ac_cv_func_strstr" = x""yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_STRSTR /**/ _ACEOF else LIBEXTRAOBJ="$LIBEXTRAOBJ strstr.c" fi { $as_echo "$as_me:$LINENO: checking for strcasecmp" >&5 $as_echo_n "checking for strcasecmp... " >&6; } if test "${ac_cv_func_strcasecmp+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define strcasecmp to an innocuous variant, in case declares strcasecmp. For example, HP-UX 11i declares gettimeofday. */ #define strcasecmp innocuous_strcasecmp /* System header to define __stub macros and hopefully few prototypes, which can conflict with char strcasecmp (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef strcasecmp /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strcasecmp (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_strcasecmp || defined __stub___strcasecmp choke me #endif int main () { return strcasecmp (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_strcasecmp=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_strcasecmp=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_strcasecmp" >&5 $as_echo "$ac_cv_func_strcasecmp" >&6; } if test "x$ac_cv_func_strcasecmp" = x""yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_STRCASECMP /**/ _ACEOF else LIBEXTRAOBJ="$LIBEXTRAOBJ strcasecmp.c" fi { $as_echo "$as_me:$LINENO: checking for memmove" >&5 $as_echo_n "checking for memmove... " >&6; } if test "${ac_cv_func_memmove+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define memmove to an innocuous variant, in case declares memmove. For example, HP-UX 11i declares gettimeofday. */ #define memmove innocuous_memmove /* System header to define __stub macros and hopefully few prototypes, which can conflict with char memmove (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef memmove /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char memmove (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_memmove || defined __stub___memmove choke me #endif int main () { return memmove (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_memmove=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_memmove=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_memmove" >&5 $as_echo "$ac_cv_func_memmove" >&6; } if test "x$ac_cv_func_memmove" = x""yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_MEMMOVE /**/ _ACEOF else LIBEXTRAOBJ="$LIBEXTRAOBJ memmove.c" fi { $as_echo "$as_me:$LINENO: checking for getopt_long" >&5 $as_echo_n "checking for getopt_long... " >&6; } if test "${ac_cv_func_getopt_long+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define getopt_long to an innocuous variant, in case declares getopt_long. For example, HP-UX 11i declares gettimeofday. */ #define getopt_long innocuous_getopt_long /* System header to define __stub macros and hopefully few prototypes, which can conflict with char getopt_long (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef getopt_long /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char getopt_long (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_getopt_long || defined __stub___getopt_long choke me #endif int main () { return getopt_long (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_getopt_long=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_getopt_long=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_getopt_long" >&5 $as_echo "$ac_cv_func_getopt_long" >&6; } if test "x$ac_cv_func_getopt_long" = x""yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_GETOPTLONG /**/ _ACEOF else LIBEXTRAOBJ="$LIBEXTRAOBJ getopt.c getopt1.c" fi { $as_echo "$as_me:$LINENO: checking for inet_pton" >&5 $as_echo_n "checking for inet_pton... " >&6; } if test "${ac_cv_func_inet_pton+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define inet_pton to an innocuous variant, in case declares inet_pton. For example, HP-UX 11i declares gettimeofday. */ #define inet_pton innocuous_inet_pton /* System header to define __stub macros and hopefully few prototypes, which can conflict with char inet_pton (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef inet_pton /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char inet_pton (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_inet_pton || defined __stub___inet_pton choke me #endif int main () { return inet_pton (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_inet_pton=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_inet_pton=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_inet_pton" >&5 $as_echo "$ac_cv_func_inet_pton" >&6; } if test "x$ac_cv_func_inet_pton" = x""yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_INETPTON /**/ _ACEOF else LIBEXTRAOBJ="$LIBEXTRAOBJ inet_pton.c" fi { $as_echo "$as_me:$LINENO: checking for localtime_r" >&5 $as_echo_n "checking for localtime_r... " >&6; } if test "${ac_cv_func_localtime_r+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define localtime_r to an innocuous variant, in case declares localtime_r. For example, HP-UX 11i declares gettimeofday. */ #define localtime_r innocuous_localtime_r /* System header to define __stub macros and hopefully few prototypes, which can conflict with char localtime_r (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef localtime_r /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char localtime_r (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_localtime_r || defined __stub___localtime_r choke me #endif int main () { return localtime_r (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_localtime_r=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_localtime_r=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_localtime_r" >&5 $as_echo "$ac_cv_func_localtime_r" >&6; } if test "x$ac_cv_func_localtime_r" = x""yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_LOCALTIME_R /**/ _ACEOF else LIBEXTRAOBJ="$LIBEXTRAOBJ localtime_r.c" fi { $as_echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ac_count=`expr $ac_count + 1` if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then { { $as_echo "$as_me:$LINENO: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 $as_echo "$as_me: error: no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} { (exit 1); exit 1; }; } fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:$LINENO: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break ac_count=`expr $ac_count + 1` if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then { { $as_echo "$as_me:$LINENO: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 $as_echo "$as_me: error: no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} { (exit 1); exit 1; }; } fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:$LINENO: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_stdc=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then : else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_header_stdc=no fi rm -rf conftest.dSYM rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi fi fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then cat >>confdefs.h <<\_ACEOF #define STDC_HEADERS 1 _ACEOF fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 $as_echo_n "checking for $ac_header... " >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then eval "$as_ac_Header=yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ac_res=`eval 'as_val=${'$as_ac_Header'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } as_val=`eval 'as_val=${'$as_ac_Header'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in arpa/inet.h ctype.h errno.h fcntl.h \ limits.h netdb.h netinet/in.h signal.h \ stdarg.h stdio.h stdlib.h string.h strings.h sys/ioctl.h \ sys/socket.h sys/types.h syslog.h termios.h \ unistd.h do as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 $as_echo_n "checking for $ac_header... " >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 fi ac_res=`eval 'as_val=${'$as_ac_Header'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 $as_echo_n "checking $ac_header usability... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 $as_echo_n "checking $ac_header presence... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 $as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 $as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ;; esac { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 $as_echo_n "checking for $ac_header... " >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval 'as_val=${'$as_ac_Header'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi as_val=`eval 'as_val=${'$as_ac_Header'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF else { $as_echo "$as_me:$LINENO: WARNING: at least 1 header file is missing. This may not compile." >&5 $as_echo "$as_me: WARNING: at least 1 header file is missing. This may not compile." >&2;} fi done for ac_header in arpa/nameser.h do as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 $as_echo_n "checking for $ac_header... " >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 fi ac_res=`eval 'as_val=${'$as_ac_Header'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:$LINENO: checking $ac_header usability" >&5 $as_echo_n "checking $ac_header usability... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:$LINENO: checking $ac_header presence" >&5 $as_echo_n "checking $ac_header presence... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include <$ac_header> _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { $as_echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { $as_echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 $as_echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} { $as_echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 $as_echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} ;; esac { $as_echo "$as_me:$LINENO: checking for $ac_header" >&5 $as_echo_n "checking for $ac_header... " >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else eval "$as_ac_Header=\$ac_header_preproc" fi ac_res=`eval 'as_val=${'$as_ac_Header'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi as_val=`eval 'as_val=${'$as_ac_Header'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF cat >>confdefs.h <<\_ACEOF #define HAVE_NAMESER_H /**/ _ACEOF fi done { $as_echo "$as_me:$LINENO: checking whether stat file-mode macros are broken" >&5 $as_echo_n "checking whether stat file-mode macros are broken... " >&6; } if test "${ac_cv_header_stat_broken+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #if defined S_ISBLK && defined S_IFDIR extern char c1[S_ISBLK (S_IFDIR) ? -1 : 1]; #endif #if defined S_ISBLK && defined S_IFCHR extern char c2[S_ISBLK (S_IFCHR) ? -1 : 1]; #endif #if defined S_ISLNK && defined S_IFREG extern char c3[S_ISLNK (S_IFREG) ? -1 : 1]; #endif #if defined S_ISSOCK && defined S_IFREG extern char c4[S_ISSOCK (S_IFREG) ? -1 : 1]; #endif _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_stat_broken=no else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_stat_broken=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_stat_broken" >&5 $as_echo "$ac_cv_header_stat_broken" >&6; } if test $ac_cv_header_stat_broken = yes; then cat >>confdefs.h <<\_ACEOF #define STAT_MACROS_BROKEN 1 _ACEOF fi { $as_echo "$as_me:$LINENO: checking whether time.h and sys/time.h may both be included" >&5 $as_echo_n "checking whether time.h and sys/time.h may both be included... " >&6; } if test "${ac_cv_header_time+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #include int main () { if ((struct tm *) 0) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_time=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_time=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_time" >&5 $as_echo "$ac_cv_header_time" >&6; } if test $ac_cv_header_time = yes; then cat >>confdefs.h <<\_ACEOF #define TIME_WITH_SYS_TIME 1 _ACEOF fi { $as_echo "$as_me:$LINENO: checking for sys/wait.h that is POSIX.1 compatible" >&5 $as_echo_n "checking for sys/wait.h that is POSIX.1 compatible... " >&6; } if test "${ac_cv_header_sys_wait_h+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include #ifndef WEXITSTATUS # define WEXITSTATUS(stat_val) ((unsigned int) (stat_val) >> 8) #endif #ifndef WIFEXITED # define WIFEXITED(stat_val) (((stat_val) & 255) == 0) #endif int main () { int s; wait (&s); s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_header_sys_wait_h=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_header_sys_wait_h=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_sys_wait_h" >&5 $as_echo "$ac_cv_header_sys_wait_h" >&6; } if test $ac_cv_header_sys_wait_h = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_SYS_WAIT_H 1 _ACEOF fi { $as_echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5 $as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; } if test "${ac_cv_struct_tm+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { struct tm tm; int *p = &tm.tm_sec; return !p; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_struct_tm=time.h else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_struct_tm=sys/time.h fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_struct_tm" >&5 $as_echo "$ac_cv_struct_tm" >&6; } if test $ac_cv_struct_tm = sys/time.h; then cat >>confdefs.h <<\_ACEOF #define TM_IN_SYS_TIME 1 _ACEOF fi { $as_echo "$as_me:$LINENO: checking for struct tm.tm_zone" >&5 $as_echo_n "checking for struct tm.tm_zone... " >&6; } if test "${ac_cv_member_struct_tm_tm_zone+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include <$ac_cv_struct_tm> int main () { static struct tm ac_aggr; if (ac_aggr.tm_zone) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_tm_tm_zone=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include <$ac_cv_struct_tm> int main () { static struct tm ac_aggr; if (sizeof ac_aggr.tm_zone) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_member_struct_tm_tm_zone=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_member_struct_tm_tm_zone=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_member_struct_tm_tm_zone" >&5 $as_echo "$ac_cv_member_struct_tm_tm_zone" >&6; } if test "x$ac_cv_member_struct_tm_tm_zone" = x""yes; then cat >>confdefs.h <<_ACEOF #define HAVE_STRUCT_TM_TM_ZONE 1 _ACEOF fi if test "$ac_cv_member_struct_tm_tm_zone" = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_TM_ZONE 1 _ACEOF else { $as_echo "$as_me:$LINENO: checking whether tzname is declared" >&5 $as_echo_n "checking whether tzname is declared... " >&6; } if test "${ac_cv_have_decl_tzname+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { #ifndef tzname (void) tzname; #endif ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_have_decl_tzname=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_have_decl_tzname=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_have_decl_tzname" >&5 $as_echo "$ac_cv_have_decl_tzname" >&6; } if test "x$ac_cv_have_decl_tzname" = x""yes; then cat >>confdefs.h <<_ACEOF #define HAVE_DECL_TZNAME 1 _ACEOF else cat >>confdefs.h <<_ACEOF #define HAVE_DECL_TZNAME 0 _ACEOF fi { $as_echo "$as_me:$LINENO: checking for tzname" >&5 $as_echo_n "checking for tzname... " >&6; } if test "${ac_cv_var_tzname+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #if !HAVE_DECL_TZNAME extern char *tzname[]; #endif int main () { return tzname[0][0]; ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_var_tzname=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_var_tzname=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_var_tzname" >&5 $as_echo "$ac_cv_var_tzname" >&6; } if test $ac_cv_var_tzname = yes; then cat >>confdefs.h <<\_ACEOF #define HAVE_TZNAME 1 _ACEOF fi fi { $as_echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if test "${ac_cv_type_uid_t+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then cat >>confdefs.h <<\_ACEOF #define uid_t int _ACEOF cat >>confdefs.h <<\_ACEOF #define gid_t int _ACEOF fi { $as_echo "$as_me:$LINENO: checking type of array argument to getgroups" >&5 $as_echo_n "checking type of array argument to getgroups... " >&6; } if test "${ac_cv_type_getgroups+set}" = set; then $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then ac_cv_type_getgroups=cross else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Thanks to Mike Rendell for this test. */ $ac_includes_default #define NGID 256 #undef MAX #define MAX(x, y) ((x) > (y) ? (x) : (y)) int main () { gid_t gidset[NGID]; int i, n; union { gid_t gval; long int lval; } val; val.lval = -1; for (i = 0; i < NGID; i++) gidset[i] = val.gval; n = getgroups (sizeof (gidset) / MAX (sizeof (int), sizeof (gid_t)) - 1, gidset); /* Exit non-zero if getgroups seems to require an array of ints. This happens when gid_t is short int but getgroups modifies an array of ints. */ return n > 0 && gidset[n] != val.gval; } _ACEOF rm -f conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { ac_try='./conftest$ac_exeext' { (case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then ac_cv_type_getgroups=gid_t else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ( exit $ac_status ) ac_cv_type_getgroups=int fi rm -rf conftest.dSYM rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext fi if test $ac_cv_type_getgroups = cross; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "getgroups.*int.*gid_t" >/dev/null 2>&1; then ac_cv_type_getgroups=gid_t else ac_cv_type_getgroups=int fi rm -f conftest* fi fi { $as_echo "$as_me:$LINENO: result: $ac_cv_type_getgroups" >&5 $as_echo "$ac_cv_type_getgroups" >&6; } cat >>confdefs.h <<_ACEOF #define GETGROUPS_T $ac_cv_type_getgroups _ACEOF { $as_echo "$as_me:$LINENO: checking for mode_t" >&5 $as_echo_n "checking for mode_t... " >&6; } if test "${ac_cv_type_mode_t+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_type_mode_t=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if (sizeof (mode_t)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if (sizeof ((mode_t))) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_mode_t=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_type_mode_t" >&5 $as_echo "$ac_cv_type_mode_t" >&6; } if test "x$ac_cv_type_mode_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define mode_t int _ACEOF fi { $as_echo "$as_me:$LINENO: checking for off_t" >&5 $as_echo_n "checking for off_t... " >&6; } if test "${ac_cv_type_off_t+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_type_off_t=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if (sizeof (off_t)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if (sizeof ((off_t))) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_off_t=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_type_off_t" >&5 $as_echo "$ac_cv_type_off_t" >&6; } if test "x$ac_cv_type_off_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define off_t long int _ACEOF fi { $as_echo "$as_me:$LINENO: checking for pid_t" >&5 $as_echo_n "checking for pid_t... " >&6; } if test "${ac_cv_type_pid_t+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_type_pid_t=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if (sizeof (pid_t)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if (sizeof ((pid_t))) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_pid_t=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_type_pid_t" >&5 $as_echo "$ac_cv_type_pid_t" >&6; } if test "x$ac_cv_type_pid_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi { $as_echo "$as_me:$LINENO: checking return type of signal handlers" >&5 $as_echo_n "checking return type of signal handlers... " >&6; } if test "${ac_cv_type_signal+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int main () { return *(signal (0, 0)) (0) == 1; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_type_signal=int else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_signal=void fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_type_signal" >&5 $as_echo "$ac_cv_type_signal" >&6; } cat >>confdefs.h <<_ACEOF #define RETSIGTYPE $ac_cv_type_signal _ACEOF { $as_echo "$as_me:$LINENO: checking for size_t" >&5 $as_echo_n "checking for size_t... " >&6; } if test "${ac_cv_type_size_t+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_type_size_t=no cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if (sizeof (size_t)) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default int main () { if (sizeof ((size_t))) return 0; ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_type_size_t=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 $as_echo "$ac_cv_type_size_t" >&6; } if test "x$ac_cv_type_size_t" = x""yes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi { $as_echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5 $as_echo_n "checking for uid_t in sys/types.h... " >&6; } if test "${ac_cv_type_uid_t+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "uid_t" >/dev/null 2>&1; then ac_cv_type_uid_t=yes else ac_cv_type_uid_t=no fi rm -f conftest* fi { $as_echo "$as_me:$LINENO: result: $ac_cv_type_uid_t" >&5 $as_echo "$ac_cv_type_uid_t" >&6; } if test $ac_cv_type_uid_t = no; then cat >>confdefs.h <<\_ACEOF #define uid_t int _ACEOF cat >>confdefs.h <<\_ACEOF #define gid_t int _ACEOF fi { $as_echo "$as_me:$LINENO: checking for socklen_t" >&5 $as_echo_n "checking for socklen_t... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include socklen_t x; int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include #include int accept (int, struct sockaddr *, size_t *); int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then { $as_echo "$as_me:$LINENO: result: size_t" >&5 $as_echo "size_t" >&6; } cat >>confdefs.h <<\_ACEOF #define socklen_t size_t _ACEOF else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { $as_echo "$as_me:$LINENO: result: int" >&5 $as_echo "int" >&6; } cat >>confdefs.h <<\_ACEOF #define socklen_t int _ACEOF fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:$LINENO: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) { { $as_echo "$as_me:$LINENO: error: cannot use X directory names containing '" >&5 $as_echo "$as_me: error: cannot use X directory names containing '" >&2;} { (exit 1); exit 1; }; };; #( *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then # We can compile using X headers with no special include directory. ac_x_includes= else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:$LINENO: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:$LINENO: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. cat >>confdefs.h <<\_ACEOF #define X_DISPLAY_MISSING 1 _ACEOF X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" # For Solaris; some versions of Sun CC require a space after -R and # others require no space. Words are not sufficient . . . . { $as_echo "$as_me:$LINENO: checking whether -R must be followed by a space" >&5 $as_echo_n "checking whether -R must be followed by a space... " >&6; } ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" ac_xsave_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } X_LIBS="$X_LIBS -R$x_libraries" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 LIBS="$ac_xsave_LIBS -R $x_libraries" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } X_LIBS="$X_LIBS -R $x_libraries" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { $as_echo "$as_me:$LINENO: result: neither works" >&5 $as_echo "neither works" >&6; } fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext ac_c_werror_flag=$ac_xsave_c_werror_flag LIBS=$ac_xsave_LIBS fi # Check for system-dependent libraries X programs must link with. # Do this before checking for the system-independent R6 libraries # (-lICE), since we may need -lsocket or whatever for X linking. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn Johnson says this is needed for Ultrix, if the X # libraries were built with DECnet support. And Karl Berry says # the Alpha needs dnet_stub (dnet does not exist). ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XOpenDisplay (); int main () { return XOpenDisplay (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_dnet_dnet_ntoa=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dnet_dnet_ntoa=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:$LINENO: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet_stub $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_dnet_stub_dnet_ntoa=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_dnet_stub_dnet_ntoa=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi fi fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_xsave_LIBS" # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) # needs -lnsl. # The nsl library prevents programs from opening the X display # on Irix 5.2, according to T.E. Dickey. # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. { $as_echo "$as_me:$LINENO: checking for gethostbyname" >&5 $as_echo_n "checking for gethostbyname... " >&6; } if test "${ac_cv_func_gethostbyname+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define gethostbyname to an innocuous variant, in case declares gethostbyname. For example, HP-UX 11i declares gettimeofday. */ #define gethostbyname innocuous_gethostbyname /* System header to define __stub macros and hopefully few prototypes, which can conflict with char gethostbyname (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef gethostbyname /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_gethostbyname || defined __stub___gethostbyname choke me #endif int main () { return gethostbyname (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_gethostbyname=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_gethostbyname=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname" >&5 $as_echo "$ac_cv_func_gethostbyname" >&6; } if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_nsl_gethostbyname=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_nsl_gethostbyname=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:$LINENO: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_bsd_gethostbyname=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_bsd_gethostbyname=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary # on later versions), says Simon Leinen: it contains gethostby* # variants that don't use the name server (or something). -lsocket # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. { $as_echo "$as_me:$LINENO: checking for connect" >&5 $as_echo_n "checking for connect... " >&6; } if test "${ac_cv_func_connect+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define connect to an innocuous variant, in case declares connect. For example, HP-UX 11i declares gettimeofday. */ #define connect innocuous_connect /* System header to define __stub macros and hopefully few prototypes, which can conflict with char connect (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef connect /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_connect || defined __stub___connect choke me #endif int main () { return connect (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_connect=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_connect=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_connect" >&5 $as_echo "$ac_cv_func_connect" >&6; } if test $ac_cv_func_connect = no; then { $as_echo "$as_me:$LINENO: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if test "${ac_cv_lib_socket_connect+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_socket_connect=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_socket_connect=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = x""yes; then X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi fi # Guillermo Gomez says -lposix is necessary on A/UX. { $as_echo "$as_me:$LINENO: checking for remove" >&5 $as_echo_n "checking for remove... " >&6; } if test "${ac_cv_func_remove+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define remove to an innocuous variant, in case declares remove. For example, HP-UX 11i declares gettimeofday. */ #define remove innocuous_remove /* System header to define __stub macros and hopefully few prototypes, which can conflict with char remove (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef remove /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_remove || defined __stub___remove choke me #endif int main () { return remove (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_remove=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_remove=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_remove" >&5 $as_echo "$ac_cv_func_remove" >&6; } if test $ac_cv_func_remove = no; then { $as_echo "$as_me:$LINENO: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } if test "${ac_cv_lib_posix_remove+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lposix $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); int main () { return remove (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_posix_remove=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_posix_remove=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } if test "x$ac_cv_lib_posix_remove" = x""yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. { $as_echo "$as_me:$LINENO: checking for shmat" >&5 $as_echo_n "checking for shmat... " >&6; } if test "${ac_cv_func_shmat+set}" = set; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define shmat to an innocuous variant, in case declares shmat. For example, HP-UX 11i declares gettimeofday. */ #define shmat innocuous_shmat /* System header to define __stub macros and hopefully few prototypes, which can conflict with char shmat (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef shmat /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_shmat || defined __stub___shmat choke me #endif int main () { return shmat (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_func_shmat=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_func_shmat=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:$LINENO: result: $ac_cv_func_shmat" >&5 $as_echo "$ac_cv_func_shmat" >&6; } if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:$LINENO: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } if test "${ac_cv_lib_ipc_shmat+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lipc $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); int main () { return shmat (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_ipc_shmat=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_ipc_shmat=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } if test "x$ac_cv_lib_ipc_shmat" = x""yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS=$LDFLAGS test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # John Interrante, Karl Berry { $as_echo "$as_me:$LINENO: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char IceConnectionNumber (); int main () { return IceConnectionNumber (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_ICE_IceConnectionNumber=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_ICE_IceConnectionNumber=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi LDFLAGS=$ac_save_LDFLAGS fi { $as_echo "$as_me:$LINENO: checking whether #! works in shell scripts" >&5 $as_echo_n "checking whether #! works in shell scripts... " >&6; } if test "${ac_cv_sys_interpreter+set}" = set; then $as_echo_n "(cached) " >&6 else echo '#! /bin/cat exit 69 ' >conftest chmod u+x conftest (SHELL=/bin/sh; export SHELL; ./conftest >/dev/null 2>&1) if test $? -ne 69; then ac_cv_sys_interpreter=yes else ac_cv_sys_interpreter=no fi rm -f conftest fi { $as_echo "$as_me:$LINENO: result: $ac_cv_sys_interpreter" >&5 $as_echo "$ac_cv_sys_interpreter" >&6; } interpval=$ac_cv_sys_interpreter case $host in *-*-sunos*) cat >>confdefs.h <<\_ACEOF #define HAVE_SUN_OS /**/ _ACEOF ;; *-*-solaris*) cat >>confdefs.h <<\_ACEOF #define HAVE_SUN_OS /**/ _ACEOF ;; *-*-osf*) cat >>confdefs.h <<\_ACEOF #define HAVE_OSF1_OS /**/ _ACEOF ;; *-*-aix*) cat >>confdefs.h <<\_ACEOF #define HAVE_AIX_OS /**/ _ACEOF ;; *-*-hpux*) cat >>confdefs.h <<\_ACEOF #define HAVE_HPUX_OS /**/ _ACEOF ;; *-*-linux*) cat >>confdefs.h <<\_ACEOF #define HAVE_LINUX_OS /**/ _ACEOF ;; *-*-freebsd*) cat >>confdefs.h <<\_ACEOF #define HAVE_FREEBSD_OS /**/ _ACEOF ;; *-*-netbsd*) cat >>confdefs.h <<\_ACEOF #define HAVE_NETBSD_OS /**/ _ACEOF ;; *-*-openbsd*) cat >>confdefs.h <<\_ACEOF #define HAVE_OPENBSD_OS /**/ _ACEOF ;; *-*-bsdi*) cat >>confdefs.h <<\_ACEOF #define HAVE_BSDI_OS /**/ _ACEOF ;; *-*-irix*) cat >>confdefs.h <<\_ACEOF #define HAVE_SGI_OS /**/ _ACEOF ;; *-*-darwin*) cat >>confdefs.h <<\_ACEOF #define HAVE_DARWIN_OS /**/ _ACEOF ;; *-*-nto*) cat >>confdefs.h <<\_ACEOF #define HAVE_QNX_OS /**/ _ACEOF ;; *-*-mingw*) cat >>confdefs.h <<\_ACEOF #define HAVE_MINGW /**/ _ACEOF ;; esac # Check whether --enable-all was given. if test "${enable_all+set}" = set; then enableval=$enable_all; if test "$enableval" = "yes" ; then enable_usb=yes enable_net=yes enable_snmp=yes enable_test=yes enable_pcnet=yes enable_modbus=yes enable_modbus_usb=yes enable_cgi=yes if test "$host_os" != "mingw32" ; then enable_gapcmon=yes fi fi fi case $host in *-*-linux*) HALPOLICYDIR="/usr/share/hal/fdi/policy/20thirdparty" ;; *) HALPOLICYDIR="" ;; esac # Check whether --with-halpolicydir was given. if test "${with_halpolicydir+set}" = set; then withval=$with_halpolicydir; HALPOLICYDIR=$withval fi if test "x$HALPOLICYDIR" != "x" ; then { $as_echo "$as_me:$LINENO: result: Using halpolicydir=$HALPOLICYDIR" >&5 $as_echo "Using halpolicydir=$HALPOLICYDIR" >&6; } else { $as_echo "$as_me:$LINENO: result: Will not install HAL policy file" >&5 $as_echo "Will not install HAL policy file" >&6; } fi #-------------------------------------------------------------------- # Check for TCP wrapper support, code taken from Bacula KES-7Nov03 #-------------------------------------------------------------------- # Check whether --with-libwrap was given. if test "${with_libwrap+set}" = set; then withval=$with_libwrap; if test "x$withval" != "xno" ; then saved_LIBS="$LIBS" LIBS="$saved_LIBS -lwrap" { $as_echo "$as_me:$LINENO: checking for libwrap" >&5 $as_echo_n "checking for libwrap... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int deny_severity = 0; int allow_severity = 0; struct request_info *req; int main () { hosts_access(req); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } cat >>confdefs.h <<\_ACEOF #define HAVE_LIBWRAP /**/ _ACEOF TCPW_MSG="yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 LIBS="$saved_LIBS -lwrap -lnsl" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int deny_severity = 0; int allow_severity = 0; struct request_info *req; int main () { hosts_access(req); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } cat >>confdefs.h <<\_ACEOF #define HAVE_LIBWRAP 1 _ACEOF TCPW_MSG="yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:$LINENO: error: *** libwrap missing" >&5 $as_echo "$as_me: error: *** libwrap missing" >&2;} { (exit 1); exit 1; }; } fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi fi ENABLE_CGI="no" CGI= GD_LIBS= SYS_GD_FOUND=no # Check whether --enable-cgi was given. if test "${enable_cgi+set}" = set; then enableval=$enable_cgi; if test "$enableval" = "yes" then ENABLE_CGI="yes" CGI=cgi { $as_echo "$as_me:$LINENO: checking for gdImagePng in -lgd" >&5 $as_echo_n "checking for gdImagePng in -lgd... " >&6; } if test "${ac_cv_lib_gd_gdImagePng+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgd $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gdImagePng (); int main () { return gdImagePng (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_gd_gdImagePng=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_gd_gdImagePng=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_gd_gdImagePng" >&5 $as_echo "$ac_cv_lib_gd_gdImagePng" >&6; } if test "x$ac_cv_lib_gd_gdImagePng" = x""yes; then { $as_echo "$as_me:$LINENO: result: using PNG file format." >&5 $as_echo "using PNG file format." >&6; } cat >>confdefs.h <<\_ACEOF #define SYS_IMGFMT_PNG /**/ _ACEOF GD_LIBS="-lgd" SYS_GD_FOUND=yes else $as_unset ac_cv_lib_gd_gdImagePng fi if test "${SYS_GD_FOUND}" = "no" then { $as_echo "$as_me:$LINENO: checking for gdImagePng in -lgd" >&5 $as_echo_n "checking for gdImagePng in -lgd... " >&6; } if test "${ac_cv_lib_gd_gdImagePng+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgd -lpng12 -lz $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gdImagePng (); int main () { return gdImagePng (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_gd_gdImagePng=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_gd_gdImagePng=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_gd_gdImagePng" >&5 $as_echo "$ac_cv_lib_gd_gdImagePng" >&6; } if test "x$ac_cv_lib_gd_gdImagePng" = x""yes; then { $as_echo "$as_me:$LINENO: result: using PNG file format." >&5 $as_echo "using PNG file format." >&6; } cat >>confdefs.h <<\_ACEOF #define SYS_IMGFMT_PNG /**/ _ACEOF GD_LIBS="-lgd -lpng12 -lz" SYS_GD_FOUND=yes fi fi if test "${SYS_GD_FOUND}" = "no" then { $as_echo "$as_me:$LINENO: checking for gdImageGif in -lgd" >&5 $as_echo_n "checking for gdImageGif in -lgd... " >&6; } if test "${ac_cv_lib_gd_gdImageGif+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lgd $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gdImageGif (); int main () { return gdImageGif (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_gd_gdImageGif=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_gd_gdImageGif=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_gd_gdImageGif" >&5 $as_echo "$ac_cv_lib_gd_gdImageGif" >&6; } if test "x$ac_cv_lib_gd_gdImageGif" = x""yes; then { $as_echo "$as_me:$LINENO: result: using GIF file format." >&5 $as_echo "using GIF file format." >&6; } cat >>confdefs.h <<\_ACEOF #define SYS_IMGFMT_GIF /**/ _ACEOF GD_LIBS="-lgd" SYS_GD_FOUND=yes fi fi if test "${SYS_GD_FOUND}" = "no" then { { $as_echo "$as_me:$LINENO: error: Your system lacks the GD library which is needed for compiling the apcupsd CGI programs. Please install libgd and re-run the ./configure script. Alternatively you can disable the CGI support." >&5 $as_echo "$as_me: error: Your system lacks the GD library which is needed for compiling the apcupsd CGI programs. Please install libgd and re-run the ./configure script. Alternatively you can disable the CGI support." >&2;} { (exit 1); exit 1; }; } fi if test "${ac_cv_header_gd_h+set}" = set; then { $as_echo "$as_me:$LINENO: checking for gd.h" >&5 $as_echo_n "checking for gd.h... " >&6; } if test "${ac_cv_header_gd_h+set}" = set; then $as_echo_n "(cached) " >&6 fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_gd_h" >&5 $as_echo "$ac_cv_header_gd_h" >&6; } else # Is the header compilable? { $as_echo "$as_me:$LINENO: checking gd.h usability" >&5 $as_echo_n "checking gd.h usability... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:$LINENO: checking gd.h presence" >&5 $as_echo_n "checking gd.h presence... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { $as_echo "$as_me:$LINENO: WARNING: gd.h: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: gd.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd.h: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: gd.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { $as_echo "$as_me:$LINENO: WARNING: gd.h: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: gd.h: present but cannot be compiled" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd.h: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: gd.h: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd.h: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: gd.h: see the Autoconf documentation" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd.h: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: gd.h: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd.h: proceeding with the preprocessor's result" >&5 $as_echo "$as_me: WARNING: gd.h: proceeding with the preprocessor's result" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd.h: in the future, the compiler will take precedence" >&5 $as_echo "$as_me: WARNING: gd.h: in the future, the compiler will take precedence" >&2;} ;; esac { $as_echo "$as_me:$LINENO: checking for gd.h" >&5 $as_echo_n "checking for gd.h... " >&6; } if test "${ac_cv_header_gd_h+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_header_gd_h=$ac_header_preproc fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_gd_h" >&5 $as_echo "$ac_cv_header_gd_h" >&6; } fi if test "x$ac_cv_header_gd_h" = x""yes; then GDHEAD= else if test "${ac_cv_header_gd_gd_h+set}" = set; then { $as_echo "$as_me:$LINENO: checking for gd/gd.h" >&5 $as_echo_n "checking for gd/gd.h... " >&6; } if test "${ac_cv_header_gd_gd_h+set}" = set; then $as_echo_n "(cached) " >&6 fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_gd_gd_h" >&5 $as_echo "$ac_cv_header_gd_gd_h" >&6; } else # Is the header compilable? { $as_echo "$as_me:$LINENO: checking gd/gd.h usability" >&5 $as_echo_n "checking gd/gd.h usability... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:$LINENO: checking gd/gd.h presence" >&5 $as_echo_n "checking gd/gd.h presence... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { $as_echo "$as_me:$LINENO: WARNING: gd/gd.h: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: gd/gd.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd/gd.h: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: gd/gd.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { $as_echo "$as_me:$LINENO: WARNING: gd/gd.h: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: gd/gd.h: present but cannot be compiled" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd/gd.h: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: gd/gd.h: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd/gd.h: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: gd/gd.h: see the Autoconf documentation" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd/gd.h: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: gd/gd.h: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd/gd.h: proceeding with the preprocessor's result" >&5 $as_echo "$as_me: WARNING: gd/gd.h: proceeding with the preprocessor's result" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd/gd.h: in the future, the compiler will take precedence" >&5 $as_echo "$as_me: WARNING: gd/gd.h: in the future, the compiler will take precedence" >&2;} ;; esac { $as_echo "$as_me:$LINENO: checking for gd/gd.h" >&5 $as_echo_n "checking for gd/gd.h... " >&6; } if test "${ac_cv_header_gd_gd_h+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_header_gd_gd_h=$ac_header_preproc fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_gd_gd_h" >&5 $as_echo "$ac_cv_header_gd_gd_h" >&6; } fi if test "x$ac_cv_header_gd_gd_h" = x""yes; then GDHEAD="gd/" else if test "${ac_cv_header_gd2_gd_h+set}" = set; then { $as_echo "$as_me:$LINENO: checking for gd2/gd.h" >&5 $as_echo_n "checking for gd2/gd.h... " >&6; } if test "${ac_cv_header_gd2_gd_h+set}" = set; then $as_echo_n "(cached) " >&6 fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_gd2_gd_h" >&5 $as_echo "$ac_cv_header_gd2_gd_h" >&6; } else # Is the header compilable? { $as_echo "$as_me:$LINENO: checking gd2/gd.h usability" >&5 $as_echo_n "checking gd2/gd.h usability... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ $ac_includes_default #include _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_header_compiler=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:$LINENO: checking gd2/gd.h presence" >&5 $as_echo_n "checking gd2/gd.h presence... " >&6; } cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include _ACEOF if { (ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then ac_header_preproc=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in yes:no: ) { $as_echo "$as_me:$LINENO: WARNING: gd2/gd.h: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: gd2/gd.h: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd2/gd.h: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: gd2/gd.h: proceeding with the compiler's result" >&2;} ac_header_preproc=yes ;; no:yes:* ) { $as_echo "$as_me:$LINENO: WARNING: gd2/gd.h: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: gd2/gd.h: present but cannot be compiled" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd2/gd.h: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: gd2/gd.h: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd2/gd.h: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: gd2/gd.h: see the Autoconf documentation" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd2/gd.h: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: gd2/gd.h: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd2/gd.h: proceeding with the preprocessor's result" >&5 $as_echo "$as_me: WARNING: gd2/gd.h: proceeding with the preprocessor's result" >&2;} { $as_echo "$as_me:$LINENO: WARNING: gd2/gd.h: in the future, the compiler will take precedence" >&5 $as_echo "$as_me: WARNING: gd2/gd.h: in the future, the compiler will take precedence" >&2;} ;; esac { $as_echo "$as_me:$LINENO: checking for gd2/gd.h" >&5 $as_echo_n "checking for gd2/gd.h... " >&6; } if test "${ac_cv_header_gd2_gd_h+set}" = set; then $as_echo_n "(cached) " >&6 else ac_cv_header_gd2_gd_h=$ac_header_preproc fi { $as_echo "$as_me:$LINENO: result: $ac_cv_header_gd2_gd_h" >&5 $as_echo "$ac_cv_header_gd2_gd_h" >&6; } fi if test "x$ac_cv_header_gd2_gd_h" = x""yes; then GDHEAD="gd2/" else { { $as_echo "$as_me:$LINENO: error: Found system GD library but no header file. Please find the file gd.h in your system include directories and report its location to apcupsd-users@lists.sourceforge.net" >&5 $as_echo "$as_me: error: Found system GD library but no header file. Please find the file gd.h in your system include directories and report its location to apcupsd-users@lists.sourceforge.net" >&2;} { (exit 1); exit 1; }; } fi fi fi fi fi # Check whether --enable-apcsmart was given. if test "${enable_apcsmart+set}" = set; then enableval=$enable_apcsmart; if test "$enableval" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_APCSMART_DRIVER /**/ _ACEOF APCSMART_DRIVER="apcsmart" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/apcsmart/libapcsmartdrv.a" fi else cat >>confdefs.h <<\_ACEOF #define HAVE_APCSMART_DRIVER 1 _ACEOF APCSMART_DRIVER="apcsmart" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/apcsmart/libapcsmartdrv.a" fi # Check whether --enable-dumb was given. if test "${enable_dumb+set}" = set; then enableval=$enable_dumb; if test "$enableval" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_DUMB_DRIVER /**/ _ACEOF DUMB_DRIVER="dumb" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/dumb/libdumbdrv.a" fi else cat >>confdefs.h <<\_ACEOF #define HAVE_DUMB_DRIVER 1 _ACEOF DUMB_DRIVER="dumb" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/dumb/libdumbdrv.a" fi GENERICUSB="no" # Check whether --with-generic-usb was given. if test "${with_generic_usb+set}" = set; then withval=$with_generic_usb; GENERICUSB="yes" fi # Check whether --enable-usb was given. if test "${enable_usb+set}" = set; then enableval=$enable_usb; if test "$enableval" = "yes" ; then if test $GENERICUSB = "yes" ; then usbhost=forcegeneric else usbhost=$host fi cat >>confdefs.h <<\_ACEOF #define HAVE_USB_DRIVER /**/ _ACEOF USB_DRIVER="usb" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/usb/libusbdrv.a" case $usbhost in *-*-linux*) USB_TYPE="linux" { $as_echo "$as_me:$LINENO: result: Using Linux USB driver." >&5 $as_echo "Using Linux USB driver." >&6; } ;; *) needlibusb=true USB_TYPE="generic" ;; esac DISPLAY_USB_DRIVER=$USB_TYPE-$USB_DRIVER fi fi # Check whether --enable-net was given. if test "${enable_net+set}" = set; then enableval=$enable_net; if test "$enableval" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_NET_DRIVER /**/ _ACEOF NET_DRIVER="net" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/net/libnetdrv.a" fi else cat >>confdefs.h <<\_ACEOF #define HAVE_NET_DRIVER 1 _ACEOF NET_DRIVER="net" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/net/libnetdrv.a" fi # Check whether --enable-snmp was given. if test "${enable_snmp+set}" = set; then enableval=$enable_snmp; if test "$enableval" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_SNMPLITE_DRIVER /**/ _ACEOF SNMPLITE_DRIVER="snmplite" DISPLAY_SNMP_DRIVER="snmp" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/snmplite/libsnmplitedrv.a" fi else cat >>confdefs.h <<\_ACEOF #define HAVE_SNMPLITE_DRIVER 1 _ACEOF SNMPLITE_DRIVER="snmplite" DISPLAY_SNMP_DRIVER="snmp" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/snmplite/libsnmplitedrv.a" fi # Check whether --enable-test was given. if test "${enable_test+set}" = set; then enableval=$enable_test; if test "$enableval" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_TEST_DRIVER /**/ _ACEOF TEST_DRIVER="test" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/test/libtestdrv.a" fi fi # Check whether --enable-pcnet was given. if test "${enable_pcnet+set}" = set; then enableval=$enable_pcnet; if test "$enableval" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_PCNET_DRIVER /**/ _ACEOF PCNET_DRIVER="pcnet" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/pcnet/libpcnetdrv.a" fi else cat >>confdefs.h <<\_ACEOF #define HAVE_PCNET_DRIVER 1 _ACEOF PCNET_DRIVER="pcnet" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/pcnet/libpcnetdrv.a" fi # Check whether --enable-modbus-usb was given. if test "${enable_modbus_usb+set}" = set; then enableval=$enable_modbus_usb; if test "$enableval" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_MODBUS_USB_DRIVER /**/ _ACEOF MODBUS_USB_DRIVER="modbus-usb" enable_modbus=yes needlibusb=true fi fi # Check whether --enable-modbus was given. if test "${enable_modbus+set}" = set; then enableval=$enable_modbus; if test "$enableval" = "yes" ; then cat >>confdefs.h <<\_ACEOF #define HAVE_MODBUS_DRIVER /**/ _ACEOF MODBUS_DRIVER="modbus" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/modbus/libmodbusdrv.a" fi else cat >>confdefs.h <<\_ACEOF #define HAVE_MODBUS_DRIVER 1 _ACEOF MODBUS_DRIVER="modbus" APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/drivers/modbus/libmodbusdrv.a" fi if test "$needlibusb" = "true" ; then case $host in *-*-mingw*) LIBUSBH=libusb-winusb-bridge.h DRVLIBS="$DRVLIBS -lsetupapi" { $as_echo "$as_me:$LINENO: result: Using generic winusb USB driver." >&5 $as_echo "Using generic winusb USB driver." >&6; } ;; *) # Extract the first word of "libusb-config", so it can be a program name with args. set dummy libusb-config; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_usbcfg+set}" = set; then $as_echo_n "(cached) " >&6 else case $usbcfg in [\\/]* | ?:[\\/]*) ac_cv_path_usbcfg="$usbcfg" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_usbcfg="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi usbcfg=$ac_cv_path_usbcfg if test -n "$usbcfg"; then { $as_echo "$as_me:$LINENO: result: $usbcfg" >&5 $as_echo "$usbcfg" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test x$usbcfg != x ; then LIBUSB=`$usbcfg --libs` LIBUSBH=`$usbcfg --prefix`/include/usb.h else { $as_echo "$as_me:$LINENO: checking for usb_init in -lusb" >&5 $as_echo_n "checking for usb_init in -lusb... " >&6; } if test "${ac_cv_lib_usb_usb_init+set}" = set; then $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lusb $DRVLIBS $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char usb_init (); int main () { return usb_init (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then ac_cv_lib_usb_usb_init=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_cv_lib_usb_usb_init=no fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:$LINENO: result: $ac_cv_lib_usb_usb_init" >&5 $as_echo "$ac_cv_lib_usb_usb_init" >&6; } if test "x$ac_cv_lib_usb_usb_init" = x""yes; then LIBUSB=-lusb LIBUSBH=usb.h else { { $as_echo "$as_me:$LINENO: error: Unable to find libusb" >&5 $as_echo "$as_me: error: Unable to find libusb" >&2;} { (exit 1); exit 1; }; } fi fi DRVLIBS="$DRVLIBS $LIBUSB" { $as_echo "$as_me:$LINENO: result: Using generic libusb USB driver." >&5 $as_echo "Using generic libusb USB driver." >&6; } ;; esac LIBUSBHID=libusbhid APCDRVLIBS="$APCDRVLIBS \$(topdir)/src/libusbhid/libusbhid.a" CPPFLAGS="$CPPFLAGS -I\$(topdir)/src/libusbhid" fi cat >>confdefs.h <<\_ACEOF #define HAVE_NISSERVER /**/ _ACEOF cat >>confdefs.h <<\_ACEOF #define HAVE_NISLIB /**/ _ACEOF NISSRV_ENABLED=yes NISIP="0.0.0.0" # Check whether --with-nisip was given. if test "${with_nisip+set}" = set; then withval=$with_nisip; NISIP="$withval"; fi CGIBIN="/etc/apcupsd" # Check whether --with-cgi-bin was given. if test "${with_cgi_bin+set}" = set; then withval=$with_cgi_bin; CGIBIN="$withval"; fi GAPCMON= GAPCMON_ENABLED=no if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PKG_CONFIG+set}" = set; then $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:$LINENO: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:$LINENO: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:$LINENO: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:$LINENO: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:$LINENO: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi # Check whether --enable-gapcmon was given. if test "${enable_gapcmon+set}" = set; then enableval=$enable_gapcmon; if test "$enableval" = "yes" ; then GAPCMON=gapcmon GAPCMON_ENABLED=yes pkg_failed=no { $as_echo "$as_me:$LINENO: checking for GAPCMON" >&5 $as_echo_n "checking for GAPCMON... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GAPCMON_CFLAGS"; then pkg_cv_GAPCMON_CFLAGS="$GAPCMON_CFLAGS" else if test -n "$PKG_CONFIG" && \ { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0\"") >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_GAPCMON_CFLAGS=`$PKG_CONFIG --cflags-only-I "gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GAPCMON_LIBS"; then pkg_cv_GAPCMON_LIBS="$GAPCMON_LIBS" else if test -n "$PKG_CONFIG" && \ { ($as_echo "$as_me:$LINENO: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0\"") >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0") 2>&5 ac_status=$? $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then pkg_cv_GAPCMON_LIBS=`$PKG_CONFIG --libs "gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GAPCMON_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0"` else GAPCMON_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0"` fi # Put the nasty error message in config.log where it belongs echo "$GAPCMON_PKG_ERRORS" >&5 { { $as_echo "$as_me:$LINENO: error: Package requirements (gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0) were not met: $GAPCMON_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables GAPCMON_CFLAGS and GAPCMON_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&5 $as_echo "$as_me: error: Package requirements (gtk+-2.0 >= 2.4.0 glib-2.0 gthread-2.0 gconf-2.0) were not met: $GAPCMON_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables GAPCMON_CFLAGS and GAPCMON_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " >&2;} { (exit 1); exit 1; }; } elif test $pkg_failed = untried; then { { $as_echo "$as_me:$LINENO: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { { $as_echo "$as_me:$LINENO: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables GAPCMON_CFLAGS and GAPCMON_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&5 $as_echo "$as_me: error: The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables GAPCMON_CFLAGS and GAPCMON_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." >&2;} { (exit 1); exit 1; }; }; } else GAPCMON_CFLAGS=$pkg_cv_GAPCMON_CFLAGS GAPCMON_LIBS=$pkg_cv_GAPCMON_LIBS { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } : fi GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DVERSION=\\\"$VERSION\\\"" fi fi APCAGENT= APCAGENT_ENABLED=no # Check whether --enable-apcagent was given. if test "${enable_apcagent+set}" = set; then enableval=$enable_apcagent; if test "$enableval" = "yes" ; then case $host in *-*-darwin*) APCAGENT=apcagent APCAGENT_ENABLED=yes ;; *) { { $as_echo "$as_me:$LINENO: error: apcagent can only be built on Mac OS X" >&5 $as_echo "$as_me: error: apcagent can only be built on Mac OS X" >&2;} { (exit 1); exit 1; }; } ;; esac fi else case $host in *-*-darwin*) APCAGENT=apcagent APCAGENT_ENABLED=yes ;; esac fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:$LINENO: checking how many arguments gethostbyname_r() takes" >&5 $as_echo_n "checking how many arguments gethostbyname_r() takes... " >&6; } if test "${ac_cv_func_which_gethostbyname_r+set}" = set; then $as_echo_n "(cached) " >&6 else ################################################################ ac_cv_func_which_gethostbyname_r=unknown # # ONE ARGUMENT (sanity check) # # This should fail, as there is no variant of gethostbyname_r() that takes # a single argument. If it actually compiles, then we can assume that # netdb.h is not declaring the function, and the compiler is thereby # assuming an implicit prototype. In which case, we're out of luck. # cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { char *name = "www.gnu.org"; (void)gethostbyname_r(name) /* ; */ ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_func_which_gethostbyname_r=no else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext # # SIX ARGUMENTS # (e.g. Linux) # if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { char *name = "www.gnu.org"; struct hostent ret, *retp; char buf[1024]; int buflen = 1024; int my_h_errno; (void)gethostbyname_r(name, &ret, buf, buflen, &retp, &my_h_errno) /* ; */ ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_func_which_gethostbyname_r=six else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi # # FIVE ARGUMENTS # (e.g. Solaris) # if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { char *name = "www.gnu.org"; struct hostent ret; char buf[1024]; int buflen = 1024; int my_h_errno; (void)gethostbyname_r(name, &ret, buf, buflen, &my_h_errno) /* ; */ ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_func_which_gethostbyname_r=five else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi # # THREE ARGUMENTS # (e.g. AIX, HP-UX, Tru64) # if test "$ac_cv_func_which_gethostbyname_r" = "unknown"; then cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ #include int main () { char *name = "www.gnu.org"; struct hostent ret; struct hostent_data data; (void)gethostbyname_r(name, &ret, &data) /* ; */ ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ac_cv_func_which_gethostbyname_r=three else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi ################################################################ fi case "$ac_cv_func_which_gethostbyname_r" in three) { $as_echo "$as_me:$LINENO: result: three" >&5 $as_echo "three" >&6; } cat >>confdefs.h <<\_ACEOF #define HAVE_FUNC_GETHOSTBYNAME_R_3 1 _ACEOF ;; five) { $as_echo "$as_me:$LINENO: result: five" >&5 $as_echo "five" >&6; } cat >>confdefs.h <<\_ACEOF #define HAVE_FUNC_GETHOSTBYNAME_R_5 1 _ACEOF ;; six) { $as_echo "$as_me:$LINENO: result: six" >&5 $as_echo "six" >&6; } cat >>confdefs.h <<\_ACEOF #define HAVE_FUNC_GETHOSTBYNAME_R_6 1 _ACEOF ;; no) { $as_echo "$as_me:$LINENO: result: cannot find function declaration in netdb.h" >&5 $as_echo "cannot find function declaration in netdb.h" >&6; } ;; unknown) { $as_echo "$as_me:$LINENO: result: can't tell" >&5 $as_echo "can't tell" >&6; } ;; *) { { $as_echo "$as_me:$LINENO: error: internal error" >&5 $as_echo "$as_me: error: internal error" >&2;} { (exit 1); exit 1; }; } ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu case "$ac_cv_func_which_gethostbyname_r" in three) cat >>confdefs.h <<\_ACEOF #define HAVE_FUNC_GETHOSTBYNAME_R_3 /**/ _ACEOF GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DHAVE_FUNC_GETHOSTBYNAME_R_3" ;; five) cat >>confdefs.h <<\_ACEOF #define HAVE_FUNC_GETHOSTBYNAME_R_5 /**/ _ACEOF GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DHAVE_FUNC_GETHOSTBYNAME_R_5" ;; six) cat >>confdefs.h <<\_ACEOF #define HAVE_FUNC_GETHOSTBYNAME_R_6 /**/ _ACEOF GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DHAVE_FUNC_GETHOSTBYNAME_R_6" ;; no) cat >>confdefs.h <<\_ACEOF #define HAVE_FUNC_GETHOSTBYNAME_R_0 /**/ _ACEOF GAPCMON_CFLAGS="$GAPCMON_CFLAGS -DHAVE_FUNC_GETHOSTBYNAME_R_0" ;; *) { { $as_echo "$as_me:$LINENO: error: gethostbyname_r is required" >&5 $as_echo "$as_me: error: gethostbyname_r is required" >&2;} { (exit 1); exit 1; }; } ;; esac if test -n "$GCC"; then # Starting with GCC 3.0, you must link C++ programs against either # libstdc++ (shared by default), or libsupc++ (always static). If # you care about binary portability between Linux distributions, # you need to either 1) build your own GCC with static C++ libraries # or 2) link using gcc and libsupc++. We choose the latter since # CUPS doesn't (currently) use any of the stdc++ library. # # Previous versions of GCC do not have the reliance on the stdc++ # or g++ libraries, so the extra supc++ library is not needed. { $as_echo "$as_me:$LINENO: checking if libsupc++ is required" >&5 $as_echo_n "checking if libsupc++ is required... " >&6; } SUPC="`$CXX -print-file-name=libsupc++.a 2>/dev/null`" case "$SUPC" in libsupc++.a*) # Library not found, so this is an older GCC... LD="$CXX" { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } ;; *) # This is gcc 3.x, and it knows of libsupc++, so we need it LIBS="$LIBS -lsupc++" LD="$CC" { $as_echo "$as_me:$LINENO: result: yes" >&5 $as_echo "yes" >&6; } # See if this system has a broken libsupc++ that requires # a workaround (FreeBSD 5.x, 6.x) case $host in *-*-freebsd*) { $as_echo "$as_me:$LINENO: checking if libsupc++ is missing __terminate_handler" >&5 $as_echo_n "checking if libsupc++ is missing __terminate_handler... " >&6; } nm -C --defined-only "$SUPC" 2>/dev/null | grep __terminate_handler > /dev/null if test $? -eq 0 ; then { $as_echo "$as_me:$LINENO: result: no" >&5 $as_echo "no" >&6; } else { $as_echo "$as_me:$LINENO: result: yes -- will attempt workaround" >&5 $as_echo "yes -- will attempt workaround" >&6; } LIBEXTRAOBJ="$LIBEXTRAOBJ libsupc++fix.cpp" fi ;; esac ;; esac fi { $as_echo "$as_me:$LINENO: checking whether C compiler accepts -fno-exceptions" >&5 $as_echo_n "checking whether C compiler accepts -fno-exceptions... " >&6; } if test "${ax_cv_check_cflags___fno_exceptions+set}" = set; then $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -fno-exceptions" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ax_cv_check_cflags___fno_exceptions=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ax_cv_check_cflags___fno_exceptions=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:$LINENO: result: $ax_cv_check_cflags___fno_exceptions" >&5 $as_echo "$ax_cv_check_cflags___fno_exceptions" >&6; } if test x"$ax_cv_check_cflags___fno_exceptions" = xyes; then CXXFLAGS="$CXXFLAGS -fno-exceptions" else : fi { $as_echo "$as_me:$LINENO: checking whether C compiler accepts -fno-rtti" >&5 $as_echo_n "checking whether C compiler accepts -fno-rtti... " >&6; } if test "${ax_cv_check_cflags___fno_rtti+set}" = set; then $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -fno-rtti" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ax_cv_check_cflags___fno_rtti=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ax_cv_check_cflags___fno_rtti=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:$LINENO: result: $ax_cv_check_cflags___fno_rtti" >&5 $as_echo "$ax_cv_check_cflags___fno_rtti" >&6; } if test x"$ax_cv_check_cflags___fno_rtti" = xyes; then CXXFLAGS="$CXXFLAGS -fno-rtti" else : fi { $as_echo "$as_me:$LINENO: checking whether C compiler accepts -Wall" >&5 $as_echo_n "checking whether C compiler accepts -Wall... " >&6; } if test "${ax_cv_check_cflags___Wall+set}" = set; then $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -Wall" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ax_cv_check_cflags___Wall=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ax_cv_check_cflags___Wall=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:$LINENO: result: $ax_cv_check_cflags___Wall" >&5 $as_echo "$ax_cv_check_cflags___Wall" >&6; } if test x"$ax_cv_check_cflags___Wall" = xyes; then CXXFLAGS="$CXXFLAGS -Wall" else : fi { $as_echo "$as_me:$LINENO: checking whether C compiler accepts -Wno-unused-result" >&5 $as_echo_n "checking whether C compiler accepts -Wno-unused-result... " >&6; } if test "${ax_cv_check_cflags___Wno_unused_result+set}" = set; then $as_echo_n "(cached) " >&6 else ax_check_save_flags=$CFLAGS CFLAGS="$CFLAGS -Wno-unused-result" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_compile") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then ax_cv_check_cflags___Wno_unused_result=yes else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ax_cv_check_cflags___Wno_unused_result=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS=$ax_check_save_flags fi { $as_echo "$as_me:$LINENO: result: $ax_cv_check_cflags___Wno_unused_result" >&5 $as_echo "$ax_cv_check_cflags___Wno_unused_result" >&6; } if test x"$ax_cv_check_cflags___Wno_unused_result" = xyes; then CXXFLAGS="$CXXFLAGS -Wno-unused-result" else : fi cat >>confdefs.h <<_ACEOF #define SYSCONFDIR "$sysconfdir" _ACEOF MKINSTALLDIRS= if test -n "$ac_aux_dir"; then MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" fi if test x$MKINSTALLDIRS = x ; then MKINSTALLDIRS="\$(topdir)/autoconf/mkinstalldirs" fi for ac_func in wait waitpid wait3 do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 $as_echo_n "checking for $ac_func... " >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then eval "$as_ac_var=yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } as_val=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "$ENABLE_CGI" = "yes" then for ac_func in snprintf do as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` { $as_echo "$as_me:$LINENO: checking for $ac_func" >&5 $as_echo_n "checking for $ac_func... " >&6; } if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then $as_echo_n "(cached) " >&6 else cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ /* Define $ac_func to an innocuous variant, in case declares $ac_func. For example, HP-UX 11i declares gettimeofday. */ #define $ac_func innocuous_$ac_func /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $ac_func /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $ac_func (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$ac_func || defined __stub___$ac_func choke me #endif int main () { return $ac_func (); ; return 0; } _ACEOF rm -f conftest.$ac_objext conftest$ac_exeext if { (ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\"" $as_echo "$ac_try_echo") >&5 (eval "$ac_link") 2>conftest.er1 ac_status=$? grep -v '^ *+' conftest.er1 >conftest.err rm -f conftest.er1 cat conftest.err >&5 $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then eval "$as_ac_var=yes" else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 eval "$as_ac_var=no" fi rm -rf conftest.dSYM rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ conftest$ac_exeext conftest.$ac_ext fi ac_res=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` { $as_echo "$as_me:$LINENO: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } as_val=`eval 'as_val=${'$as_ac_var'} $as_echo "$as_val"'` if test "x$as_val" = x""yes; then cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF else { { $as_echo "$as_me:$LINENO: error: cannot find required function." >&5 $as_echo "$as_me: error: cannot find required function." >&2;} { (exit 1); exit 1; }; } fi done echo 'Enabling cgi program support...' else echo 'Disabling cgi support...' fi # now allow user to specify DISTNAME # Check whether --with-distname was given. if test "${with_distname+set}" = set; then withval=$with_distname; DISTNAME=$withval fi if test "x$DISTNAME" != "x" then echo "distname set to $DISTNAME" elif test "$host_os" = "mingw32" ; then DISTNAME=mingw elif test $HAVE_UNAME=yes -a x`uname -s` = xOSF1 then DISTNAME=alpha elif test $HAVE_UNAME=yes -a x`uname -s` = xHP-UX then DISTNAME=hpux elif test $HAVE_UNAME=yes -a x`uname -s` = xSunOS then DISTNAME=sun elif test $HAVE_UNAME=yes -a x`uname -s` = xFreeBSD then DISTNAME=freebsd elif test $HAVE_UNAME=yes -a x`uname -s` = xNetBSD then DISTNAME=netbsd elif test $HAVE_UNAME=yes -a x`uname -s` = xOpenBSD then DISTNAME=openbsd elif test $HAVE_UNAME=yes -a x`uname -s` = xBSD/OS then DISTNAME=bsdi elif test $HAVE_UNAME=yes -a x`uname -s` = xDarwin then DISTNAME=darwin elif test $HAVE_UNAME=yes -a x`uname -s` = xQNX then DISTNAME=qnx elif test -f /etc/SuSE-release then DISTNAME=suse elif test -d /etc/SuSEconfig then DISTNAME=suse5 elif test -f /etc/mandrake-release then DISTNAME=mandrake elif test -f /etc/whitebox-release then DISTNAME=redhat elif test -f /etc/redhat-release then DISTNAME=redhat elif test -f /etc/yellowdog-release then DISTNAME=yellowdog elif test -f /etc/debian_version then DISTNAME=debian elif test -f /etc/slackware-version then DISTNAME=slackware elif test -f /etc/gentoo-release then DISTNAME=gentoo elif test -f /etc/engarde-version then DISTNAME=engarde else DISTNAME=unknown fi DISTDIR=$DISTNAME with_distdir="yes" # Check whether --enable-install-distdir was given. if test "${enable_install_distdir+set}" = set; then enableval=$enable_install_distdir; if test "$enableval" = "no" ; then DISTDIR="" with_distdir="no" fi fi # Define the default UPS UPSTYPE=apcsmart # Define the default Cable UPSCABLE=smart # set the default nologin directory nologdir=/etc # Find the default directory to put the root-mode PID file in for PIDDIR in "/var/run" "/etc/apcupsd" do if test -d $PIDDIR then break; fi done # Find the default directory to put the apcupsd.events and apcupsd.status files for LOGDIR in "/var/log" "/etc/apcupsd" do if test -d $LOGDIR then break; fi done # set the default serial port lock director for LOCKDIR in "/var/lock" "/var/spool/locks" "/etc/apcupsd" do if test -d $LOCKDIR then break; fi done # set the default PWRFAILDIR PWRFAILDIR=${sysconfdir} # define the default serial port device SERIALDEV=/dev/ttyS0 # define the default NIS (Network Information Server -- CGI) port NISPORT=3551 # # Now we set appropriate distribution specific # variables and defaults # case "$DISTNAME" in alpha) PTHREAD_LFLAGS="-lpthread -lexc" DISTVER=`uname -r` SERIALDEV=/dev/tty01 LOCKDIR=/var/spool/locks LOGDIR=/etc/apcupsd DFILES="\ platforms/alpha/apcupsd \ platforms/alpha/awkhaltprog" ;; bsdi) DISTVER=`uname -a |awk '{print $3}'` ;; debian) DISTVER=`cat /etc/debian_version` DFILES="\ platforms/debian/apcupsd \ platforms/debian/ups-monitor" ;; freebsd) DISTVER=`uname -a |awk '{print $3}'` SERIALDEV=/dev/cuaa0 nologdir=/var/run PWRFAILDIR=/var/run LOCKDIR=/var/spool/lock PTHREAD_CFLAGS="-pthread" PTHREAD_LFLAGS="" LDFLAGS="$LDFLAGS -pthread" DFILES="\ platforms/freebsd/apcupsd \ platforms/freebsd/apccontrol" ;; gentoo) DISTVER=`awk '/version / {print $5}' < /etc/gentoo-release` DFILES="\ platforms/gentoo/apcupsd \ platforms/gentoo/halt" ;; hpux) DISTVER=`uname -r` SERIALDEV=/dev/tty0p0 PTHREAD_CFLAGS="-D_XOPEN_SOURCE_EXTENDED -D_REENTRANT" DFILES="\ platforms/hpux/apcupsd \ platforms/hpux/halt" ;; netbsd) DISTVER=`uname -a |awk '{print $3}'` SERIALDEV=/dev/cua01 PTHREAD_CFLAGS="-pthread" PTHREAD_LFLAGS="" LDFLAGS="$LDFLAGS -pthread" DFILES="\ platforms/netbsd/apcupsd" ;; openbsd) DISTVER=`uname -a |awk '{print $3}'` SERIALDEV=/dev/cua01 LOCKDIR=/var/spool/lock PTHREAD_CFLAGS="-pthread" PTHREAD_LFLAGS="" LDFLAGS="$LDFLAGS -pthread" DFILES="\ platforms/openbsd/apcupsd \ platforms/openbsd/apccontrol" ;; mandrake) DISTVER=`cat /etc/mandrake-release | grep release | cut -f 5 -d ' '` DFILES="\ platforms/mandrake/apcupsd \ platforms/mandrake/apcupsd.spec \ platforms/mandrake/awkhaltprog" ;; redhat) if test -f /etc/whitebox-release ; then f=/etc/whitebox-release else f=/etc/redhat-release fi if test `cat $f | grep release | cut -f 3 -d ' '`x = "Enterprise"x ; then DISTVER="Enterprise "`cat $f | grep release | cut -f 6 -d ' '` else DISTVER=`cat /etc/redhat-release | grep release | cut -f 5 -d ' '` fi DFILES="\ platforms/redhat/apcupsd \ platforms/redhat/apcupsd.spec \ platforms/redhat/awkhaltprog" ;; yellowdog) if test `cat /etc/yellowdog-release | grep release | cut -f 3 -d ' '`x = "Enterprise"x ; then DISTVER="Enterprise "`cat /etc/yellowdog-release | grep release | cut -f 6 -d ' '` else DISTVER=`cat /etc/yellowdog-release | grep release | cut -f 5 -d ' '` fi DFILES="\ platforms/yellowdog/apcupsd \ platforms/yellowdog/apcupsd.spec \ platforms/yellowdog/awkhaltprog" ;; engarde) DISTVER=`cat /etc/engarde-release | grep ersion | cut -f 5 -d ' '` DFILES="\ platforms/engarde/apcupsd \ platforms/engarde/apcupsd.spec \ platforms/engarde/awkhaltprog" ;; slackware) DISTVER=`cat /etc/slackware-version` DFILES="\ platforms/slackware/apcupsd \ platforms/slackware/rc6.patch" ;; sun) DISTVER=Solaris SERIALDEV=/dev/ttya PWRFAILDIR=/etc PIDDIR=/var/run LOCKDIR=/var/spool/locks LOGDIR=${sysconfdir} APCUPSD_MAIL=/usr/bin/mailx PTHREAD_CFLAGS="-D_POSIX_PTHREAD_SEMANTICS" DFILES="\ platforms/sun/apcupsd \ platforms/sun/rc0.solaris \ platforms/sun/apccontrol" ;; suse) DISTVER=`cat /etc/SuSE-release |grep VERSION| cut -f 3 -d ' '` DFILES="\ platforms/suse/apcupsd \ platforms/suse/awkhaltprog" ;; suse5) DISTNAME=suse DISTVER=5.x DFILES="\ platforms/suse/apcupsd \ platforms/suse/halt-setup.sh \ platforms/suse/halt" ;; darwin) DISTVER=`uname -r` SERIALDEV= UPSTYPE=usb UPSCABLE=usb PIDDIR=/var/run LOCKDIR=/var/tmp DFILES="\ platforms/darwin/apccontrol \ platforms/darwin/apcupsd-start \ platforms/darwin/apcupsd-uninstall \ platforms/darwin/org.apcupsd.apcupsd.plist" ;; qnx) PTHREAD_LFLAGS="" DISTVER=`uname -r` SERIALDEV=/dev/ser1 DFILES="\ platforms/qnx/apcupsd \ platforms/qnx/apccontrol" ;; mingw) PTHREAD_LFLAGS="-lpthreadGCE" LIBS="${LIBS} -luser32 -lgdi32 -lwsock32 -lnetapi32" CPPFLAGS="${CPPFLAGS} -D_WIN32_IE=0x0500" WIN32=win32 ;; unknown) DISTVER=unknown DFILES="\ platforms/unknown/apcupsd \ platforms/unknown/halt" ;; *) { $as_echo "$as_me:$LINENO: WARNING: Something went wrong. Unknown DISTNAME $DISTNAME" >&5 $as_echo "$as_me: WARNING: Something went wrong. Unknown DISTNAME $DISTNAME" >&2;} ;; esac # Check whether --with-nologin was given. if test "${with_nologin+set}" = set; then withval=$with_nologin; nologdir="$withval"; fi # now allow the user to specify the PID directory # Check whether --with-pid-dir was given. if test "${with_pid_dir+set}" = set; then withval=$with_pid_dir; PIDDIR="$withval"; fi # now allow user to specify LOGDIR # Check whether --with-log-dir was given. if test "${with_log_dir+set}" = set; then withval=$with_log_dir; LOGDIR="$withval"; fi # now allow user to specify LOCKDIR # Check whether --with-lock-dir was given. if test "${with_lock_dir+set}" = set; then withval=$with_lock_dir; LOCKDIR="$withval"; fi # now allow user to specify PWRFAILDIR # Check whether --with-pwrfail-dir was given. if test "${with_pwrfail_dir+set}" = set; then withval=$with_pwrfail_dir; PWRFAILDIR="$withval"; fi # now allow user to specify SERIALDEV # Check whether --with-serial-dev was given. if test "${with_serial_dev+set}" = set; then withval=$with_serial_dev; SERIALDEV="$withval"; fi # Check whether --with-dev was given. if test "${with_dev+set}" = set; then withval=$with_dev; SERIALDEV="$withval"; fi # now allow user to specify NISPORT # Check whether --with-nis-port was given. if test "${with_nis_port+set}" = set; then withval=$with_nis_port; NISPORT="$withval"; fi # now allow user to specify UPSTYPE # Check whether --with-upstype was given. if test "${with_upstype+set}" = set; then withval=$with_upstype; UPSTYPE="$withval"; fi # now allow user to specify UPSCABLE # Check whether --with-upscable was given. if test "${with_upscable+set}" = set; then withval=$with_upscable; UPSCABLE="$withval"; fi cat >>confdefs.h <<_ACEOF #define PIDDIR "$PIDDIR" _ACEOF cat >>confdefs.h <<_ACEOF #define LOGDIR "$LOGDIR" _ACEOF cat >>confdefs.h <<_ACEOF #define NOLOGDIR "$nologdir" _ACEOF cat >>confdefs.h <<_ACEOF #define PWRFAILDIR "$PWRFAILDIR" _ACEOF cat >>confdefs.h <<_ACEOF #define NISPORT $NISPORT _ACEOF HOST=$DISTNAME cat >>confdefs.h <<_ACEOF #define HOST "$HOST" _ACEOF gccinclude="." if test "$CC" = "gcc" then rm -f $srcdir/gcc.v $CC -v 2> $srcdir/gcc.v gccinclude=`cat $srcdir/gcc.v|grep specs|awk '{print $4}'| \ sed -e 's|specs|include|g'` echo "gcc private include directory found." rm -f $srcdir/gcc.v fi GENERATE_FILES="\ autoconf/variables.mak \ platforms/apccontrol \ platforms/etc/changeme \ platforms/etc/commfailure \ platforms/etc/commok \ platforms/etc/offbattery \ platforms/etc/onbattery \ platforms/etc/apcupsd.conf \ examples/safe.apccontrol \ $DFILES" if test "$needlibusb"x = "true"x then GENERATE_FILES="$GENERATE_FILES \ include/libusb.h" fi if test "$ENABLE_CGI" = "yes" then GENERATE_FILES="$GENERATE_FILES src/cgi/cgiconfig.h" fi ac_config_files="$ac_config_files ${GENERATE_FILES}" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:$LINENO: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) $as_unset $ac_var ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes (double-quote # substitution turns \\\\ into \\, and sed turns \\ into \). sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:$LINENO: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} cat >$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix ;; esac fi # PATH needs CR # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo if (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Support unset when possible. if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then as_unset=unset else as_unset=false fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 { (exit 1); exit 1; } fi # Work around bugs in pre-3.0 UWIN ksh. for as_var in ENV MAIL MAILPATH do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # Required to use basename. if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi # Name of the executable. as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # CDPATH. $as_unset CDPATH as_lineno_1=$LINENO as_lineno_2=$LINENO test "x$as_lineno_1" != "x$as_lineno_2" && test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { # Create $as_me.lineno as a copy of $as_myself, but with $LINENO # uniformly replaced by the line number. The first 'sed' inserts a # line-number line after each line using $LINENO; the second 'sed' # does the real work. The second script uses 'N' to pair each # line-number line with the line containing $LINENO, and appends # trailing '-' during substitution so that $LINENO is not a special # case at line end. # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the # scripts with optimization help from Paolo Bonzini. Blame Lee # E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 { (exit 1); exit 1; }; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in -n*) case `echo 'x\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. *) ECHO_C='\c';; esac;; *) ECHO_N='-n';; esac if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p=: else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 # Save the log message, to keep $[0] and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.63. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files from templates according to the current configuration. Usage: $0 [OPTION]... [FILE]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.63, with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" Copyright (C) 2008 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac CONFIG_FILES="$CONFIG_FILES '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac CONFIG_HEADERS="$CONFIG_HEADERS '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header { $as_echo "$as_me: error: ambiguous option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; };; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) { $as_echo "$as_me: error: unrecognized option: $1 Try \`$0 --help' for more information." >&2 { (exit 1); exit 1; }; } ;; *) ac_config_targets="$ac_config_targets $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "include/apcconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS include/apcconfig.h:autoconf/config.h.in" ;; "${GENERATE_FILES}") CONFIG_FILES="$CONFIG_FILES ${GENERATE_FILES}" ;; *) { { $as_echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 $as_echo "$as_me: error: invalid argument: $ac_config_target" >&2;} { (exit 1); exit 1; }; };; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap '{ (exit 1); exit 1; }' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || { $as_echo "$as_me: cannot create a temporary directory in ." >&2 { (exit 1); exit 1; } } # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=' ' ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 $as_echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\).*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\).*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || { { $as_echo "$as_me:$LINENO: error: could not setup config files machinery" >&5 $as_echo "$as_me: error: could not setup config files machinery" >&2;} { (exit 1); exit 1; }; } _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_t=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_t"; then break elif $ac_last_try; then { { $as_echo "$as_me:$LINENO: error: could not make $CONFIG_HEADERS" >&5 $as_echo "$as_me: error: could not make $CONFIG_HEADERS" >&2;} { (exit 1); exit 1; }; } else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 { { $as_echo "$as_me:$LINENO: error: could not setup config headers machinery" >&5 $as_echo "$as_me: error: could not setup config headers machinery" >&2;} { (exit 1); exit 1; }; } fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) { { $as_echo "$as_me:$LINENO: error: invalid tag $ac_tag" >&5 $as_echo "$as_me: error: invalid tag $ac_tag" >&2;} { (exit 1); exit 1; }; };; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || { { $as_echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 $as_echo "$as_me: error: cannot find input file: $ac_f" >&2;} { (exit 1); exit 1; }; };; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac ac_file_inputs="$ac_file_inputs '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:$LINENO: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` { as_dir="$ac_dir" case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || { { $as_echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 $as_echo "$as_me: error: cannot create directory $as_dir" >&2;} { (exit 1); exit 1; }; }; } ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p ' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:$LINENO: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ || { { $as_echo "$as_me:$LINENO: error: could not create $ac_file" >&5 $as_echo "$as_me: error: could not create $ac_file" >&2;} { (exit 1); exit 1; }; } fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ || { { $as_echo "$as_me:$LINENO: error: could not create -" >&5 $as_echo "$as_me: error: could not create -" >&2;} { (exit 1); exit 1; }; } fi ;; esac done # for ac_tag { (exit 0); exit 0; } _ACEOF chmod +x $CONFIG_STATUS ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || { { $as_echo "$as_me:$LINENO: error: write failure creating $CONFIG_STATUS" >&5 $as_echo "$as_me: error: write failure creating $CONFIG_STATUS" >&2;} { (exit 1); exit 1; }; } # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:$LINENO: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi chmod 755 examples/safe.apccontrol $MAKE clean # # A whole lot of hand springs to get the compiler version. # This is because gcc changed the output in version 3.0 # CXXVERSION=`${CXX} --version | tr '\n' ' ' | cut -f 3 -d ' '` if test "x${CXXVERSION}" = "x" ; then CXXVERSION=`${CXX} --version | tr '\n' ' ' | cut -f 1 -d ' '` fi eval srcdir=${srcdir} eval sbindir=${sbindir} eval sysconfdir=${sysconfdir} eval mandir=${mandir} echo " Configuration on `date`: Host: $host -- ${DISTNAME} ${DISTVER} Apcupsd version: ${VERSION} (${DATE}) Source code location: ${srcdir} Install binaries: ${sbindir} Install config files: ${sysconfdir} Install man files: ${mandir} Nologin file in: ${nologdir} PID directory: ${PIDDIR} LOG dir (events, status) ${LOGDIR} LOCK dir (for serial port) ${LOCKDIR} Power Fail dir ${PWRFAILDIR} Compiler: ${CXX} ${CXXVERSION} Preprocessor flags: ${CPPFLAGS} Compiler flags: ${CXXFLAGS} ${PTHREAD_FLAGS} Linker: ${LD} Linker flags: ${LDFLAGS} Host and version: ${DISTNAME} ${DISTVER} Shutdown Program: ${SHUTDOWN} Port/Device: ${SERIALDEV} Network Info Port (CGI): ${NISPORT} UPSTYPE ${UPSTYPE} UPSCABLE ${UPSCABLE} drivers (no-* are disabled): ${APCSMART_DRIVER:-no-apcsmart} ${DUMB_DRIVER:-no-dumb} ${NET_DRIVER:-no-net} ${DISPLAY_USB_DRIVER:-no-usb} ${DISPLAY_SNMP_DRIVER:-no-snmp} ${PCNET_DRIVER:-no-pcnet} ${MODBUS_DRIVER:-no-modbus} ${MODBUS_USB_DRIVER:-no-modbus-usb} ${TEST_DRIVER:-no-test} enable-nis: ${NISSRV_ENABLED} with-nisip: ${NISIP} enable-cgi: ${ENABLE_CGI} with-cgi-bin: ${CGIBIN} with-libwrap: ${with_libwrap} enable-pthreads: ${with_pthreads} enable-dist-install: ${with_distdir} enable-gapcmon: ${GAPCMON_ENABLED} enable-apcagent: ${APCAGENT_ENABLED} " > config.out cat config.out echo Configuration complete: Run \'$MAKE\' to build apcuspd. echo echo $PATH | grep /usr/ucb >/dev/null if test $? = 0 ; then { $as_echo "$as_me:$LINENO: WARNING: WARNING! You have /usr/ucb on your path. We STRONGLY recommend that you remove it and rerun configure. Otherwise apcupsd may be unable to shutdown your system. " >&5 $as_echo "$as_me: WARNING: WARNING! You have /usr/ucb on your path. We STRONGLY recommend that you remove it and rerun configure. Otherwise apcupsd may be unable to shutdown your system. " >&2;}; fi apcupsd-3.14.14/doc/000077500000000000000000000000001274230402600140705ustar00rootroot00000000000000apcupsd-3.14.14/doc/Makefile000066400000000000000000000021301274230402600155240ustar00rootroot00000000000000topdir:=.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-targets: apcupsd.man.txt apcaccess.man.txt apctest.man.txt \ apccontrol.man.txt apcupsd.conf.man.txt apcupsd.man.txt: apcupsd.8 $(call MANIFY,$<,$@) apcaccess.man.txt: apcaccess.8 $(call MANIFY,$<,$@) apctest.man.txt: apctest.8 $(call MANIFY,$<,$@) apccontrol.man.txt: apccontrol.8 $(call MANIFY,$<,$@) apcupsd.conf.man.txt: apcupsd.conf.5 $(call MANIFY,$<,$@) all-install: install-man all-uninstall: uninstall-man install-man: $(call MKDIR,$(mandir)/man8) $(call INSTDATA,644,apcupsd.8,$(mandir)/man8/apcupsd.8) $(call INSTDATA,644,apcaccess.8,$(mandir)/man8/apcaccess.8) $(call INSTDATA,644,apctest.8,$(mandir)/man8/apctest.8) $(call INSTDATA,644,apccontrol.8,$(mandir)/man8/apccontrol.8) $(call MKDIR,$(mandir)/man5) $(call INSTDATA,644,apcupsd.conf.5,$(mandir)/man5/apcupsd.conf.5) uninstall-man: $(call UNINST,$(mandir)/man8/apcupsd.8) $(call UNINST,$(mandir)/man8/apcaccess.8) $(call UNINST,$(mandir)/man8/apctest.8) $(call UNINST,$(mandir)/man8/apccontrol.8) $(call UNINST,$(mandir)/man5/apcupsd.conf.5) apcupsd-3.14.14/doc/apcaccess.8000066400000000000000000000304241274230402600161110ustar00rootroot00000000000000.\" manual page [] for apctest version 3.14.6 .Dd March 28, 2014 .Dt APCACCESS 8 .Os apcaccess v3.14.6 .Sh NAME .Nm apcaccess .Nd retrieve status information from apcupsd(8) .Sh SYNOPSIS .Nm [-f ] [-h [:]] [-p ] [-u] [] [[:]] .Sh DESCRIPTION .Nm is a program which prints out the complete status of most American Power Conversion Corp. (APC) UPSes provided you have the .Xr apcupsd 8 daemon installed, properly configured and running. It can access status information from any APC UPS attached to the localhost or attached to any computer on the network which is running apcuspd in NIS mode. .Pp The command line options are: .Bl -hang -width "" .It -f configuration file of apcupsd (default is usually /etc/apcupsd/apcupsd.conf) .It -h hostname and port of apcupsd to communicate with. The default hostname and port are obtained from the configuration file. .It -p Report only the value of the named parameter instead of all parameters and values. .It -u Remove units field for easier parsing by scripts. .It An optional command, unless a hostname is also being specified. The only implemented command is .Em status\& Shorthand for .Em status\& localhost:3551 . This produces a full printout of the available status information for the associated UPS. .It An optional hostname which may be a bare machine name, fully qualified domain name or IP address. .It : An optional port number where a hostname argument has been specified. The default is 3551, the official port number assigned by .Tn IANA for the apcupsd NIS server. The default hostname and port are obtained from the configuration file. .El .Pp .Nm uses apcupsd's inbuilt Network Information Server (NIS) -- no relation to Sun's NIS/YP service -- to obtain the current status information from the UPS on the local or remote computer. It is therefore necessary to have the following configuration directives: .Pp .Bl -item -compact .It NETSERVER on .It NISPORT 3551 .El .Pp in the .Pa /etc/apcupsd/apcupsd.conf configuration file so that the Network Information Server will be accessible. Firewall rules for appropriate network access may also be needed. .Sh STATUS REPORT FORMAT The status report output format is simple ASCII. Generally there is a single piece of information on each line of output. The content varies based on the model of UPS being used and, in some cases, the firmware version. .Sh EXAMPLES Set out below is a sample of the status output which may be generated for the specified UPS models. .Pp .Ss All models .Bl -hang -width "xxxxxxxxxx" -compact .It APC : version, number of records and number of bytes following .It DATE : Date and time of last update from UPS .It HOSTNAME : hostname of computer running apcupsd .It VERSION : apcupsd version number, date and operating system .It UPSNAME : UPS name from configuration file (dumb) or EEPROM (smart) .It CABLE : Cable type specified in the configuration file .It MODEL : UPS model derived from UPS information .It UPSMODE : Mode in which UPS is operating .It STARTTIME : Date and time apcupsd was started .It STATUS : UPS status. One or more of the following (space-separated): CAL TRIM BOOST ONLINE ONBATT OVERLOAD LOWBATT REPLACEBATT NOBATT SLAVE SLAVEDOWN .br or .br COMMLOST .br or .br SHUTTING DOWN .It MASTERUPD : Last time the master sent an update to the slave .It ENDAPC : Date and time of status information was written .El .Ss Smart-UPS and Matrix-UPS (Smart Signalling) .Bl -hang -width "xxxxxxxx"-compact .It LINEV : Current input line voltage .It LOADPCT : Percentage of UPS load capacity used as estimated by UPS .It BCHARGE : Current battery capacity charge percentage .It TIMELEFT : Remaining runtime left on battery as estimated by the UPS .It MBATTCHG : Min battery charge % (BCHARGE) required for system shutdown .It MINTIMEL : Min battery runtime (MINUTES) required for system shutdown .It MAXTIME : Max battery runtime (TIMEOUT) after which system is shutdown .It MAXLINEV : Maximum input line voltage since apcupsd started .It MINLINEV : Min (observed) input line voltage since apcupsd started .It OUTPUTV : Current UPS output voltage .It SENSE : Current UPS sensitivity setting for voltage fluctuations .It DWAKE : Time UPS waits after power off when the power is restored .It DSHUTD : Delay before UPS powers down after command received .It DLOWBATT : Low battery signal sent when this much runtime remains .It LOTRANS : Input line voltage below which UPS will switch to battery .It HITRANS : Input line voltage above which UPS will switch to battery .It RETPCT : Battery charge % required after power off to restore power .It ITEMP : UPS internal temperature in degrees Celcius .It ALARMDEL : Delay period before UPS starts sounding alarm .It BATTV : Current battery voltage .It LINEFREQ : Current line frequency in Hertz .It LASTXFER : Reason for last transfer to battery since apcupsd startup .It NUMXFERS : Number of transfers to battery since apcupsd startup .It XONBATT : Date, time of last transfer to battery since apcupsd startup .It TONBATT : Seconds currently on battery .It CUMONBATT : Cumulative seconds on battery since apcupsd startup .It XOFFBAT : Date, time of last transfer off battery since apcupsd startup .It SELFTEST : Date and time of last self test since apcupsd startup .It STESTI : Self-test interval .It STATFLAG : UPS status flag in hex .It DIPSW : Current UPS DIP switch settings .It REG1 : Fault register 1 in hex .It REG2 : Fault register 2 in hex .It REG3 : Fault register 3 in hex .It MANDATE : UPS date of manufacture .It SERIALNO : UPS serial number .It BATTDATE : Date battery last replaced (if set) .It NOMOUTV : Nominal output voltage to supply when on battery power .It NOMBATTV : Nominal battery voltage .It EXTBATTS : Number of external batteries (for XL models) .It BADBATTS : Number of bad external battery packs (for XL models) .It FIRMWARE : UPS firmware version .It APCMODEL : APC model information .El .Ss Newer Back-UPS Pro (Smart Signalling) .Bl -hang -width "xxxxxxxx"-compact .It LINEV : Current input line voltage .It LOADPCT : Percentage of UPS load capacity used .It MBATTCHG : Min battery charge % (BCHARGE) required for system shutdown .It MINTIMEL : Min battery runtime (MINUTES) required for system shutdown .It MAXTIME : Max battery runtime (TIMEOUT) after which system is shutdown .It MAXLINEV : Maximum input line voltage since apcupsd startup .It MINLINEV : Minimum input line voltage since apcupsd startup .It OUTPUTV : Current UPS output voltage .It BATTV : Current battery charge voltage .It STATFLAG : UPS status flag in hex .El .Ss Back-UPS RS 1500 (USB) .Bl -hang -width "xxxxxxxx"-compact .It LINEV : Current input line voltage .It LOADPCT : Percentage of UPS load capacity used .It BCHARGE : Current battery capacity charge percentage .It TIMELEFT : Remaining runtime left on battery as estimated by UPS .It MBATTCHG : Min battery charge % (BCHARGE) required for system shutdown .It MINTIMEL : Min battery runtime (MINUTES) required for system shutdown .It MAXTIME : Max battery runtime (TIMEOUT) after which system is shutdown .It *OUTPUTV : Current UPS output voltage .It *DWAKE : Time UPS waits after power off when the power is restored .It *DSHUTD : Delay before UPS powers down after command received .It LOTRANS : Input line voltage below which UPS will switch to battery .It HITRANS : Input line voltage above which UPS will switch to battery .It *RETPCT : Battery charge % required after power off to restore power .It *ITEMP : UPS internal temperature in degrees Celcius .It ALARMDEL : Delay period before UPS starts sounding alarm .It BATTV : Current battery voltage .It *LINEFREQ : Current line frequency in Hertz .It *LASTXFER : Reason for last transfer to battery since apcupsd startup .It NUMXFERS : Number of transfers to battery since apcupsd startup .It XONBATT : Date, time of last transfer to battery since apcupsd startup .It TONBATT : Seconds currently on battery .It CUMONBATT : Cumulative seconds on battery since apcupsd startup .It XOFFBAT : Date, time of last transfer off battery since apcupsd startup .It SELFTEST : Date and time of last self test since apcupsd startup .It STATFLAG : UPS status flag in hex .It MANDATE : UPS date of manufacture .It SERIALNO : UPS serial number .It BATTDATE : Date battery last replaced (if set) .It NOMBATTV : Nominal battery voltage .It FIRMWARE : UPS firmware version .It APCMODEL : APC model information .It * presence dependant on USB firmware version. .El .Ss Web/SNMP (AP9716) or PowerNet SNMP (AP9605) SmartSlot Card .Bl -hang -width "xxxxxxxx"-compact .It LINEV : Current input line voltage .It LOADPCT : Percentage of UPS load capacity used as estimated by UPS .It BCHARGE : Current battery capacity charge percentage .It TIMELEFT : Remaining runtime left on battery as estimated by UPS .It MBATTCHG : Min battery charge % (BCHARGE) required for system shutdown .It MINTIMEL : Min battery runtime (MINUTES) required for system shutdown .It MAXTIME : Max battery runtime (TIMEOUT) after which system is shutdown .It MAXLINEV : Maximum input line voltage since apcupsd startup .It MINLINEV : Minimum input line voltage since apcupsd startup .It OUTPUTV : UPS output voltage .It SENSE : Current UPS sensitivity setting for voltage fluctuations .It DWAKE : Time UPS waits after power off when the power is restored .It DSHUTD : Delay before UPS powers down after command received .It DLOWBATT : Low battery signal sent when this much runtime remains .It LOTRANS : Input line voltage below which UPS will switch to battery .It HITRANS : Input line voltage above which UPS will switch to battery .It RETPCT : Battery charge % required after power off to restore power .It ITEMP : UPS internal temperature in degrees Celcius .It ALARMDEL : Delay period before UPS starts sounding alarm .It LINEFREQ : Current line frequency in Hertz .It NUMXFERS : Number of transfers to battery since apcupsd startup .It TONBATT : Seconds currently on battery .It CUMONBATT : Cumulative seconds on battery since apcupsd startup .It XOFFBATT : Date, time of last transfer off battery since apcupsd startup .It STESTI : Self-test interval .It STATFLAG : UPS status flag in hex .It DIPSW : Current UPS DIP switch settings .It MANDATE : UPS date of manufacture .It SERIALNO : UPS serial number .It BATTDATE : Date battery last replaced (if set) .It NOMOUTV : Nominal output voltage to supply when on battery power .It NOMPOWER : Nominal power output in watts .It EXTBATTS : Number of external batteries (for XL models) .It BADBATTS : Number of bad external battery packs (for XL models) .It FIRMWARE : UPS firmware version .It APCMODEL : APC model information .El .Ss Share-UPS (AP9270) (Basic port) .Bl -hang -width "xxxxxxxx"-compact .It MBATTCHG : Min battery charge % (BCHARGE) required for system shutdown .It MINTIMEL : Min battery runtime (MINUTES) required for system shutdown .It MAXTIME : Max battery runtime (TIMEOUT) after which system is shutdown .It NUMXFERS : Number of transfers to battery since apcupsd startup .It TONBATT : Seconds currently on battery .It CUMONBATT : Cumulative seconds on battery since apcupsd startup .It XOFFBATT : Date, time of last transfer off battery since apcupsd startup .It STATFLAG : UPS status flag in hex .El .Ss UPS Environmental Monitoring SmartSlot Card (AP9612TH) .Bl -hang -width "xxxxxxxx"-compact .It HUMIDITY : Ambient humidity .It AMBTEMP : Ambient temperature .El .Ss Back-UPS Pro and Smart-UPS v/s (Smart Signalling) .Bl -hang -width "xxxxxxxx"-compact .It LINEFAIL : Input line voltage status. .It BATTSTAT : Battery status. .It LASTXFER : Last (observed) transfer to battery. .El .Ss Back-UPS and Net-UPS (Simple Signalling) .Bl -hang -width "xxxxxxxx"-compact .It LINEFAIL : Input line voltage status. .It BATTSTAT : Battery status. .It STATFLAG : UPS status flag in hex. .El .Sh FILES .Pa /etc/apcupsd/apcupsd.conf .Sh SEE ALSO .Xr apcupsd.conf 5 , .Xr apcupsd 8 . .Pp The HTML apcupsd manual installed on your system or available online at http://www.apcupsd.org/ .Sh AUTHORS .Ss This page .An Trevor Roydhouse .Ss Software .An Adam Kropelin (current Project Manager and Code Maintainer) .An Kern Sibbald (former Project Manager and Code Maintainer) .An Riccardo Facchetti (former Project Manager and Code Maintainer) .An Andre M. Hedrick (Project Founder and former Code Maintainer) .Ss Contributors An enormous number of users who have devoted their time and energy to this project -- thanks. apcupsd-3.14.14/doc/apccontrol.8000066400000000000000000000235351274230402600163350ustar00rootroot00000000000000.\" manual page [] for apctest version 3.14.6 .Dd January 10, 2009 .Dt APCCONTROL 8 .Os apccontrol v3.14.6 .Sh NAME .Nm apccontrol .Nd apcupsd(8) event handler script .Sh SYNOPSIS .Nm { } .Sh DESCRIPTION When .Xr apcupsd 8 detects anomalies from the UPS being monitored, it triggers an event which usually results in one or more calls to the .Nm shell script. Each event causes .Nm to take a particular action. These actions default to sane behaviour for all the events that apcupsd is likely to encounter. However, you can change the behaviour of every single action. .Pp When apcupsd detects an event, it calls the .Nm script with the following four arguments: .Pp .Bl -hang -width "xxxxxxxxxx" .It event This is the event that occurred. Refer to the list of possible events below. .It ups-name This is the name of the UPS as specified in the .Pa /etc/apcupsd/apcupsd.conf configuration file - not the name in the EEPROM of a smart UPS. .It connected This is 1 if apcupsd is connected to the UPS via a serial or USB port. In the case of a slave machine where apcupsd is not directly connected to the UPS, this value will be 0. .It powered This is 1 if the computer on which apcupsd is running is powered by the UPS and 0 if not. This is not currently implemented and always defaults to 0. .El .Pp Events are sent to the system log and, optionally, to the temporary events file .Pa ( /etc/apcupsd/apcupsd.events ) , and they also generate a call to .Nm which in turn will call any scripts you have placed in the .Pa /etc/apcupsd directory. .Ss LIST OF EVENTS AND DEFAULT ACTIONS .Bl -hang -width "commfailure" .It annoyme apcupsd generates this event when a shutdown is scheduled, and the time specified by the ANNOYME configuration directive in the .Pa /etc/apcupsd/apcupsd.conf file has expired. .Pp Default action -- sends "Power problems please logoff." to .Xr wall 1 and then exits. .It battattach apcupsd generates this event when it detects that the UPS battery has been reconnected after a battdetach event. .Pp Default action: does nothing. .It battdetach apcupsd generates this event when it detects that the UPS battery has been disconnected. .Pp Default action: does nothing. .It changeme apcupsd generates this event when it detects that the utility power is on, but the battery is not functioning correctly. This is repeated every 9 hours. .Pp Default action -- sends "Emergency! UPS batteries have failed Change them NOW" to wall and then exits. .It commfailure apcupsd generates this event each time it loses communication with the monitored UPS. This event is not detected on simple signalling UPSes like the Back-UPS 650. .Pp Default action -- sends "Communications with UPS lost." to wall and then exits. .It commok apcupsd generates this event after a commfailure event when communication with the UPS is re-established. .Pp Default action -- sends "Communications with UPS restored." to wall and then exits. .It doreboot This event is deprecated and should not be used. .Pp Default action -- sends "Beginning Reboot Sequence" to wall and then calls .Xr shutdown 8 with the "-r now" command line arguments to reboot the computer. .It doshutdown apcupsd generates this event to shutdown the computer when the UPS is running on battery power and one of the limits (time, run, load) is reached. .Pp Default action -- sends "Beginning Shutdown Sequence" to wall and then calls .Xr shutdown 8 with the command line arguments "-h now" to shutdown the computer. .It emergency apcupsd generates this event when the UPS is on battery power, the battery is low and the utility power is on: a sure sign of battery failure! .Pp Default action -- sends "Emergency Shutdown. Possible UPS battery failure." to wall. Immediately after this, apcupsd generates a doshutdown event to shutdown the system. .It failing apcupsd generates this event when the UPS is running on batteries and the UPS sets the low battery signal indicating that battery power is nearly exhausted. After this event, apcupsd will immediately generate a doshutdown event. .Pp Default action -- sends "UPS battery power exhausted. Doing shutdown." to wall and then exits. .It killpower apcupsd does not normally generate this event. Instead, it is invoked directly from the system halt script as 'apccontrol killpower' because the killpower event needs to be performed as late in system shutdown as possible. .Pp Default action -- sends "UPS now committed to shut down" to wall, waits for 10 seconds and then issues the command "apcupsd --killpower" to put the UPS into hibernate mode and shut off power to the connected equipment. In the case of a smart UPS, the UPS will then wait for the expiry of any configured shutdown time delay specified by the SLEEP configuration directive. In hibernate mode, the UPS will restore utility power to the connected equipment subject to the values specified for the RETURNCHARGE and WAKEUP configuration directives. .It loadlimit apcupsd generates this event when the battery discharge limit specified by the BATTERYLEVEL configuration directive has been reached. .Pp Default action -- sends "UPS battery discharge limit reached. Doing shutdown" to wall and then exits. After this event, apcupsd will immediately generate a doshutdown event. .It mainsback apcupsd generates this event when the utility power returns after a powerout event. The doshutdown event may or may not have been generated depending on the parameters you have defined and the length of the power outage. Attempting cancellation of a doshutdown event should never be tried as it is very unlikely to succeed and will almost certainly leave your computer in an indeterminate state. .Pp Default action -- if the file .Pa /var/run/powerfail exists, sends "Continuing with shutdown." to wall and then exits. Otherwise, does nothing. .It onbattery apcupsd generates this event if a power failure has been detected and the UPS is still on battery power at the expiry of the delay specified by the ONBATTERYDELAY configuration directive. .Pp Default action -- sends "Power failure. Running on UPS batteries." to wall and then exits. .It offbattery apcupsd generates this event when the utility power returns if, and only if, the onbattery event has been generated. .Pp Default -- sends ""Power has returned..." to wall and then exits. .It powerout apcupsd generates this event as soon as apcupsd detects that the UPS has switched to battery power and it is not a self-test. .Pp Default action -- does nothing. .It remotedown apcupsd generates this event on a slave machine when it detects either (1) that the master has shutdown, or (2) that an onbattery event has occurred and communication with the master has been lost. .Pp Default action: sends "Remote Shutdown. Beginning Shutdown Sequence." to wall and exits. Immediately after this, apcupsd generates a doshutdown event to shutdown the system. .It runlimit apcupsd generates this event when the remaining runtime limit specified by the MINUTES configuration directive expires while the UPS is on battery power as the result of a utility power outage. The remaining runtime is internally calculated by the UPS and monitored by apcuspd. .Pp Default action -- sends "UPS battery runtime percent reached. Doing shutdown." to wall and then exits. After this event, apcupsd will immediately generate a doshutdown event. .It timeout apcupsd generates this event when the time specified by the TIMEOUT configuration directive expires while the UPS is on battery power as the result of a utility power outage. This configuration directive is not normally used with smart UPSes which would instead rely on the more reliable remaining runtime (MINUTES) or the battery level (BATTERYLEVEL) configuration directives. .Pp Default action -- send "UPS battery runtime limit exceeded. Doing shutdown." to wall and then exits. After this event, apcupsd will immediately generate a doshutdown event. .It startselftest apcupsd generates this event when it detects the start of a UPS self test. .Pp Default action: does nothing. .It endselftest apcupsd generates this event when it detects the end of a UPS self test. .Pp Default action: does nothing. .El .Ss CUSTOMISING EVENT ACTIONS Do .Em not modify .Nm directly as it will be overwritten the next time you upgrade to a new release of apcupsd. .Pp The recommended way to customise an event action is simply to create an executable program or script file with the same name as the event and put that file in the .Pa /etc/apcupsd directory. Now, when the selected event occurs, .Nm will execute your program or script. .Pp If you want .Nm to also execute its default action for the selected event, your program or script should exit with an exit status of 0 (zero). .Pp If you do .Em not want .Nm to also execute its default action for the selected event, your program or script must exit with an exit status of 99. Be aware that if you completely override the default action, you must ensure the proper shutdown of your computer if this is necessary. .Pp Some sample scripts (changeme, commfailure, commok, offbattery and onbattery) that email messages to root instead of broadcasting messages to all logged-in users may be found in .Pa /etc/apcupsd after an installation and also in the .Pa platforms/etc directory of the apcupsd source code. .Pp .Sh FILES .Pa /etc/apcupsd/apccontrol .Sh SEE ALSO .Xr wall 1 , .Xr apcupsd.conf 5 , .Xr apcupsd 8 , .Xr shutdown 8 . .Pp The HTML apcupsd manual installed on your system or available online at http://www.apcupsd.org/ .Sh AUTHORS .Ss This page .An Trevor Roydhouse .Ss Software .An Adam Kropelin (current Project Manager and Code Maintainer) .An Kern Sibbald (former Project Manager and Code Maintainer) .An Riccardo Facchetti (former Project Manager and Code Maintainer) .An Andre M. Hedrick (Project Founder and former Code Maintainer) .Ss Contributors An enormous number of users who have devoted their time and energy to this project -- thanks. apcupsd-3.14.14/doc/apctest.8000066400000000000000000000274751274230402600156430ustar00rootroot00000000000000.\" manual page [] for apctest version 3.14.6 .Dd January 10, 2009 .Dt APCTEST 8 .Os apctest v3.14.6 .Sh NAME .Nm apctest .Nd apcupsd(8) test program .Sh SYNOPSIS .Nm .Sh DESCRIPTION .Nm is a program that enables the running of certain low-level tests to check the operation of the attached simple signalling American Power Conversion Corp (APC) UPS and to check that your .Xr apcupsd 8 configuration is correctly setup and can establish communication with the UPS. .Pp For an APC UPS operating in APC smart protocol mode, .Nm enables the reading and programming of the values of the UPS EEPROM configuration variables as well and the performing of a battery runtime calibration. It also provides a simple TTY chat mode which allows direct interaction with the UPS via the APC smart protocol. For details of this protocol and the available commands, refer to the detailed "APC Smart Protocol" section in the apcupsd manual. .Pp IMPORTANT: Before running .Nm .Pp .Bl -bullet .It Check that the UPSCABLE, UPSTYPE and DEVICE configuration directives in the .Xr apcupsd.conf 5 configuration file have been set appropriately; and .It Shutdown apcupsd if it is running. You cannot run both .Xr apcupsd and .Nm at the same time. .El .Pp When run, .Nm displays a menu of options which are different depending on whether the UPS is connected to a USB port or to a serial port. For a serial port connection, there are two different menus depending on whether the UPS is operating in APC smart protocol mode or simple signalling mode - this also depends on which cable is used to connect to the UPS. If a simple signalling cable is used to connect to a Smart-UPS, the UPS will only be able to operate in simple signalling mode. .Pp .Nm saves a transcript of the session to the file .Pa apctest.out in the directory from which the program was called. Its content is useful for debugging purposes. .Sh USB PORT When using a UPS connected to a USB port (eg Back-UPS RS 1500), the following menu options will appear: .Ss Option 1) Test kill UPS power Performs a power down of the UPS into hibernate mode. .Ss Option 2) Perform self-test Performs an immediate self-test (switches to battery power to do so). .Ss Option 3) Read last self-test result Displays the last self-test result. .Ss Option 4) View/Change battery date Displays the current battery replacement date and optionally allows you to change it - useful when the battery is replaced so that you can accurately keep track of its age. .Ss Option 5) View manufacturing date Displays the date the UPS was manufactured. .Ss Option 6) View/Change alarm behavior Sets the delay period before the UPS starts sounding its alarm when the utility power is lost. .Ss Option 7) View/Change sensitivity Changes how sensitive the UPS is to the utility power quality and voltage fluctuations - (H)igh, (M)edium or (L)ow. The higher the sensitivity, the faster the UPS will switch to battery power or activate SmartBoost/SmartTrim (features that avoid using battery power provided the under/over voltage is within 12% of nominal). This setting should normally be set to High unless the UPS switches to battery power frequently, in which case a less sensitive setting will preserve UPS batteries... if the connected equipment can tolerate the power quality. .Ss Option 8) View/Change low transfer voltage Sets the low voltage level at which the UPS switches to battery or activates SmartBoost. .Ss Option 9) View/Change high transfer voltage Sets the high voltage level at which the UPS switches to battery or activates SmartTrim. .Ss Option 10) Perform battery calibration This performs a battery runtime calibration. This can only be performed if your battery is charged to 100% of capacity. The runtime calibration discharges the UPS battery to approximately 25% of capacity. The exact percentage depends on the UPS model. .Pp The advantage of doing this calibration is that the UPS will recalibrate the remaining runtime counter that it maintains and therefore report a more accurate estimated runtime. As batteries age, they tend to hold less charge, so the UPS's internal runtime counter may not be accurate after several years. .Pp It is recommended that battery runtime calibration be performed annually. Performing it too often shortens the lifetime of the UPS batteries. .Ss Option 11) Test Alarm This option will cause the UPS alarm beeper to sound for several seconds. .Ss Option 12) View/Change self-test interval This option allows you to change the time interval between automatic UPS self-tests. .Ss Option Q) Quit Exits from the program. .Sh SERIAL PORT (SMART PROTOCOL MODE) When using a UPS operating in APC smart protocol mode (eg a Smart-UPS) the following menu options will appear: .Ss Option 1) Query the UPS for all known values Selecting this option probes the UPS for all EEPROM configuration variable values known to .Nm and displays them in rather raw format. This output can be useful for providing technical support if you are having problems with the behaviour of the UPS or .Xr apcupsd 8 . .Ss Option 2) Perform a Battery Runtime Calibration This performs a battery runtime calibration. This can only be performed if your battery is charged to 100% of capacity. The runtime calibration discharges the UPS battery to approximately 25% of capacity. The exact percentage depends on the UPS model. .Nm can optionally abort the calibration if it detects that the battery charge is below 10%. .Pp The advantage of doing this calibration is that the UPS will recalibrate the remaining runtime counter that it maintains and therefore report a more accurate estimated runtime. As batteries age, they tend to hold less charge, so the UPS's internal runtime counter may not be accurate after several years. .Pp It is recommended that battery runtime calibration be performed annually. Performing it too often shortens the lifetime of the UPS batteries. .Ss Option 3) Abort Battery Calibration This option aborts an in progress battery runtime calibration. .Pp .Ss Option 4) Monitor Battery Calibration progress Allows restarting of the monitoring of a battery runtime calibration. .Ss Option 5) Program EEPROM Allows the programming of the values of a Smart-UPS's EEPROM configuration variables. .Pp Choosing this option presents a sub-menu of programming options which are detailed below. .Bl -hang .It Option 1) Print EEPROM values .Pp Prints the value of all EEPROM configuration variables known to .Nm . .It Option 2) Change Battery date .Pp Changes the battery date - useful when the battery is replaced so that you can accurately keep track of its age. .It Option 3) Change UPS name .Pp Changes the UPS name - use no more than 8 characters to name the UPS. .It Option 4) Change sensitivity .Pp Changes how sensitive the UPS is to the utility power quality and voltage fluctuations - (H)igh, (M)edium or (L)ow. The higher the sensitivity, the faster the UPS will switch to battery power or activate SmartBoost/SmartTrim (features that avoid using battery power provided the under/over voltage is within 12% of nominal). This setting should normally be set to High unless the UPS switches to battery power frequently, in which case a less sensitive setting will preserve UPS batteries... if the connected equipment can tolerate the power quality. .It Option 5) Change alarm delay .Pp Changes the delay period before the UPS starts sounding its alarm when the utility power is lost. .It Option 6) Change low battery warning delay .Pp Changes the remaining runtime minutes at which the UPS will send the low battery signal. When the UPS internally calculates that the specified number of minutes remains before battery power will be exhausted, it sends the low battery warning. .It Option 7) Change wakeup delay .Pp Changes the delay before the UPS restores power to connected equipment when the utility power returns after shutting down in hibernate mode. .It Option 8) Change shutdown delay .Pp Changes the delay for which the UPS waits before shutting off power to the connected equipment after being commanded to power down in hibernate mode. .It Option 9) Change low transfer voltage .Pp Changes the low voltage level at which the UPS switches to battery or activates SmartBoost. .It Option 10) Change high transfer voltage .Pp Changes the high voltage level at which the UPS switches to battery or activates SmartTrim. .It Option 11) Change battery return threshold percent .Pp Changes the battery charge percentage required after power down in hibernate mode before to the UPS will restore power to connected equipment on the return of utility power. .It Option 12) Change output voltage when on batteries .Pp Changes the nominal voltage output when the UPS is running on battery power. .It Option 13) Change the self test interval .Pp Changes or disables the automatic self-test interval. .It Option 14) Set EEPROM with configuration file values .Pp This option allows the bulk programming of the EEPROM configuration variables from the values contained in the .Pa /etc/apcupsd.conf configuration file. Refer to the "APCTEST EEPROM CONFIGURATION DIRECTIVES" section of the man page for .Xr apcupsd.conf 5 .It Option 15) Quit .Pp This option exits back to the previous (main) menu. .El .Ss Option 6) Enter TTY mode communicating with UPS This option allows direct interaction with the attached UPS using the APC smart protocol commands. .Pp WARNING: Take special care what commands you enter because it is possible to cause the UPS to suddenly shutdown or, in the worst case, modify the UPS in such a way as to permanently disable it. Do NOT experiment with unknown or unsupported commands. Caveat Utilitor! .Ss Option 7) Quit Exits from the program. .Sh SERIAL PORT (SIMPLE SIGNALLING MODE) When using an APC UPS operating in simple signalling mode the following menu options will appear: .Ss Option 1) Test 1 - normal mode The test result depends on the model of UPS and type of cable being used. Refer to the "Using apctest on Serial-Line UPSses" section in the apcupsd manual for details. .Ss Option 2) Test 2 - no cable The test result depends on the model of UPS and type of cable being used. Refer to the "Using apctest on Serial-Line UPSses" section in the apcupsd manual for details. .Ss Option 3) Test 3 - no power The test result depends on the model of UPS and type of cable being used. Refer to the "Using apctest on Serial-Line UPSses" section in the apcupsd manual for details. .Ss Option 4) Test 4 - low battery (requires Test 3 first) The test result depends on the model of UPS and type of cable being used. Refer to the "Using apctest on Serial-Line UPSses" section in the apcupsd manual for details. .Ss Option 5) Test 5 - battery exhausted The test result depends on the model of UPS and type of cable being used. Refer to the "Using apctest on Serial-Line UPSses" section in the apcupsd manual for details. .Ss Option 6) Test 6 - kill UPS power The test result depends on the model of UPS and type of cable being used. Refer to the "Using apctest on Serial-Line UPSses" section in the apcupsd manual for details. .Ss Option 7) Test 7 - run tests 1 through 5 This option has .Nm guess which cable should be used with the attached UPS. .Ss Option 9) Quit Exits from the program. .Sh FILES .Pa /etc/apcupsd/apcupsd.conf default configuration file .Pp .Pa apctest.out transcript of the .Nm session .Sh SEE ALSO .Xr apcupsd.conf 5 , .Xr apcupsd 8 . .Pp The HTML apcupsd manual installed on your system or available online at http://www.apcupsd.org/ .Sh AUTHORS .Ss This page .An Trevor Roydhouse (current) .An Robert Huff .Ss Software .An Adam Kropelin (current Project Manager and Code Maintainer) .An Kern Sibbald (former Project Manager and Code Maintainer) .An Riccardo Facchetti (former Project Manager and Code Maintainer) .An Andre M. Hedrick (Project Founder and former Code Maintainer) .Ss Contributors An enormous number of users who have devoted their time and energy to this project -- thanks. apcupsd-3.14.14/doc/apcupsd.8000066400000000000000000000166571274230402600156370ustar00rootroot00000000000000.\" manual page [] for apcupsd version 3.14.6 .Dd January 10, 2009 .Dt APCUPSD 8 .Os apcupsd v3.14.6 .Sh NAME .Nm apcupsd .Nd a daemon for controlling most APC UPSes .Sh SYNOPSIS .Nm .Op Fl b .Op Fl d Ar level | Fl -debug Ar level .Op Fl f Ar file | Fl -config-file Ar file .Op Fl P Ar file | Fl -pid-file Ar file .Op Fl p | -kill-on-powerfail | t | -term-on-powerfail .Op Fl R .Pp .Nm .Op Fl k | -killpower | -hibernate | o | -power-off .Pp .Nm .Op Fl h | -help .Pp .Nm .Op Fl V | -version .Pp .Sh DESCRIPTION .Pp The .Nm daemon controls the operation of most American Power Conversion Corp (APC) UPSes. During a power failure, .Nm informs users about the loss of utility power and that a shutdown may occur. If utility power is not restored, a system shutdown will follow when the battery is exhausted, a specified timeout expires, a specified battery charge percentage is reached, or a specified battery runtime (based on internal UPS calculations and determined by power consumption rates) expires. If the utility power is restored before one of the these shutdown conditions is met, .Nm will inform users of this and the shutdown will generally be cancelled. Refer to the Implementation Notes section below for situations in which the shutdown may not be cancelled. .Pp The meaning of the command line options is as follows: .Bl -tag -width Fl .It Fl b Run in the foreground, do not detach and become a daemon. .It Fl d Ar level Fl -debug Ar level Set debugging output level where level is a number greater than zero. .It Fl f Ar file Fl -config-file Ar file Load the specified configuration file. The default configuration file is .Pa /etc/apcupsd/apcupsd.conf . It must be changed when running more than one copy of .Nm on the same computer to control multiple UPSes. .It Fl k | Fl -killpower | -hibernate Power down the UPS in hibernate mode after a 10 second delay. This option is normally only used by .Nm itself to power down the UPS after a system shutdown has almost completed. In hibernate mode, the UPS will again supply power to the system when the utility power returns. .It Fl o | -power-off Power down UPS completely. The UPS will not supply power to the system when the utility power returns. .It Fl P Ar file Fl -pid-file Ar file Create the specified process ID file. The default is .Pa /var/run/apcupsd.pid . It must be changed when running more than one copy of .Nm on the same computer to control multiple UPSes. .It Fl p -kill-on-powerfail .Nm commands the UPS to power down in hibernate mode just before .Nm starts the system shutdown. This relies on the grace shutdown delay of a Smart-UPS being long enough to allow the system to shutdown completely before the UPS shuts off the power to the system and goes into hibernate mode. This shutdown grace delay is a programmable value stored in a Smart-UPS EEPROM which can be changed using .Xr apctest 8 . In hibernate mode, the UPS will again supply power to the system when the utility power returns. Refer to .Xr apcupsd.conf 5 for an alternative method using the KILLDELAY configuration directive and the only method available when using a Back-UPS or other UPS operating in simple signalling mode. .It Fl t -term-on-powerfail .Nm exits immediately when it issues the system shutdown command. This behaviour is useful for those systems where it is not possible to insert .Nm commands in a halt script to issue the killpower command. Without this option, .Nm will wait for the SIGTERM signal from the system shutdown process before exiting. .It Fl R Put a UPS which runs in smart signalling mode by default (eg a Smart-UPS) into simple signalling mode. .It Fl v -version Prints the .Nm version number and the program help. .It Fl h -help Prints the program help. .Pp .El The .Nm daemon supports a networking mode called Network Information Server (NIS) -- not related to Sun's NIS/YP -- in which the daemon serves status and event information to clients over a network. See the "Running The Network Information Server" section of the apcupsd manual for more information and configuration details on this mode. .Pp The .Nm daemon also supports a Smart-UPS in SNMP mode provided an APC Web/SNMP or APC PowerNet SNMP card is installed in the UPS's SmartSlot. For more information and configuration details on this mode, refer to the "Support for SNMP UPSes" section of the apcupsd manual. .Pp .Sh IMPLEMENTATION NOTES .Pp The shutdown is made by calls to the script .Pa /etc/apcupsd/apccontrol by the .Nm daemon. Consequently, no changes to .Pa /etc/inittab are necessary on Linux as there is no communication between the daemon and the init(1) process. Installation of the daemon modifies the halt script so that at the end of the shutdown process, the daemon will be re-executed to power off the UPS in hibernate mode. .Pp On some operating systems (eg FreeBSD) there is no halt script so apccontrol must be modified to cause the daemon to power off the UPS after a delay. Alternatives are to use the --kill-on-powerfail command on the .Nm command line or refer to .Xr apcupsd.conf 5 for details of the KILLDELAY configuration directive. .Pp .Sh CONFIGURATION It will almost certainly be necessary to customise the configuration information in the .Pa /etc/apcupsd/apcupsd.conf configuration file to suit your configuration and desired UPS behaviour. .Pp For information on the configuration directives and the format of the configuration file, refer to .Xr apcupsd.conf 5 . .Pp .Sh EVENTS .Pp .Nm generates events when certain conditions occur. These events are sent to the system log and, optionally, to the temporary events file .Pa ( /var/log/apcupsd.events ) . They also generate a call to the .Pa /etc/apcupsd/apccontrol script which in turn will call any custom scripts placed in the .Pa /etc/apcupsd directory which may override apccontrol's default behaviour. For details of the events and customising apccontrol's behaviour, refer to .Xr apccontrol 8 . .Pp .Sh DATA FILE FORMAT .Pp If the DATATIME configuration directive is set to non-zero, .Nm will log a data record at the interval defined by the DATATIME directive. This data record is in a format similar to the APC PowerChute software data file format. .Sh STATUS REPORT FORMAT The status report output format is simple ASCII. Generally there is a single piece of information on each line of output. The content varies based on the model of UPS being used and, in some cases, the firmware version. This status report is also optionally written the the .Pa /etc/apcupsd/apcupsd.status file. Refer to .Xr apcaccess 8 for full details of the status report output. .Sh FILES .Pa /etc/apcupsd/apcupsd.conf default configuration file .Pp .Pa /var/run/apcupsd.pid default process ID file .Pp .Pa /var/log/apcupsd.status optional status file .Pp .Pa /var/log/apcupsd.events default events file .Pp .Sh SEE ALSO .Pp .Xr apcupsd.conf 5 , .Xr apcaccess 8 , .Xr apccontrol 8 , .Xr apctest 8 . .Pp The HTML apcupsd manual installed on your system or available online at http://www.apcupsd.org/ .Pp .Sh AUTHORS .Pp .Ss This page .An Trevor Roydhouse (current) .An Andre M. Hedrick .An Christopher J. Reimer .Pp .Ss Software .An Adam Kropelin (current Project Manager and Code Maintainer) .An Kern Sibbald (former Project Manager and Code Maintainer) .An Riccardo Facchetti (former Project Manager and Code Maintainer) .An Andre M. Hedrick (Project Founder and former Code Maintainer) .Pp .Ss Contributors .Pp An enormous number of users who have devoted their time and energy to this project -- thanks. apcupsd-3.14.14/doc/apcupsd.conf.5000066400000000000000000000370011274230402600165420ustar00rootroot00000000000000.\" manual page [] for apcupsd.conf version 3.14.6 .Dd January 10, 2009 .Dt APCUPSD.CONF 5 .Os apcupsd.conf v3.14.6 .Sh NAME .Nm apcupsd.conf .Nd apcupsd(8) configuration file .Sh DESCRIPTION .Nm is the configuration file for the .Xr apcupsd 8 program. The file is a plain ASCII text file which comprises a number of configuration directives which control how the apcupsd program behaves when controlling most American Power Conversion Corp (APC) UPSes. The configuration file is also used for the .Xr apctest 8 program when bulk programming the EEPROM in a Smart-UPS model. .Pp It will almost certainly be necessary to customise the information in the configuration file to suit your particular configuration and operating requirements. .Pp .Em Note that the apcupsd daemon must be restarted in order for changes to the .Em configuration file to become active. .Pp The configuration file directives are explained in the subsections below. .Pp .Ss GENERAL CONFIGURATION DIRECTIVES .Pp .Bl -hang -width "xxxxxxx" .It UPSNAME .Pp Specify a name for the UPS for log files, status reports etc. .It UPSCABLE [\& simple | smart | ether | usb | 940-0119A | 940-0127A | 940-0128A | 940-0020B | 940-0020C | 940-0023A | 940-0024B | 940-0024C | 940-1524C | 940-0024G | 940-0095A | 940-0095B | 940-0095C | 940-0625A | MAM-04-02-2000 \&] .Pp The type of cable used to connect the UPS to the computer. .Pp .It UPSTYPE [\& dumb | apcsmart | net | usb | snmp | pcnet | modbus |test \&] .Pp The type of APC UPS that you have. .It DEVICE .Pp The name of the device used for communication between the UPS and the computer. For a USB UPS, you should leave the DEVICE directive blank and apcupsd will figure out where the device is located. .Pp .Bl -bullet -compact .It apcsmart : /dev/tty** (serial connection) .It usb : leave blank! (USB connection) .It net : hostname:port (NIS connection) .It snmp : hostname:port:vendor:community (SNMP connection) .It dumb : /dev/tty** (serial connection) .It pcnet : ipaddr:username:passphrase (AP9617 SmartSlot card) .It modbus : /dev/tty** (serial connection) .It modbus : leave blank (USB connection) .El .Pp If you have problems, please see the apcupsd manual for more detailed information and comprehensive troubleshooting advice. .Pp .It POLLTIME .Pp The rate in seconds that the daemon polls the UPS for status. This rate is automatically set to 1 second when the UPS goes on battery and reset to the specified value when the utility power returns. This setting applies both to directly-attached UPSes and networked UPSes. A low setting will improve the daemon's responsiveness to certain events at the cost of higher CPU utilisation. The default of 60 is appropriate for most situations. .Pp .It LOCKFILE .Pp apcupsd creates a lockfile for the serial or USB port in the specified directory. It must be changed when running more than one copy of apcupsd on the same computer to control multiple UPSes. .It SCRIPTDIR .Pp Directory in which apccontrol and event scripts are located. Defaults to .Pa /usr/local/etc/apcupsd . It must be changed when running more than one copy of apcupsd on the same computer to control multiple UPSes. .It PWRFAILDIR .Pp Directory in which apcupsd writes the powerfail flag file created when apcupsd initiates a system shutdown. The directory is checked in halt scripts to determine if turning off the UPS output power is required. Defaults to .Pa /var/run . It must be changed when running more than one copy of apcupsd on the same computer to control multiple UPSes. .Pp .It NOLOGINDIR .Pp Directory in which apcupsd writes the nologin file which tells the OS to disallow new logins. Defaults to .Pa /var/run . It must be changed when running more than one copy of apcupsd on the same computer to control multiple UPSes. .El .Ss NIS CONFIGURATION DIRECTIVES .Pp .Bl -hang -width "xxxxxxx" .It NETSERVER [\& on | off \&] .Pp Turns the network information server (NIS) on or off. When on, apcupsd serves status and event information over the network. This information is also used by the web-based CGI monitoring programs. The default is set to on. .Pp .It NISIP .Pp Specifies the IP address of the network interface on which apcupsd will listen for incoming connections. The default value is 0.0.0.0 which means the NIS will listen for connections on all network interfaces. If the computer has more than one interface, you can specify the IP of a single interface to limit connections to that interface. Specifying the loopback address (127.0.0.1) will cause the NIS daemon to accept connections only from the local computer. .Pp .It NISPORT .Pp Specifies the port to be used by the NIS daemon. The default is 3551 which has been received from IANA as the official apcupsd networking port. It must be changed when running more than one copy of apcupsd on the same computer to control multiple UPSes. .Pp .It EVENTSFILE .Pp If you want NIS to provide the last 10 events via the network, you must specify a file where apcupsd will save these events. The default is: .Pa /var/log/apcupsd.events . apcupsd will save at most the last 50 events to this file. When more than 50 events are saved and a network request for the events arrives, apcupsd will truncate the file to the most recent 10 events. It must be changed when running more than one copy of apcupsd on the same computer to control multiple UPSes. .El .Ss LOGGING CONFIGURATION DIRECTIVES .Pp .Bl -hang -width "xxxxxxx" .It STATTIME .Pp Specifies the time interval between writes to the status file. If set to zero, the status file will not be written. The status file will disappear in a future apcupsd version as its functionality has been replaced by the Network Information Server and the .Xr apcaccess 8 program. .Pp .It STATFILE .Pp Specifies the file to be used when writing the status information. The default is .Pa /etc/apcupsd/apcupsd.status . It must be changed when running more than one copy of apcupsd on the same computer to control multiple UPSes. .Pp .It LOGSTATS [\& on | off \&] .Pp Activate log file. This generates a lot of output, so if you turn this on, be sure that the file defined in .Xr syslog.conf 5 for LOG_NOTICE is a named pipe. .Pp .It DATATIME .Pp Specifies the time interval between writes of the APC PowerChute software-like data information to the log file. .Pp .It FACILITY .Pp Change the system logging (syslog) facility. The default is daemon. This parameter can be useful if you wish to direct the apcupsd system logging information to other than your system default files. See .Xr syslog.conf 5 for details of other possible facilities and general system logging configuration. .Pp .El .Ss POWER FAILURE CONFIGURATION DIRECTIVES .Pp .Bl -hang -width "xxxxxxx" .It ONBATTERYDELAY .Pp The number of seconds from when a power failure is detected until apcupsd reacts with an onbattery event. .Pp .It BATTERYLEVEL .Pp apcupsd will shutdown the system during a power failure when the remaining battery charge falls below the specified percentage. The default is 5. .Pp .It MINUTES .Pp apcupsd will shutdown the system during a power failure when the remaining runtime on batteries as internally calculated by the UPS falls below the specified minutes. The default is 3. .Pp .It TIMEOUT .Pp After a power failure occurs, apcupsd will shutdown the system after the specified number of seconds have expired. For a Smart-UPS, this should normally be set to zero so that the shutdown time will be determined by the battery level or remaining runtime (see above). This command is, however, useful for a Back-UPS or other simple signalling UPS which does not report battery level or the remaining runtime. It is also useful for testing apcupsd because you can force a rapid shutdown by setting a small value (eg 60) and turning off the power to the UPS. .Pp TIMEOUT, BATTERYLEVEL, and MINUTES can all be set without problems. apcupsd will initiate a shutdown when the first of these conditions becomes valid. .Pp .It ANNOY .Pp Specifies the time in seconds between broadcast messages requesting logged in users to log off from the system. This timer starts only when the UPS is running on battery. The default is 300 seconds (5 minutes). .Pp .It ANNOYDELAY .Pp Specifies the delay time in seconds before broadcast messages requesting logged in users to log off from the system. This timer starts only after the UPS is running on battery power. This timer is reset when the power returns. The default is 60 seconds (ie the first request to log off occurs after 60 seconds on battery power). .Pp .It NOLOGON [\& disable | timeout | percent | minutes | always \&] .Pp Specifies when apcupsd should create the nologon file to prevent users from logging on to the system. .Pp "disable" prevents apcupsd from creating the nologin file. .Pp "timeout" specifies a specific wait time before apcupsd creates the nologin file. .Pp "percent" specifies the percentage of battery charge remaining before apcupsd creates the nologin file. .Pp "minutes" specifies the battery runtime remaining before apcupsd creates the nologin file. .Pp "always" specifies that apcupsd should create the nologin file immediately after a power failure occurs. .Pp This directive is important for allowing systems with BIG UPSes to run normally until the system administrator determines the need for dumping users. It also allows the system administrator to hold the "ANNOY" factor until the .Pa /etc/nologin file is created. .Pp .It KILLDELAY .Pp Specifies the number of seconds for which apcupsd will continue running after a shutdown has been requested. After the specified time, apcupsd will attempt to put the UPS into hibernate mode and kill the power to the computer. This is for use on operating systems where apcupsd cannot regain control after a shutdown (eg FreeBSD) to issue an apcupsd --killpower command. Setting the delay to 0 disables it. .El .Ss SHARE-UPS CONFIGURATION DIRECTIVES .Pp .Bl -hang -width "xxxxxxx" .It UPSCLASS [\& standalone | shareslave | sharemaster \&] .Pp The default is "standalone" and should be used for all computers powered by the UPS, with a direct connection to the UPS and where there are no other computers dependent on power from the UPS. This is the "normal" case. .Pp Use "shareslave" if you are using a Share-UPS interface expander and connected to the BASIC port (simple signalling). .Pp Use "sharemaster", if you are using a Share-UPS interface expander and connected to the ADVANCED port (smart signalling). .Pp .It UPSMODE [\& disable | share \&] .Pp Set to "disable" for normal standalone operation to indicate that you are disabling the Share-UPS interface expander support. .Pp Set to "share" for two to seven additional simple signalling ports on a Share-UPS interface expander. This code may not be fully tested in every new release. .El .Ss APCTEST EEPROM CONFIGURATION DIRECTIVES .Pp These directives have no effect on the operation of .Xr apcupsd 8 but are reserved for use by .Xr apctest 8 when bulk programming the values of the UPS EEPROM configuration variables in a Smart-UPS model. .Pp .Bl -hang -width "xxxxxxx" .It UPSNAME .Pp Name of UPS. Maximum of 8 characters. .Pp .It BATTDATE [\& mm/dd/yy | dd/mm/yy \&] .Pp Last battery replacement date. Maximum of 8 characters. .Pp .It SENSITIVITY [\& H | M | L \&] .Pp .Bl -item -nested -compact .It H : High (most sensitive setting) .It M : Medium .It L : Low (least sensitive setting) .El .It WAKEUP [\& 000 | 060 | 180 | 300 \&] .Pp The time delay in seconds that the UPS waits after the return of utility power before "waking up" and restoring power to the connected equipment. .Pp .It SLEEP [\& 020 | 180 | 300 | 600 \&] .Pp The time delay in seconds for which the UPS waits or "sleeps" after it receives a request to power off the connected system. .Pp .It LOTRANSFER .Pp Low line voltage causing transfer to battery power or activation of SmartBoost. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are: .Pp D 106 103 100 097 M 177 172 168 182 A 092 090 088 086 I 208 204 200 196 .Pp where D = domestic (USA), M = Canada, A = Asia and I = International. .Pp .It HITRANSFER .Pp High line voltage causing transfer to battery power or activation of SmartTrim. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are: .Pp D 127 130 133 136 M 229 234 239 224 A 108 110 112 114 I 253 257 261 265 .Pp where D = domestic (USA), M = Canada, A = Asia and I = International. .Pp .It RETURNCHARGE [\& 00 | 15 | 50 | 90 \&] .Pp Percentage of battery charge needed for the UPS to restore power to the connected equipment. .Pp .It BEEPSTATE [\& 0 | T | L | N \&] .Pp Alarm delay. .Pp .Bl -item -nested -compact .It 0 : Zero delay after power fails. .It T : When power fails plus 30 seconds. .It L : When low battery occurs. .It N : Never. .El .It LOWBATT .Pp Low battery warning occurs when the specified number of minutes remains before the UPS estimates battery power will be exhausted. There are four user-changeable settings: 2, 5, 7, or 10 minutes .Pp .It OUTPUTVOLTS .Pp UPS nominal output voltage when running on battery. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are: .Pp D 115 M 208 A 100 I 230 240 220 225 .Pp where D = domestic (USA), M = Canada, A = Asia and I = International. .Pp .It SELFTEST [\& 336 | 168 | ON | OFF \&] .Pp Self test interval in hours (336 = 2 weeks, 168 = 1 week, ON = at power on, OFF = never). .Pp .El .Sh EXAMPLES Note that in the following examples, the device names assume that you are using Linux. Device names for serial devices in *BSD and other operating systems will be different. .Pp .Ss Minimal USB Configuration for a USB UPS UPSCABLE usb UPSTYPE usb DEVICE LOCKFILE /var/lock UPSCLASS standalone UPSMODE disable .Pp Notice no device name is specified. .Xr apcupsd 8 will try all the well known USB ports. Only specify a specific USB device name if you know what you are doing. For detailed information on setting up a USB UPS, refer to the "USB Configuration" section of the apcupsd manual. .Ss Minimal Serial Configuration for a Smart UPS UPSCABLE smart UPSTYPE apcsmart DEVICE /dev/ttyS0 LOCKFILE /var/lock UPSCLASS standalone UPSMODE disable .Pp Normally there would be more configuration directives to completely customise your installation, but this example shows the minimum required. .Ss Minimal Serial Configuration for a Dumb UPS UPSCABLE UPSTYPE dumb DEVICE /dev/ttyS0 LOCKFILE /var/lock UPSCLASS standalone UPSMODE disable .Pp If your cable does not have low battery detection (eg such cables include the APC 940-0020B and 940-0023A), you will also need to define the TIMEOUT configuration directive to set the number of seconds on battery during a power failure after which apcupsd will do a system shutdown. .Pp Normally there would be more configuration directives to completely customise your installation, but this example shows the minimum required. .Pp .Sh FILES .Pa /etc/apcupsd/apcupsd.conf default configuration file .Pp .Sh SEE ALSO .Pp .Xr syslog.conf 5 , .Xr apcupsd 8 , .Xr apctest 8 . .Pp The HTML apcupsd manual installed on your system or available online at http://www.apcupsd.org/ .Sh AUTHORS .Pp .An Trevor Roydhouse (current) .An Andre M. Hedrick .An Christopher J. Reimer apcupsd-3.14.14/doc/coverity/000077500000000000000000000000001274230402600157345ustar00rootroot00000000000000apcupsd-3.14.14/doc/coverity/model.c000066400000000000000000000001751274230402600172030ustar00rootroot00000000000000/* Coverity models */ void error_out_wrapper(const char *file, int line, const char *msg, ...) { __coverity_panic__(); } apcupsd-3.14.14/doc/images/000077500000000000000000000000001274230402600153355ustar00rootroot00000000000000apcupsd-3.14.14/doc/images/apcupsd-logo.png000066400000000000000000000171361274230402600204500ustar00rootroot00000000000000PNG  IHDRH@ x`PLTE SJj$eՆ]hpAIO)5soW|(/4Ty>uGYc7Kȵ r?,.Az@"a]5Pm!m| q)'FJt ~iGEHC0|[1/tg{_6! yPƣMy+Wm^fm?H)Ny獵e!{EO@ȫӾ$5OQǁD7}@'v 5vw|h^rpض `oI/M?R@1;I[:n1=|g˶+irmN '6 HG 5_v!vl|L$[ĭW33avQiT{=/Evgu '# ^?HWq~!mٲp&H/m- f[~ػ>H $})Hʾ$xER Bq˸:>Ij^PAj@ ER${ZN9> J?zHz)(Arf b)X,NڷrHzH:NYKy7%Hoج=wZtIiI)WH`kwԤڸ6V( =OGB0C\<˘E<,vH‚fI*2yO=-LCncGٵL =5(@z3Ed[| AH5MG׋-I/M܂Tlj%} ]0:lo2e'w58ݚt: m/|qPTA*tCrpɵ;6Ń䟟)e#Q!c)'LB-~O H, 5.$EF.S畷&tqV@ [R}.Diqc1!H-H14 R; @ 8z"&ڎRSl@a݂#5WIZs}^kA8!H@i6K*w<@7 =|]1՚YqZyD[\sjKơ(`gcj7BY}js]w@Oc0H zJcs@uXm8cAKӶ !KGhRGn"6JM= f5h-pĤAu™E %@&lv0亁}!Wk_mg'#(-2`PבP c5ې$i(^ G֏ħTxbht.~xѹ ۭM%/G0&G&AYn)0=iI<Ƙد?jOXΫNR(}6 tQdR 7iX]6TOm zH re߀X^[D$3(!ԕ4tdtf' HTuOG$0%q1Gr8Еˮ12&Y|1JA0fq} TptAB+ q[yD6r6fC83fONb֟kk9!85H9hSs!Gϵiq enfC Hͼc2-Hv6 M@JEm*X뺮$) [\`X)1ޕƐؿћ7!ɀ# W\ u^#ݲ zE_-/`?[łE{ ]"V[ sXe\K& =eP7 s0((QTj_o@%^ĶĀW[ǺuHv DDgBVr~DKuـU*JԘ[+XpkBTrܝ_4An@R?I 4 hvn etlȏЁ װڦem y*2z 92@G-T3tGHHP&Lw|D@$EV4v ,3Q3#y)lu> 4c,Yȅ+BAjHCUǁ Ϋ7Kр6r4Z*t4d¿1TOT}Yп-dY :W6\1G7UfR2"T)D#h!ӹOEƵo1ϫ #PUJΉQ4M/$q=)ոb[Ui^a)\G?Kך4U_;֝Vx.ʉGVF^v ICX'$Le0S鉦I+yeq#Svh/`— $|&!.\/L0_j6A9>H&++4cO(/}W Ueƒ,ClX9Yrε VZOAnU+|sWքҸe|ݠGStdA bn3rDپ@WdžHS|:K胄1QT9b,gOQ >y% Ey  Lo7T47(toK +R tu"|n"~7R?{LE# p82"?&li3dBYL @*^r'un+m0ВvC0\i%A:? C,aP ztn$a`YKkLN3Ėq'*DSUaDZ$ ` Ef紑- ]LPEHd'>H_za__Vݛx68'jAMoeoE0UKzm Oꠈy!HWS»ތMG_ȮdH'Ug”P]-a0E蔜 u.e@hl\s:cSpv"eu&GvsyjVW7A$Gku^|& VSϴwκ -{Z%gۛ Hh1 ] SB ьeN$  ~_#*Azt$AJw ]tyלs I| /;:)GD˭㫫cg8^2q]:>Y C:2dzAjxV4IdY:$=65W삕/ yvQ!ͫރĵ I;7$y qR1ݼH]P0p버/Gq[̵1s>©HCOCΊ1Mr\TRớ,FKRvHO ]+~Tiig$nݵ!I?}&߃JHB&pq-i  g72KjA"rd8RI Rg@x (!ubvcu;_҃R}A9m-( ʂܟ>^ W@6]n? K,/ˬ0.<&0ޔ@iE.)}l)OzF,P׮ 5IȜ*oA b$⍵:"ׅ EHF>0O6RȤ92e6v*Dwm" >3 Lfm5qy$iz>YgQص8 ]Q5f%u< =aE-TK ^h=P QG(H,چuJnTBj:=w^6 6D$p>nZ247ɫ"J3"18t$|^jHWI\L%ݎy $RXc]b338/Xr7V.5*wMlh\I7{?QhV_Ӊ%AcM7 IVI_OH*2r>c G0 NEkr0b|#)n#{KrTq}4߀to6=ڷ Yupy^Q,֮qu5f?v ֿ*5Hȉ=IA)=y.m%H^wېE4˃HSY"*}zsJ?oI-HmYNyQ4vŵehh'"Ϯ:[h4PH$^g4>,mi8ۃǘ҉}4P2= BByì"|qhӸ0-$V9PβYvxH.˼4ۍՁogc=fyL@B@HwGs$7SG?o摤ȃ\'컄%3Um__ vNoXɄ/W1ٸߝeh[ƀt]u}ʴzl!HWt\Vo4UZ F3A 5FhUyowɒjT-sakۺ#ɖAPfrIWuAIxl^dMn֊dhmCiF|xٔ͊)ڵ,{u&ہ.@jky5t\ÀM05 6k8Nڞ눧iz_\H)bVk׮JE."%/ˁ\*T!=æKLJQ)U􂈳Sr.ߏh,[IT6^B_ L8//0< }4b5 3hyyPwiիKMTZ4)>G:aR!HR/xl?L#`bE]8jLi wǓƏiD =<=k`BŃ$0鐬@ (NCl饌MxEM60ن-/-A֙9.71OM߯^tC4 qyZƀ#8,~w2-;V>Ⱦ_rRgGkM;0 #*2O#xy\oI]R ڡ/XRtKpHnmCqj_A(H_8Z.RhQTq#K UH,4~#L96jG~*>$L8\ڑzFM2W`õ>dD 4Mp%0R& + ,^isUN=1YR29,xdXۃDVME/XXN_ :]J,H۬M!;AQb] W$Q¡4i] ^DŽV*lIV2_x@fuLKYc˂ژuGt}42S0)"/QWbFۼ {R̹= R)eFM5)ؒrBǀFUicɘ!B&IXJW޾(R4<V%)`n.~K3j ˅jYSݡ51A^Ea'[ɐiEZ_b{4/ֽ]l@]<aKnPttSwEr([SLH o {H3*_@YJ WN$a@q6_:dC7<ٖ.p$u[aF^.7m8MQ )>q!-4vlVKbwN /00/=?Os ]<(}Rk&VTt&% Ĵł]<*ELl\Ƙ0#Ɇ!v[%ތp.Jt|6@I鋄YBP SpCLԯt :zJ#Gk6hر'E8b :pZ JxYr5wm? W,yM67cv7)~rb[1G7;EIM摢)gȨN4R29m./1Y@iaiᖅ$w7fG 罙}/flW͛,SBb•= Gn;$*{Zdaq#a=wd\Bnn%W'peTrydJ%]o,!:u'M{3a3H,z ioylsҡ/\ٲ=lNYaۿLnX.s4XX0ǭ7\ p1gƺ;c$kOiwj];+ eAN3F,F[-::,$R/łn}(des7ȿ( 1Ցs $ǟ +u5AZb=/q%n]9\Y7}~g\YIENDB`apcupsd-3.14.14/doc/images/apcupsd.png000066400000000000000000000173001274230402600175030ustar00rootroot00000000000000PNG  IHDRH@ x`PLTE SJj$eՆ]hpAIO)5soW|(/4Ty>uGYc7Kȵ 5 ^uv\_@{[ۜyoJnAaѫ6ѥ! >,:!Az@"aPMb(ٶꃐѶB> 8#n%ijmZZSQ)c=$.f+tg{BsH t.fz/^Pۼ;¿ @NA7p8vPK^nYeaIW}/H k$7 v3MJ\oN´c>)-G:ERK;|LDz~-HMvCeڕ4rt 6}'b#/ELo ;6wi>Pe Hi4(gK0;(HL@ڂ"n3:铑H-8z? \:|g˖3aIg HG A&X`Iw}dc<"-a2dތy {5 \_~A //g6;c<")n!e|:Ij^PA*HG˙lH9j9z{>8~7n45SQBdr b)X,vڷr0ZCu§[xF(AsfK퐔z ƻ)HZMMKmcpO N0oow,c\]n % CCd>mS0ͻ& kkG(l{I冇k}iEI䃤&~nA*6~ž`XJyq^7B⓻|~nMN<q[sRеE$׶`J;@7~^JRUDSG2 &G *Ұ lW>܂M % G}yHǩ)6 ¿nA‘{ګ In'9ƒnkh*@Fbi6K*w<@7 _2 dWLnf"xVV~g/"+KǜyCW\z0E!+&5lnnV:  K*))V]a! T-I 1o@8Bb8r ~`(50ՠt g6-L7ZIJv ¬C +/Z[S3T Q!v ! Gu$Xhc6dl%cJ6~Rт44YO E;OiQKjGq ~}=ۡɴ{crl2Cѓjkq+ Gy YqbO5N2Y 7iX]6 TOm zH re߀X^[D$3(!ԕ4tdtf' HTuOG:ȏ p +G]m 1cdFKōM)f9 mfq} TfFy]x'1ř1C(}rCE ]fweh\8tXy Eu A @K$ڜ 1QŘ㢺y^IskvNa#K iAdQd\0UU8P)I)@WӞ-\K)^~>b- HV( I{tJSe޻cyl[y颜xd?Z* զKD%??' d(sdL>GHO4`ܥH_y ,K+mQζ%xD~1&|z+JJNqke˴&`1Ap0XI^}By`Ml.'Aː7$ hY ٰ{-s@kA$R%V < +i܃tβlnPƣ)Q٠I1J9lRO ||+cDd$)B^}%AΌܘV(bu*UKMD$-jj}1 STb(A^IC"Cm^B A&xͺ͵enFḑ{3]B.Y eJ#Q}[uM%%{(Ɨj߻dDDG e$(biolÁD4adK+H_ȟQ&(~bJUHՈW+]]>s[n߀!d/˕V30gφjПףSu# {Z\cZUw&S>AVq%j n& I̗V(J6;naXe(D";Aҳ( `2nַZ㱙9Qlz/{;(Zk0LVxRE|w AGz36ArENJ]m#{g'<ȐNɫ΄)a0Z`Y)9Uf=t\ʀ$$Q\o(u&3D("=HˎL.ԬN؍ H`u|y~ ģr6{u;s3䚂؆}msuhThٳ*8L@FTfT-tu'dݨL8K7W9 &a4Yށti^s ~Eh-o"H7_ QrxXe""$󹗦LxmtNO{@gAr:$^@YIͧG )`e6T$.;*y{!$iGt$$0N*n]P[#NHH,&)](#Fm܂,qQJ&z9&\}=wtFQ]`5ל]a\xL`;<)Z )]RXSU)Y]7j6ȑIUނĢIn#& IS 0-r]Ȟ X$d$1a uzsL#\_lcGΨAJtv_**JOT&<4=Ҭq+G8 ]e~nR@m )4CհZ%՗ MSti(nD88]#P/9 [6kK<۵]eWIb@šưAf_R$i¯"ʲS(UiE:+=Az FQuN\#\7j>(RcR6-]UL6hd`/6K%#jS|A%< j+qs]#􆨻* ?^K~u#8N~vp;y1 I8L([m@t?fs+D=YCMRŃ2zMsKl#&>4]R$QU=ܞwm RG,f4X'sRĢm 0k]W$$q*H%ƩnJMqes1Pjђ$gݍR>&B yp[DiF8G$€N $\$USIXFUZ k-F`qy)]r[GWUJU4_EHٜ&E N - o`;9$`d>Z=T$0e%|A`N˻3@ޝZ`$G|~ kSX۝G ~Tq认whk <_6=ڻ Y$SQR:=HknԘ綃l,|?oQCCtۓ'V!ۆ(Hy[TȦJhG.ޜh틯x ˤEȶ,~Uqg<(ڲCu kW|s H4(FuwK@4Q4 N`AL DgcjD>Ojt(9ER?"tAU"uuR76_i:4Lp:FKo6[g{?-ԥlVG.-2- @$Ej D+ώH06n6W%ȃ\+컄%5U4Jv ombq3(;6ѸdVr:^eZ=rcmm:.m_4UZ3HBF2"wbFȁ*yy,I'Hi2dC6{b[w #^(< `cY.\t.( @LE]e*v zӑ/R3Y1X֮$ii]l@U 5Y^E`:0 +gLM@w:i8~جZ==iQKȻCjzr װJ$w_ڛaiץ{z_ݔVs TĥAKt+j݋檗WA"S:+AK4 H}XM} Z^j]ZRo,M gPxI@=L*1IjbJ0ut11]O?6\D-n&Id5A9tN7?26%7 f0?Z3rn<6}_wG_dB:7Rɔ.FWG\i?S43yLnQ4*lSKMTLӄ_<(y2\8X5^`('xU9QdI䰬amY5%`m&Nc_ 8}Y+#XH۬M!;AQb] W$Q¡4i] ^DŽV*lIV2_᯸AfuLKYc˂ژuGt}42S0)]N)tE,vaT8Kpͬoc |1ozafjyռ2+$̓Ks~3jZ,;|uݘbºl$7引7'–ŏgCںytʝQAq +d9;l$~N[Hm[lx_d[&*rAbr_ȵ3j^lV|@2g@Chۅ\>9n*N; ]l!_ԭuw޳H&vVܵ+ABA 4ysg 5j<с`!=M~)tN@wmF&,AmGy>H S97~ Br(j|QλFB_7)vX&莃Kü_E4Uvî̟oN?]k~g\>IENDB`apcupsd-3.14.14/doc/images/charging.png000066400000000000000000000006401274230402600176250ustar00rootroot00000000000000PNG  IHDRasRGBgAMA a cHRMz&u0`:pQ<tEXtSoftwarePaint.NET v3.36%IDAT8O}S0 C#d tI%۲,zC^ۧC1LEH)' ^eF+'C^ QHVd`n;ժ_tâ-%T vIENDB`apcupsd-3.14.14/doc/images/commlost.png000066400000000000000000000006721274230402600177050ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME *:GIDATx͑M+Da , 5K/0ݥ'#Dhi|) (5ea&j" 5:̝(:us_frB=pX}lSwq+rC)MPHeBtJ&,_m*NUEtHd}Lܺ+8vź=9yW^jYvr[.B 'ǰ BPF.e]SICJK )%V}} 2JӸފz ج.(o}6j [.H)[Y4M >0gt ~ σiIENDB`apcupsd-3.14.14/doc/images/main_configs.png000066400000000000000000000326151274230402600205060ustar00rootroot00000000000000PNG  IHDRepbKGD̿ pHYs  ~tIME 'X[ IDATxOHz߿~,9TKFX /j|\AXVMK ٛ { Ae'ˢ>lnF"dr>HkB.))qPjuT*U[zzAyhGz.Srf̟D>0;7 -ؐD2 _pgIOqx$4 QA/T e4]Zp"w<":B=Kđs)s9G$"@pԙ:~'c-C @L@@J $;"PPI"!#"I=\AMd2ݓ4] -X0}l:;7=p;TۙXj ICLǖ " TFus.ww.st,$" }l2yywD {RD$`_bջB?yzХ pOpV`#82쌈:+& G ;ŀ`$0D)p~dkcR.*\HhbIJeֈ9ě[`Ty֥xDjg"5ƃcTցQYFeu`TցQYFeu`TցQYFe)[u\~UKpuL:0*:0*1Fd>gT>@#M5F9 ˕`l;y'ɇ_DSGʛUJeڪGr륪zkl34m<`g pA!URs9}߆((/<AQu0}*?oc45DZ`z󐈂#{3zZ uΛvrXci{G]%oeNfOܸWOhYь--rDjADv%CƟŦgc>16n}2QWPO;#vQJI!O'D挭6ل,~"쨫Қb B=U/(N $ U^&avH$8 ##Xp "X H r$XCXH%(귙q!G𐼐d_JjW{@ogA}f}Ҝo0T>Ly$1wPCh-%pa*)APd nAATi] c"is դ.HeP+)AP c{yR aD/t:Vog8}[ؓ/W?_|~Rӏ_7Fu*n}3ok nWo71=;Yk[]/7cOG.ˋxzü"WkXZ3>s8zܙyoǶ+±6`TE>a&4?4qQJm`p?["pVC Qy1bgX2Zb cj5E4̣[Ycͷ{jC@BL(Y3]ط JvL@VzkՋ9v+Zg܎*a֢|+b\{)K袷oZXN;De)\xKOyU9.|;Z_ÖpeV(3>xHbRoͲgv+UcDbm<9CM-SvK_G{\'gr69~pDl%KZ~Yxgޯ@5-7 PEe* );nZQn~"Y&濋^^'re&3VB*lv]yn }c9S媝pnQ A`Q+ϱE.6`;YmVuc._g|j3iVȎq4GmQ9ۏu;x?g?/geL,`5VVim{_v`y:K^V>]$Czf}Ktm'ydK&I}~g"H[c0YnX rNݾEWeRVDP IRKң6k}N[ѸH֖TND޾%ޓ}g\"ٞy'm4\^W m}݇zܟLثr)ȫmKOQ..TuwL";I|Nٗ 0*&Y;Q6+ר|z1`TցQYFeu`TցQYFeB*t;]Ձ1t`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeupG*C[Tc/6cmo7U0ϖ_r'ZrŞ}kDtDF[N*|4!mvy6$ )}ܞ"|!t4S9#ԩ"lK7P\HvBTUCFDTdX4eǞkʸD ɕ2Q`Yыf#&I9ڮHHpAE+ĒC'Dj#"a{^(s9GL/H${hQ-D :"`/LrbU4J  \#s $l/ND$PP:=mF/ }]EK%A/clNqjX$TlWmL1`0g(ɥ4[`-Y>:0*:0*:xS~eEQЁQYFeu`TցQYFeu``>gT>@9^x۴ܩ1ʱr6Tc JÈ<`et*GD){gE'z4:7~s&ܪGtMy.^wzy4`7g!(yHDD.W$*ik^B? s&ǧ5|{=edpN8;Ƒ|jIGe[3TY )T P"BL,!ɛ~MRjo_! ~t( H:>{m9[l[`Qy[GK6-l{~k!sU;oJTǞa8*-Eݩl~D DFkZ'^۫b'fe4߬hm|9f. e;zbdYiihO2"*b J&Uc.2J@#) qȉATI{Gfx6!_36j&Ơ؂D!lO"&&IBՀ>C+e6`Dҁ#)12 .`AD. *iнE6`;n|f'jUW߃^; 3 arr"{Y"$M!' "ʅ-iKezt()H4N#~BW* Z~9cDxe )EQkGUFW"v7nTIyeQg\j U -m( ;L "\pG f W8ILܮ/#=pA*\I B]`˓=qmFIců>{jxv7?= rӟ~./>o|c\'7g~+&%}߈۳ίsޙVr9w>?|z{䲼?̋O>8,rf)5˫5cl/<1_5/[vE8PӪ'$F@.jcT Xb}pk_P. x!*o3|TlxZF+TbLmfy4c3 }p/82XejUf?JH JOw.[]c}D; x A֢r`ݺen=vt*Va֢|+bN70.!p!*/KLƒ_"L]ԆqZT/ԺejUz0Iz;#gv+UcDbm<9CM-SviΑM0(Pyzk g,^o8ƘbzLf䡹yGuRf(_?_8V1upo?\؊.;8"Ug ir3'@~0k% DΣ%[37gc$TΘX *呃d6#sB B0Uih@L݄ķ/IFjre):0* xNhԕkT>xKz0*:0*\/;rOs\sa05:0*:0*:0*:0*xGT֌1TPilTD$m ?ƃNj?5FyՔIqUPsfdwSE?դl5qtf68j0A\PHF2|QvmCl;׾^s+Sz4s3f9w:ź ,r7`>RDE.jvds&'7RgGC_WFb-T X5TՍ{ GKT9[zf@F6@1<"yɮqN:"$*KqW8HeCe]aEX4N.A\53^ʃj@+(:ظ +A*" h:иWOQݦ?Q<.0APd nDQӸ-wr. MqWPcc_K0 Feu`TցQYFeu`TցQYFeu`TցQYFeR;'}{:͝T1t`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeup%7&FSZ3X=Y4=R1\ ѸL.erѼj_$θ*WkgԴ'fe4߬zO53[%yM\>Q"RB Dɵ|A1~a@Լ簁< xm\/{ּg_%&b7;.j򀌦rc,N5[XEG\ȅSc].a əyد:0*:0*:0*:0*:0*MNt. gx#ޔ/r!Ơ7:0*:0*:0*`W x0\ ˗~:{AΏAOe?H`TցQYFerԂ|bUn/js@*=l1eVYQ1ysiP11"qK{ _?zj`$OJُwPb_v0DeaPIq+k92%tZ?Sd|R\!6)p߬JqK@5)&/.Z 9Tl%M(D (;^|WU㙚'Űz l8p "ag p۶CΈg?}X)XIDAT&0+ QChU[jck~pl܇ ~FdksʂAfW+*Y[TϢ /ʷ lN҇?he Th4N0Hl"_ hɖ*pT>gX hSX>!@DZ 섨8/b=λi:U&1i S~ʰ{/;ܪeA=)xŠYpDw3u~t PS* WH -1QZP.zv$x?GŽЄΙ?Kqaѓ X,":`AQxwT& MsΏR6TYAHjozw [9pR J?BPITp;&6:'ݳv{˭v*o'O͏POOF[Y3J8p!Ie /B^ N}z4F5/!yKyғDwU}{R7 _ I 0ih@LW^9ռN V߾oUam֙J/_6:~\y|Lk7o%Վ%"nܡ{͟L^̲o/ۛN=Bۻvڱhx3Љu~OUƼma^|;StֿjhieaeDT۷%BF (q$<"neQ5M"PLBtf*>|lN9aZ_ÖpFD-l6L|jmg'N{xws2cWRY`vuj6쒥X-G o߈+!b 2}MhT<84䗫\6t!J RV[C" 0Py1bgX2Zb cjNg7"n<]#g0V[5,U:F[ %$*%֢ZXUH.1^\ͼ^W S+k9z+ .ĹʌHGDt|mz*?[5,!RC>遫^rg/Wxŭn[,+SȟP5ɫ Pg;`DI3~zV @4CJb=`^{m_6ַ:c0ֈVx3m w`)QJ0.#6ϷGv-5֭+IGKay~/ '"RpEin ż3&c_{:ѽrߙ-'q}lwUY*g{ά8 Vqћ縏rRIqThƱG3l<;[`SKLђ- X f.Nίr 2A07nܷǷJL@/>u)T_|_V06F?+7|l} Mܙw4TOʝPYxe̾S8=Ue̽jUٲȘz*Cܑl.'>ί^Tĭn&#]o5nus5=uMYܳ5kkr*MU}|/];W[w!|'&}tM^ܽw5kr*CT|]GPy]+0h*WkOvS2 "i4.g]ǎ\h^5ey'yeYf h^ԫPI^ξݢ"h ʄu0-wЪ !JAR Nޑ [2km2`9S"{b7jWyZ ]vd΋L0R_T 2iZv|gǣyYcLk*Ok*Ok*Ok*Ok*Ok*Ok*Ohd1FpId~e]tƋ:^y`2]ʕ`l|Am}2T#SHHJS}6ST:7Lmws-^>WZꦉtM5Z۩+"/GlU |lzb4߬:i~}ӠT&]glǍG!6j4J5e!G,UzMIwRL tMmgl s {dm%|X^<9PR4*鬍9R$Dj @@\?E5 zH1;jϯHEBDk^\SmϾ|vVLվl8QYFeu:A#!8r b;4 {z~==:^:^:^:^:^ sO{NJJJJ-9.mrOLxvrz;^)ίJRz;^)d_B)ɻ4uwq>0}V9MT$mIˉb=t'$`7~ͯc>,ǔO9N!o>[sP_PsLI B &D?+k 6w $`FSRs<߷s f&,KA6Tުa틟6C1*N.4 :}"\ Xj` 씅-ӘsZW;-yQ^3Ăq2kz}3 @zz P eZ9^3)ץy]-PG&_wU,g9͂'H$q)}L90(k°F<Q[t.hCF:4Q;(.z,W2ePE rDYBxX jsV4LDi53)3!Edũ{lСwůxq=A@H11< )/I^ND R 1js%~e824Ȅm((ǬǨz{5+dTP`L5`Lчtan`L <bgqM6I2&2CLL{.T'_Թ~d{k5 ALtFY$JtOXX ~xyʱ\~I%XʼZZA&jo$V^i"Pxż1 qO_0 >ȅ0Z~>~r2c?d/$8L/cω$̯$+/#:.1 =ўIQXJ)7~H8z]ْ#in;GQbs7oH4_&să8KgF _`sc(Wpvʆny%K"{BXk09i&&e`x 2ʊZF,Zc/0ţ06L`2;ϪfƱ|ʑq+%c wuQDw`K"1 Ř9$?=_yW¤% _1?ȗIN)k^ |բǒ5M~ywůȲU;ὃCϲ);c&t ͺLz_B|=-2 cu~~9crS&`RU ^"Q1^ &)V9,)ƗCeSWNb9~eǯ V9 P^ u5VoBA{ٳ~)++p~t gZW2H N6is>eD5`)(YH _j QV. ϥ>eJH G#O4y*V吣M~EeLbIQuJMYGI.UŝYK;`9iGVŪ  <81ʄZu7ðdb%JpKFDܻa_+YU&p(R+l"၅i”4&f@3Jplt`0zi7',RX TU g~9zy~g(442Xi.q|L.!7B#!sdFNyz~i?/O/?~ɔ nqEN\@ ENt+l @SzIge$>ÜMy</߄[T*8d(K!T̅׊^?ͯtM~E;sj _5(k^Yn+rUi1_!ҦjڦWucpqKrU4i{_S{:G 0k~ڟI8Wq(UM N.hMoTES伃l3\\ ]DNAv)5WW%{Z^zv6ep A옘;{zqgᘖqFKJ$ljL8 {zE̿.D rpFuM۫.\6~F)rkS=i2~`c|[#$@!`Eq \IOe S; /V>Kϑ]S8[:qA9lh y.:kʎ^hh{_?eaKrZҋ6Ni a2^{pRM~i Q5-\QA%.(S_\&dVX +DtVM 뷎_AM̉ä$V!Z B/@:_\ #>ԍ.V z/U؅s-6-|GF!ij/d꤁ ΂_8q^1a'm^2 7`g2#fJ:KV B gU@/Ru_'-Q'*uSW_#Z+Ջ؂_xwA׳ܞ;OYSү_n0Q4&J S*Í'"8$H_9C9\]¡,LId ]+?X)hRz;O$h඄ <b⟺'*!xUk .OzVxx ('ՇI:2;K#b`D'0̯l ' K1A:'&dprIU ݏ{_ĂD 'z;~9ҁ_9LBKW1VٰE\@a:bʧS(n̩R:@(_ڤKΘC_ TA$aN_c{vs*7sM~NjUf[.e_$lKǜhSZSR'Tjy"BYn)m@KE_vd l]*oe*Q+P..zNJi07T|"}~|z{y2^|A?jsA?.;M9?Y% lI+Hx} H-1x#/ aů*huXS {z+x)^˚_+|hѪx\^78x 85^[xIϯ{6m5lvD9-P:݁ s!sGXx<^|nU x-;WDbs[? i2F#=Ƌ#.z$ZGuK & B7ϮK{DCVh.՛xmt.kPX"I3^#I.33(g&YeXG̈ /F xï7}sW_[xIY"F`e5y¯udoK=1mnx&ׇAx`r=/]kp m'5IoI1>`ċCv[Ï{zkxSo5V/bCp'^7G G3_c/UCѐTޜjͿ<ޜsm/9RۇGm PX֖}8yh9>\և/024 Zx5^ҐW֌DZ ZӠo0%/]d|c|/J [%2rA-m|/m`=C)5[FB]H}pC_b_x݋g#ug;u~Wǫxu:^?ǫk_^v:^Wǫxu:^Wix[xʙmY'$2Žވ'2ל'|7Ou.]D^Ot);>W9«x3ފ'*[Sׯ'Z5,K4X{≊W7E EDE)ȉvXx%^8=쇍Oq^x"7 2k0[sx"ևb밊-MDVezaP .y XOd`sͽ܉p'^],ERZE)h1,  5z/1De"_ulo'ZUYpoջw} F >d-MDp1ZܲӇT78HixZ,OtUL^{'2yڌ'z3íUꉶ'*?Lt^;'re;;u [x [x])QNבC-JTLBDlu4B ^;' CDG㢤lLu/D/poyvO>I|>DfQm DG+Z_)y<u<6J,{{>o|^8%*x9T.C느:^=DW'z-ȯWǫxu:^oëkkkk^=DxVxVxVxVxVxVxVxVxVxVxVxVxV/6pCh=IENDB`apcupsd-3.14.14/doc/images/onbatt.png000066400000000000000000000006201274230402600173300ustar00rootroot00000000000000PNG  IHDRasRGBgAMA a cHRMz&u0`:pQ<tEXtSoftwarePaint.NET v3.36%IDAT8OSI0 lhU8 qȍgk}Z?waƵ-%TŮ'Mg\ Aw=py|RřqAF$$`829YfvY;e/,˫A4UAIc${?d *dNPꟕ~ Z`;Tfw ƫ!r#!XwDnF ̳N+x]@!.ZNIENDB`apcupsd-3.14.14/doc/images/online.ico000066400000000000000000000021761274230402600173230ustar00rootroot00000000000000 h(  UmmmmU   a3apcupsd-3.14.14/doc/images/online.png000066400000000000000000000006631274230402600173340ustar00rootroot00000000000000PNG  IHDRasRGBgAMA a cHRMz&u0`:pQ<tEXtSoftwarePaint.NET v3.36% IDAT8OS $iG,1:d;!Dj%b}w6֔R)=>- лj>{>5tM%Aq f@GFjoGp)_ݸwxqd^*{-vP@#&:e=нF%g::JA%&!h)xVR~uXzNeJ*{Ot"|߅ӈhZ;&% ;3 'Vmi=IENDB`apcupsd-3.14.14/doc/images/status.png000066400000000000000000000177571274230402600174070ustar00rootroot00000000000000PNG  IHDRN|;KPLTE111ŦIDATxMq`ګloro m36~Z,?$R{LIQ,XWm8!pCԇS~ǘӫ/PQ]pjZ]pjZ]pjZ]pjZ]ЅMσ)V/9=l ^Uxԇԇԇԇ sهJbmH[rn0}Nt"979'y6/yu7{sLs*+#٘ћc8=7?do-fNCilfga^zrr} E-r")R1-rbߍ4EsZd>ז<_,X- 6GLYۑ2'6C7j=q_4|6W8=i'cD©`nB2&wZ8L}/!;[~N_vӏ6qby}/}d^R3p'r:ēr?.N u(9ۏOgקY8i~}*qv}:iPn޹5c$맜MfW '䞑)5iccm/^*%'PM;{d!S6d1gDGE# kfa}(r*(] -s ,]tR88RҭdIe1q)4PγoJv툓bfɹ<ӡyfT Ɂ{bnW): xh|i M9g9i=]-s/2,pr[yd+QΉܹg8eRO!^_7-p=sklgeN9S_݉}R|\pYsqWIY9㡂AsqkFO^laJT>[Ͻs8y d׊E+AX'+!?f8mx|\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p܌ӫ܁V܋Rs˜pjZ]pjZ]pjZ]pjZ]pjZ]8U~BL]B%^7xgSSS~h6˿%צCnm2_{gȦ q 4z;a\Bֳ$4INIྷa+sb6'b39D!oCuNqZQ1++pDCQN ڌcVD< NG9I8:5-ؤk~[g?t9i+8M&q߷.&99/0pb^H y=ބȔ.Ir=W2f8i\ 8M'"V)a5q9=<'7IQÍt%>O}*3%>T8i8шK9>5ӄ֟SDŽsF$i}N>L|d| {N^i}a:[ft'rJ=I"dv)oB)NTRO\U^*c?Arm }.mdt; 6gO!ۛ8r(ڼ~S-N %N .4}mGT|VHRpo32d ?p:_d(溎>)^Of|FIJƁ&e'H|R3Ya4eXpShC}F)' ,Ɓ%:SNVR姙'9?*/O x~9Ym=t5ܧT..4đSFST;IUT!'d;^Q~?krz  ˒?{Si?:N}N"tSeg5$-t,نJ/m8pS?b|ίi)ԧBp>etL6g > pđSe~ЏXNg9Gf |*~98> 圆Ns$p'pąX,58iYNdc:X{3q271o:&eNF58[0i. xxgJp+kS&CzU礏`4R?EI̽OHNy/g`OdivgroB̽}eBϭt>={zN/:DTUn&}{Nzx'=n%;rJ )8k}[N4V Nk8SByqYp3Jg_9 qtfN6vNiܜa(No#VNs֨hөf#('SLa28SZlrJ8Qt8>eϯHa<3|fep=O7闋yB~N/888888^N| $.¨sYf&='&o|{''sUb p:ɇ7$4s_Ed_Kp)Uk4_}koT3UOLc}4oS=l ~a~ kӥ5׆#ߑSj`ENv qb.8888888˩4!M̭+}y~^Ӻ\kB\}(\(֏~,Ӈ82W$VImAd!i/X|qbM~ 19 P8]I5RFY5NLSIڑ ~)}3s <Nvi4ZӞO N1WCz88888%3NQS_Ϥ w'188]Sh\5O:D>?jkUne}אqm84G}Mw)'tO} &O)35NSTהק ֈ0?jkr8d>1yNkN8?*5YEF?KO\u N7'p'p'p'pNNNNN‰59 CњslI򖜮]e'9 #'kYǜN Ӝ.ʯA6ُ׸> 4`>ʜ 8D#N81eix.#sp:MkؘB\nCxGWO?pp [SX?t d59!3*,'sl|' %NrIś8(֥8=R(8l_ȍiTQgksc67s*b0KBr C;OfK`N楜pI|LqsqS0/q5^^T#`˸Vls5s4"v}~ 3Ii<:fuiCŠ's ܟOZ3}]G91uwtE4T'J¼ ȉ.D k9lX8Oa])TʜE\_ܷ{FK$'V>[v$/ɯ!קXwsz_Ή_t}z1srOOV}GNƘkpxD'gm0X'9388888}y*,("18b.T? BP|󟮬O4?q]?esF\p_?epq){Nt'ނP6'sYb'=Oԧ ^/p:iប͌Iuo|s N'9Sٺ>FcNn{s>';q'b_cYINaԌFQo= #N#Z):hOb/ٍ lKӦN2 ilӺ pr|qY?X|8^ 8n8|>O 2N[Foџ888\NNNNNz9Dvz}q4̜1M9vx;U /+m8~CsߔO}q%e' _N'l?)9I_9̜18'wJ쟝8-ϛ9cp^wOq}}SRqrks4oMq}Z>11mCT?"nܤDӏ(+mЯGpp N} N} N} N} N} N} N} N} N} N} N} N} N} N} N} N} N} N}qф܁V܋Rs˜pjZ]pjZ]pjZ]pjZ]pjZ]8 5?.pznR pCԇS>N} 'f- tS zvq*v kZD[N/FN.d[B Ԍ!ws5lV9T^\Hk'k 6p"<>R^^_ kՇvg`ӿh}r-dXS'38EWY뜴*ku]⅋p}ҽ#ʈ۸UYCԇS>N}8!pCԇS>N}8!pCԇS>N}8N zrfkӫG_i}˷/pjZ_Z8= J}Q27,en N{8y4Ӳ|??S>|M쿓Ԑgn/wqonŌx~?$sm :Z[2c]dل{Β_urqbN=Hrsj"'aٵ]Nڦ9Nf;'W&q-mbTRr_1{8ٜp}<6'9IZOR?o,޷j4zod ?bʦk+W__OK~:IMp9LIP#?qx}v'>Qv~)SzƜ> vwm"#8iyS Lx}vq/VFpdYOaԇԧ3't)2zgv-jO}:J}BW׬C<6]ק'ER2XޯljMlG1(WѮ SX6P38~-jw}:J} WdLF̵Pdj]f9Na,t>?>O6i8d2|hQۢvէ'tIG1ߤ9Yb{l3665#>z3#9[}TV>UO}>!ԧ>n'3~{?kOHmL2%vhSIo8zT;tSֹN%Ѹ)7&eu*K^.t}m9龱koSM?>mK~ciN ƩO8!pCԇS+^?AO7q7˵OS}swiw|S'2"֓wISXgX8l9l}P⅝?uɏgCUnpuY?8*Y?Q9QGp:ۜ?QIʵox{8U?Q/?yL&wwS:"ךmWoӧ Y!ijCȧև^z{WFԽ?xP5FJw~]wϽ?1lۋWSiSloEV܁N}8!pCԇS>N}8!pCԇS>N}h-pZCi=tCi=tCi=tCi=tCi=tsgE9A 8!pCԇS>N}8!pCԇS`-)QrIENDB`apcupsd-3.14.14/doc/images/thanks.png000066400000000000000000000371761274230402600173510ustar00rootroot00000000000000PNG  IHDRqVVPLTE~fffJJJeEBBBL9:::i666#2I0!"*:I.fᚚ&&& )^^_epVFbvvv""%NKN>nc 2]ZH`v5Jmu>;l@>AZ!!&D5*r0-N R1Lh>Z~":FFFf`1?>D1>V~&f\v,*z VB0B nJR0&GXP1?R2fhUN.TR'5=nUv e/{pv7Nr.D\PTx#1v VRrhV^ &S*:T" {04XXXl"":  =Lv"E (/Ba2?4o>*pIf<=FrR[>UP$1n ZNZD,X;2[X]:) &<)E~z.zt6,^2Ff2 t~.zi \3"FV fNn&j(*H'G&6P:Rx: r^ b2=]w*>Zr Y)2W3"*FjvR e> o9z* yT=2 v.>\V\Jd 82,!*J jVbT:=lR=>Z b(#&t#+G(0/2>&_=YCBFO"">Nf bYjv{v84F l& z*:%CCN|b5v"04Kj6%"&fF&Vh`rjBBC^. t*,L&*PPPN i>> ~ ~C;mFFvCJ{Bvvvj&:O>" !3FkD;^rb `6 r bKGDK ;2IDATx}}\T癶4B!|4'! 6EFe!n邱C'tP,]݂ӼkAe 0qN(1d7"ɀK`$k1/cg>pΙ3gs\9I!£: "M>mUz7| ӂ(Oc Q\$%%`KIuEͯ5cHr&gx S|G<\9!uŭ6.x>.ƉE^^q< R)2^(>~G~p#B[R2\ԡ}_W|L .bbQXOI.8ʕ["beW{)q²l5)7$K [ЬH$~+W0$ǃ!͛[P:pBTEC(~L$nI 9޿u'4[$i0n6UP'=@~_u@rM! }>&z?sD(͏ y6CE4k<V}^IHFq!|9l4_IJpj4 vzP*뒒BpS -Ȭ lP hL~z@[ЂMg.^<лW.YH-GGS^Q]-Rvu*i2lgQG!!L&ZKSR|g7|ŅnBCM*R&ܸH`L>AVKG4}7#!ؐLBqVp'1rurBsv.z/LQG>z't;FG[z1ᨆֵKn:5xZ|a^`:C& b L7K;@i\XY@|lh(PdYeb*>:NϦ̦1K{+yy/+1#SO WG \L~)cIKѬ~ :!=T)!-,u4a2n*,&q¿+WBTS{w39g_)kc؊'/@ܯRlq=}}) : AmY>D{Q/r!V=2۲ʯZm9NDtlWi0^=|q7L*8skB[ 9fS|<@q78KY,ŝ0*4nIqn. үH$(>VְqBL9v#v W1I).U|!p' hZ:gLN&[_-o$[u$Ge6 .:Ù"4")NE?ξ`='>XpU N!*~E1\,FE$ҨB&6Ȭ{u|h2iq8q8>8 YY}`??0iQ 6?U$Iwu~oKZWT0T.$,)-E^R_"K^zTqF]Fe|GnD jw()W #^^nQQtI 97|C}qsiϣ [DRJϋ}ˇ8!@ܢ&O?n)ɸ@aחv\v9Nmef(E_^rO/8ѻ=@6/^u0\8/G yssvn6pKXFdbEVk.?x96g3+vp\E y@\jJ|S.Jhao#U(B~^av2ν}Oq"~_%F-ϱIŻIdz})#2PR{JLdk}MJK !]oUI .t 6>.2}RqP8^i1O6qudLK{c!,7D(9Nqpj g`ae+CtxuZFOōܔUWV<ɉ(ϱ~JcJHCV&*g(??ņ\g?Z~*.h7DOڀR([ e_R3r'^.T3HAglFǁfhN}Mv,.lC$- |(`p~Q\qǁ8ULkg[$ccchf[/%3Sa>sRݒNB"9n";i%aIeXm{@WF_5NC~e;grmޖN> U}&,oa/6ɂP&*q iL9;ƈc2q}r gLxLNÌ^#l Q[_1qp_o)bWY YYVxFPF<,9Q!~O(KoM ]-J[wot^S9ui^7 QFXmm.~z x ٤o:}ի^u3d{5CY0t/5/ }3*5LgLV"ȱdpֈz'sPR18tW/8Q(Y_!H1ӳ|#Nr7bI̮Dq\qEbΌBoO_ĸ%#&ͳ2.8NAݑoBƣ(MITo"ďgC~ eFM)/כ&0Ѫ2Vj-C)d2.[^pCZm~~~ywYselʪyao/jXWܛjk}.:&7ׅBOk{-<;, cx̟} A7oF  1S1btD(=Y&&6r,zn X%Dž pirtMY r|:kJH[RR cx*ZSZԷ9T7p 9xSOKQPV[ tڴi跓y 4jW!ȇjv M78ӆ!P8>@׾=͕DdK!) t7 $+9558[à'~q?U')Br ~?Ĵ^L_ ^8%q?L`m >E'4/WxDo#S䀮 w(jOZMG\rW;H>,}YOjY!ON&ubP$(>gHTPcv] 5)ۺZ*Tv8~]u^:JKهv i|D/ cc٪lEqFX><Ù b6CQlk[Fd'&6d &`LB WLC}qp> 9Yr1a9騝d j琠?tCCT:P} 8TJ1tlܵr8BJ4oFl<wJu2(aVVPCݻwwڲc߾\@x(EqTkX/$x$*:9|&*-«O-[VwTRmkZrzδؕP涒~]UV괁7jȊrtg:"d= |N8gגAòS̀lJEMRA6=-S{?s4q $8kNx_EV/.vŭ2ZG_8KQQG 87SOc8sݩO>ڔ/Oygjj;*\ڇYm/N 6iĔ{͝ӄ_qyz10q %U)ٔ52򍦆7NqPxY9.(ӯ) ,]g#odB`S]0$* xB%KXU5|bEcaБK}'Q<2ˏ-y_#:j8jgp዗ &WJQ t<3|qPl&# .$S<݆WZ_׫{5"rzVrGx! T%DbzO-ZNj5G&):q5UXx rg2L&?]&S|?"gcj!nsr1KRvݻs9o'Igq7y:NpL۽"j)x*O0]q;v 7sEQvV[oA$ i1)D@U}Y%ݕ Vzs N"IZ^0Ƀ[Uψ?$gI,,y%%8XM".A\je'_m%\1(ֱSL|$S\r>CUd!*u<#Ei9i_E-Ĕ=6s604 ߓTs"-g,f)Ըm}sx y $D?'uG hI@-1&3D%Hq1 UѓARG?|)ye9oҥI *~E^O ̏su,!ap˂v@i$D*"w)w9 6hsBGp|JURo'fEqEpn9 077\Zqs0q_Grj +o r*1|(w'ݓ\"1mG+-qD|W&/$4ϏsvY3ꢀg\8 %l < TbD/f!r~B&z-9pPumD9> U,wqu[NC9rEqqb8IW(*G#1A9NQ*r>yi'mǥ8.{z?37qp\Upz xcHیtf)z>yyÏU^E$''hߐVހ[F[L*D H_qI ^rSSլ*gIUxDWa K @ȧ@b"Ў,TY,/LE" {we{[ =ɯ򕲘Wq-gkNXh8?Bt<9N Pj]&nb GONܛaHe"8y5QpXtvA%6g[#ӲKb ҡ+|Q0 G˹~Px\jR\p|^l1"P|Ga0^ZȁynE.Ø_c)Q?!:.nW*d'M!>^ck^>EzT㼯S«TWym~U‹¡)=N{84E>,^AǎUꢜB $O~W|jVsuYQV:*qvbx͛7-3;~[c+_eῠ}"{n_gBܠ!ċms݄ɯ\%~+Lγ\%kYyeVq!_ akJ0O_r/=GeqMڒK,:E4[CIsƕ t/ϻ|{<#Snq݁6hʹ:mf߽u/x:AF<}'Lf7_?_T4e{x79m%(eɐs~ΚUIxu꩕x]ɓiQXg~vdUqH8Q; pu~%_g4_M̯W`5Vt-T%o.+1=qײGbcȎ{姄8-Y$qūpB1Y9I^/e(5r0k''C6kN]8ľzyR "XS0lfɊNt+ӓMbO<_߷mKVt|>O@<Iưb9lVyIF f_*<Qp]ik_KTc%j_B!ߎAVà 9]@Q}Dt|W,j˔yUL%6fhhcvTLʾ24^-~2b 9tDvAhzq#;ǂF8!V`QK vuj }˟-a2.HQyHO׉ojqL';؏8Sq+++ѫY?KX'!9^~70 SkO`(\XR_FF܆6Κged*"#s`QY侠n T1nIDM9 L@'rC{1g&r FM 2fijG@\̓Q85j@Y.溡q=Tr=Og^'Z/B8ໜ? h(PRVɒUF7U7&"#Η晗1ɢR>M"fÄxW U_G'r?=vB}']9 |Ǒx kR[~uhn[߻p<,z`K1Sƫ *mj(tE+{bFo< Q< &_oK#HBѝ x奛, d'U]  o'Wisz\]zmyZF'O >ԶE۵mrxQmP1EAJΎ__6F?-8.[0%NBt3ǛyI hW==fYy>~=O;OD?;^eI@v q|eJ7quÕAw oQ|Ar\h_{fZ>eLV_ZRʸq0##Å7MTgJ^/Tg}ee:Az55oYr& } ;x{CFfsoʃШQy'~*6F.͛z팃oMwdA6y[Ÿ-:6L)W&^ody%' e_kbx2]/n#bIK?{ߐs^mlQmHMsKK\ų2R4ESjϭ{zNO`/kG<j(D!w`EEF#5 YO9}S(j{\!S6\h4hƛ7#s#{bRlږgjXȓU,Ka~p10^,_mB\:(U2/wcclȧ'"[@_gNawIOgeiS$Fڃ>_ j$bF|'V^-ٴ 0)wѫZ;֫}ua >j(os۶M}ZLaB+hϾT= ک0b76<|ïP7W&( {NU1&9C5[U8XL/U8e>w4}KG$WDuq ʏQ㙙ˆ[,%^rTW/[z ;^^}oaNJ*U)4q=!N|Q.~c!]L ʴ۷ک C bwa.nY~0\ȍ`Q'ćSr3`f>C> Tt䗛E@^;HL4|jsjjC| yd-gsP]~`dDTJF܃_ڸqyE`8JV6pn d쁩WIkc侥UrоȊb?SSn?g>/c Հ'AÇPoEgQ|+}?g>w]OJĈ?FOyÏChٱs£8xnSOfn{➻y}qߗMB}m ";O(q}';s|ǭ{˯q_p=8C~P8J^<Cٻ}>җ>x|K_}xm-xC`CzzލO~6M;ΐ.5nqX_ٻ?[%L}S|mG;8߹t|w>&8Nn;h]=XH? [< n%c_6N.C;;օ{8/xG ZH ޹7k!V@B(? 1g-rmIENDB`apcupsd-3.14.14/doc/images/wininstall6.png000066400000000000000000000113561274230402600203230ustar00rootroot00000000000000PNG  IHDRSPLTE{AJIDATxђ*9_صJO> DbcuF60ճ !v7]@w o+AP[읿STÍ:}'KBy@u exMKtTHWޕGqm~Tʦ:TҼP@*PdEOEE@U"_y UwgDzT+oJJuNu~?]j)Jڪ D@""\ """""""""""""nFv kk*О1nc'\@(zR”.0*K~樚TFX׫{?{rNەr*ԯ+aJڿ{tAT: )o|SJiYQ =d{ S ZҦ &&YPmh0yڳH@{V*(㝵fԅ@֡{_M@[C;([C(^u FfN졶P0kuTۭ-)nZy~oE]y@WʶhE&׊cyW6 ,4F lsE@Wh鴉tb'Q30^O_>P*{Oг ? I@7'$Lȿ(d#(~&8w< m:K>KTv6o[N@6ƹBoQ6x}}DyP>Ah7EPX(\6S q>Ƭ?^3%uDGn3 T=Z@t">`}/Sm:к@ovPA=u:|^RE(^˧T(*RuflP ,C+PzTvW*/Gx&S^Z-PTL6!AdM&-0?6T@*t<ֵP"F/WJ {'ֵ0j23лXj>=uo[*p:2bZyn un{!V~oЃVBV//c]y= o[%PB1PU f{(fжTz:PLg!W" 4O$ ywyz:g(7F7)P'g8~V{>qJV^:<0AM d&&Z=N)t; A8SKzGR׍F*<pqJ˭yZ4[4~‰mP"01JR8XQ&J=6lCݭ(qJbKpzɽ{̉=7h8%@4݃@ VDB BYm VlKW|" %Y(hdt*[R~>:ncrOXU m88Ħ.@Z(lE@21B.;1 .(yM)ZS&6OFzې. xb`} ^NŸɷwNPa.rmX*P)2|u p"p0}>%(,"Ӥb eEξ4@cPs@ \VeŅB]BI({KF@>4}J@Z]@j*\Lۇo]5M+"Ѕ:Kak],Ԟ;O ͹n yzԤZSifkߧ ==L@ ,"ęB/-UjIRꑷjZ&qd @@AzRCNznGr<*PL*U%Yաj:"/?E@s*C 㕊ɧt-{}w%l@EzNȫVD3h7&Sng@Shw*\`Mw^2.6Bmjzą[k^w%p)6}Jyn МO)j|ϽNtE@)Ej|I{I4F5S1Є{"ߘOI̴vuȽ4 >%9w`&oM@i3h=BqE-P\MPKsDRH|G44.א}J@G"gdr 1D_IԍP,B b\625$L?xt=(@''5iTO-2 zMtF5$L/_u8ہމCOC$$/&P8)pynf OU*P=Q\jNև_DYc?98/MP-͙zJ5G0/DiTWETe=#Ћye:9΃Te=2@3+:&-T Λh}OֵP[Lc2";| 4[j؅)UBtT34ܙxZsr}zJ@cqW% E`,Wd" Y(BqU7M7>$}yYcqXco nb#"7?cjG (,bڗ9LRw l74}_N&z\?}2XC=5}PoC IARO|Pqʝc飀:͘A=ОM@&EcաSON͉Լq@+Ϸ~ ,t`]Ϻczм AQLz 肞j:%v@'*lPFu=P}bZN7Lk4]f;_.aPARs+qQ>U<)9eИ]d}q DZb7\sii&}_k\+V}{%jv^5GP~m<3nEMkjT Ig-Tx@%3󫀪O As+<4]0Z>Cj@~I6'nЄ tQBӘ}h 4'-aO"mî:*zED[J ?SmocW@IEEEEǢW#ԝM㘻pi^'D@SZj0Ub1^"FQ0Mc.H}]*O5L >J@S-wh!*_@5_**hJ1P{fE >J@SZ:tj;')ѥ'"f IG hJd"""""g ~0G0gfP)h<Q41]76+n$:45]Im ߺnChK~+D7JѼ%3M5tyzTB?"`T\nChKщ}<] 5u) MZG*OP%"zE@E@}m-`#" 5s;t;s#֢#1uʅ5J@ h PaHC@e- n: 'VJ@v Ju(&Pjzro@uJZhV ^aF6L4oqF@I8""""""""""""]]gﰁ_VS8ҌIENDB`apcupsd-3.14.14/doc/manual/000077500000000000000000000000001274230402600153455ustar00rootroot00000000000000apcupsd-3.14.14/doc/manual/Makefile000066400000000000000000000004131274230402600170030ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-targets: manual.html manual.pdf # Force pdf to regenerate whenever HTML changes # HTML rule has all the dependency stuff manual.pdf: manual.html # Include dependencies -include $(DEPDIR)/manual.P apcupsd-3.14.14/doc/manual/apcupsd.png000066400000000000000000000170321274230402600175150ustar00rootroot00000000000000PNG  IHDRG@'#TsRGB`PLTE$e kGYc,;EW|AIO7K)5>u]hp (/4SsJjYTyqzCo }J_Co^/G{]ۜxA nK.UU>x9kL9Hc]dKQ~V(oGɆJt ~i 9*r̬r;$Q Kq)>uGLQ;:vք˸L{o/:f(= E1C Nv^ȕh1F `/4|s?Qkk%8$F:RKSWhp٘~7uU`:|.S]w"^OՖc}%#vhnS|0S.6H}I#HדqG[..8ؽYoqDjHc]^^at*ZwtG1g.xSRU?eC]tˇ)r pt1\r(0q8}!^ [ƽ R7Qq ? k Rqt{хSAd':xq Awča->l*ȝM `މ;p|`yt#lLwH=) _ $ڏx/xIsQ 팔m2DW:M]sT[ &Upst$ 8qF;ƒ7#.i$hV2,YWM>& kkim&mG }eu:t*=NRy!h/Q)f/"zGzm疣ƮV K#[%=K͕ KO&^G Gg] =Gm>pU)}EJRNZS~6(G2 ݚPuqzdEn}Wt#s(.>믨lZ-h=cqTA!봀Y"1һ:.; Sg88?9o9HHn8/Yoѻc G,E ڀкzˑ}^p=;'ȑ.n9e]9"ijnKɭ^V7ki9=LrV}4sHTڴFg#K}hu :(\bWAǣah r\π5РI9BJBb8u&DG#֩8N+y>ĨÚQIJx:YuYY^<<= Vn!}|}DZ`:$@Zb8()X}jNvkOzVDr6xO77;3+ulR鞣CѓJkq+ (>Șډ}$9&8'nH'OfWsDMUyrᎼѷIßG#Ip~:"bz9 d.L  Y֨8QM+?s,2* ? #q\ ]vUL,g"G)5afRptfm  kAۘ {,}rɃ h|#{$ 3ƪw8 ׊ac5gAtQ)GuK%r9RP`QLa+]k}t(1VCMojK:Nq)%[\`A)/ޕFؼ7pt{_^>cxGSj8[ S(j}Ά"^kȲhgYY^6to0Bz5[C8e׷zFh.+-G})Q9+G T}Ծd5o@l=G(|^c`8G9 -;?*"*=9k׳zh8H{k%ThOYw|J~ջHGe97 |_lgP :PW ulރ);J[sN?to BDt&hK+U!ķv۽.S6#={PeӚ1(8YfTFo L|PȖ{9+9^8CU9ƣP7Jt6r4W&1Hig*95oTOCL*C N,SŎ?†'%UQLCS1mitޓ,ӻhTU$Sy-C %Ӛ5b=R=GqlƎtseƻb8~l'xyt?WIPiː$ __' d(qo4>FGwԴ@ܥ^?yq,K#Lƽ3ץ¨8⁒#{b<䆸pDrVb |K8$PbP^}WMdd+kaT“CzlXE\gOZb+IT/A%~9GET q9i^/(Կ(lH0J1ҬFG2~A5h#Pko$m|B "}3#71y8j#&czDN{Í9 v(1 6&a e,\1cb&/%PUKG68z8PT>M/T@bL֯뵭W DQ9"޽6f6G)D"[ZF}2F`@y1G/P[)}5ʺR5&ƨ߁"(I%V=}$/0|^6ՍlkApy,_ amaŸ׈*.B i¬q8Ej(%Af+Ы rHSM!]~XXD\˚VxUfisaΉ`&b᠈{x cY e>l#x7';/ɇ΄xQ]+^9$1.ӂYO:2 Iė!֨1<=}}<΂$nSoSѝt#Py+8QϯثCpt}݀X̦zim[ڶu**&UOzjloyspp#Xj©9z8zїY4rݏ81IG.OA͙l['Ϗ8H GyQ(@H7yqdi*A8ɚ];zrt#(l8jIqGpH4q$,GǑw+Q:c#O/;(v{!$G HGAYFxj=]\K73`ʼ,{vjtv6EpVey5#Me5Gh$$e;8*}ht;TQӞ^ZM^ 6dGhZ+nvi9 1 hy F'f<娵Y ԅ9TZm=w1pr!ƂߍQ=#G6jlJXW)?2&%vԳk\BM bdpien9bѺhfUHWu!{WQѲYէ Pd7l3  Zk;Jw;z7,u|bg8bl+7h6CJB l9vPܕ la1-\*(7CzU|= Nl0,*ƈ{A#*rb'#w+ᆣzbZ^ "/@4MSIBшpNz҃䊀&5[|U ߌ"lib>E+Y`"΄K#"*wԏt XߐLarx9R  C*҆t_z1kOb7xnw~e1gnQz9I@9)kq([m8<'3]]]&90cEKüjۈq"|>ƷKMF kL~ 'EӾiGwX\r4S0P<E0 d=F"&5K acGjyZ`В=FրiI+3y!Jx"n1I{D^3e!E0u ] pAIb*ss(9ˆ:u\y)7~ѻ9%]560h\Bw>sϲĒMyoe;q&^\'bFЊpsoR*;X$|g mSj ~{j!(Q=X`ok3u9;bmwO8{Acv"m#ݠsg^#Ĥ#]p G8臯6 &"/d7Yzvﲫ}hV*/]ks(J>䨷8"TC׊-PH lk8@{ Xz qv}b ̲=G)@FY<N/}M#˚w" }8s4̛1Gb[zhsn~B=:ŦUI_ڽڑc8rYuh#~%1[̇E"j'I'0{غkJF~f}\g]ȨQ3\voޱDAtL wخ_hXg8z:>]=r3UfbJ󪼊 F໑R GDi:ڙ6uIU~%oZ[!muGȑ-C̜ 6Mv  3#0P?w"d v6r ]>_g3GdM\b6I7UG:l~:ਣU\b隱9xUM[b:~mUWy>K~BsT+#V]Jb@UӥUv.Cyj*+@rc,?x'-lzMo]}1E/8;qikMbD]s9zSzq@~[$JU'f~R* r7(IKMTZ(9]R2RxlwP44:@ycm6b* *mk?VkG ogt Ʒ&lf㷓 {m8'ڦ/C(snĵ 6p9'J;Ik#xPQ۶WZ8jtڂ@I?Sy4w8Z;}!B5,Ǯ. HO g{5S5WFs's~#>"(&RC.3ƍdE^$o?ՙ @:eY;9Ɯ].m>+3~W`ɔi?Uỏ";cw0s/4*JOl׍o^e/7(vgRV"KX檜(ObrXԽAmi5'`Y* <˰+_kiGؓkr!3Y/*=II] {~Pb$I‰o{,#t%yEis1;ļZs]FYWR&.⯬(FuEj6['*~)6'^4Z0ʂߏ)e&SM(XV4 4BVu6Bt;mQ%2kQKD~∣԰\oh L!ێ H6_$nܯ+,cfO ^/L@#JDIV0$Z l9Co OSK 풝Ѿw*ݽ1Bե*aV'8@ k7j~}RkևVTt&&2di-"*EYڰXf.#YK{4W|eZ{i#Q7Hʈg-Q V(n9O~3 rTjCk*]J_LKk6dة'DV9tfW:p\ZLuI z\;xĝa{stliJhܮfodºwA\XU9NQJst5l'ʋe[B#2R29m..MITY se!I(aQ6ƢVybBՏUlxalX3j^RAt;83LwKm.h5o~[n&r)9z.cz9g8'z x?Y]rI+qSc'p J)$um᦮[IruYv7/穘1"D;nq3io+lL#!9#mέwX8-r2t->f:L9Ԣ(wg<{|drl}(vJܵ(h:5/e'qm`/Z(ut XH`;t^ ?06s`{Qgwݓv9 GλFO 'Ŏu*zP88"js(~?W~%IENDB`apcupsd-3.14.14/doc/manual/cables.rst000066400000000000000000000676031274230402600173440ustar00rootroot00000000000000Cables ====== You can either use the cable that came with your UPS (the easiest if we support it) or you can make your own cable. We recommend that you obtain a supported cable directly from APC. If you already have an APC cable, you can determine what kind it is by examining the flat sides of the two connectors where you will find the cable number embossed into the plastic. It is generally on one side of the male connector. To make your own cable you must first know whether you have a UPS that speaks the apcsmart protocol or a "dumb" UPS that uses serial port line voltage signalling. If you have an smart UPS, and you build your own cable, build a Smart-Custom cable (see `Smart-Custom Cable for SmartUPSes`_). If you have a voltage-signalling or dumb UPS, build a Simple-Custom cable (see `Simple-Custom Voltage-Signalling Cable for "dumb" UPSes`_). If you have a BackUPS CS with a RJ45 connector, you can build your own Custom-RJ45 cable (see `Custom-RJ45 Smart Signalling Cable for BackUPS CS Models`_). Smart-Custom Cable for SmartUPSes --------------------------------- *You do not have this cable unless you built it yourself. The Smart-Custom cable is not an APC product.* :: SMART-CUSTOM CABLE Signal Computer UPS DB9F DB9M RxD 2 -------------------- 2 TxD Send TxD 3 -------------------- 1 RxD Receive GND 5 -------------------- 9 Ground When using this cable with apcupsd specify the following in apcupsd.conf: :: UPSCABLE smart UPSTYPE apcsmart DEVICE /dev/ttyS0 (or whatever your serial port is) If you have an OS that requires DCD or RTS to be set before you can receive input, you might try building the standard APC Smart 940-0024C cable listed below (see `940-0024C Cable Wiring`_). Simple-Custom Voltage-Signalling Cable for "dumb" UPSes ------------------------------------------------------- *You do not have this cable unless you built it yourself. The Simple-Custom cable is not an APC product.* For "dumb" UPSes using voltage signalling, if you are going to build your own cable, we recommend to make the cable designed by the apcupsd team as follows: :: SIMPLE-CUSTOM CABLE Signal Computer UPS DB9F 4.7K ohm DB9M DTR 4 --[####]--* DTR set to +5V by Apcupsd | CTS 8 ----------*--------- 5 Low Battery GND 5 -------------------- 4 Ground DCD 1 -------------------- 2 On Battery RTS 7 -------------------- 1 Kill UPS Power List of components one needs to make the Simple cable: #. One (1) male DB9 connector, use solder type connector only. #. One (1) female DB9/25F connector, use solder type connector only. #. One (1) 4.7K ohm 1/4 watt 5% resistor. #. rosin core solder. #. three (3) to five (5) feet of 22AWG multi-stranded four or more conductor cable. Assembly instructions: #. Solder the resistor into pin 4 of the female DB9 connector. #. Next bend the resistor so that it connects to pin 8 of the female DB9 connector. #. Pin 8 on the female connector is also wired to pin 5 on the male DB9 connector. Solder both ends. #. Solder the other pins, pin 5 on the female DB9 to pin 4 on the male connector; pin 1 on the female connector to pin 2 on the male connector; and pin 7 on the female connector to pin 1 on the male connector. #. Double check your work. We use the DTR (pin 4 on the female connector) as our +5 volts power for the circuit. It is used as the Vcc pull-up voltage for testing the outputs on any "UPS by APC" in voltage-signalling mode. This cable may not work on a BackUPS Pro if the default communications are in apcsmart mode. This cable is also valid for use on a ShareUPS BASIC Port. It is reported to work on SmartUPSes, however the Smart Cable described above is preferred. To have a better idea of what is going on inside apcupsd, for the SIMPLE cable apcupsd reads three signals and sets three: Reads: CD, which apcupsd uses for the On Battery signal when high. CTS, which apcupsd uses for the Battery Low signal when high. RxD (SR), which apcupsd uses for the Line Down signal when high. This signal isn't used for much. Sets: DTR, which apcupsd sets when it detects a power failure (generally 5 to 10 seconds after the CD signal goes high). It clears this signal if the CD signal subsequently goes low -- i.e. power is restored. TxD (ST), which apcupsd clears when it detects that the CD signal has gone low after having gone high - i.e. power is restored. RTS, which apcupsd sets for the killpower signal -- to cause the UPS to shut off the power. Please note that these actions apply only to the SIMPLE cable. The signals used on the other cables are different. Finally, here is another way of looking at the CUSTOM-SIMPLE cable: :: APCUPSD SIMPLE-CUSTOM CABLE Computer Side | Description of Cable | UPS Side DB9f | DB25f | | DB9m | DB25m 4 | 20 | DTR (5vcc) *below | n/c | 8 | 5 | CTS (low battery) *below | <- 5 | 7 2 | 3 | RxD (no line voltage) *below | <- 3 | 2 5 | 7 | Ground (Signal) | 4 | 20 1 | 8 | CD (on battery from UPS) | <- 2 | 3 7 | 4 | RTS (kill UPS power) | -> 1 | 8 n/c | 1 | Frame/Case Gnd (optional) | 9 | 22 Note: the <- and -> indicate the signal direction. When using this cable with apcupsd specify the following in apcupsd.conf: :: UPSCABLE simple UPSTYPE dumb DEVICE /dev/ttyS0 (or whatever your serial port is) Custom-RJ45 Smart Signalling Cable for BackUPS CS Models -------------------------------------------------------- If you have a BackUPS CS, you are probably either using it with the USB cable that is supplied or with the 940-0128A supplied by APC, which permits running the UPS in dumb mode. By building your own cable, you can now run the BackUPS CS models (and perhaps also the ES models) using smart signalling and have all the same information that is available as running it in USB mode. The jack in the UPS is actually a 10 pin RJ45. However, you can just as easily use a 8 pin RJ45 connector, which is more standard (ethernet TX, and ISDN connector). It is easy to construct the cable by cutting off one end of a standard RJ45-8 ethernet cable and wiring the other end (three wires) into a standard DB9F female serial port connector. Below, you will find a diagram for the CUSTOM-RJ45 cable: :: CUSTOM-RJ45 CABLE Signal Computer UPS UPS DB9F RJ45-8 RJ45-10 RxD 2 ---------------- 1 2 TxD Send TxD 3 ---------------- 7 8 RxD Receive GND 5 ---------------- 6 7 Ground FG Shield ---------------- 3 4 Frame Ground The RJ45-8 pins are: looking at the end of the connector: 8 7 6 5 4 3 2 1 ___________________ | . . . . . . . . | | | ------------------- |____| The RJ45-10 pins are: looking at the end of the connector: 10 9 8 7 6 5 4 3 2 1 _______________________ | . . . . . . . . . . | | | ----------------------- |____| For the serial port DB9F connector, the pin numbers are stamped in the plastic near each pin. In addition, there is a diagram near the end of this chapter. Note, one user, Martin, has found that if the shield is not connected to the Frame Ground in the above diagram (not in our original schematic), the UPS (a BackUPS CS 500 EI) will be unstable and likely to rapidly switch from power to batteries (i.e. chatter). When using this cable with apcupsd specify the following in apcupsd.conf: :: UPSCABLE smart UPSTYPE apcsmart DEVICE /dev/ttyS0 (or whatever your serial port is) The information for constructing this cable was discovered and transmitted to us by slither_man. Many thanks! Other APC Cables that apcupsd Supports -------------------------------------- apcupsd will also support the following off the shelf cables that are supplied by APC - 940-0020[B/C] Simple Signal Only, all models. - 940-0023A Simple Signal Only, all models. - 940-0119A Simple Signal Only, Back-UPS Office, and BackUPS ES. - 940-0024[B/C/G] Smart mode Only, SU and BKPro only. - 940-0095[A/B/C] PnP (Plug and Play), all models. - 940-1524C Smart mode Only - 940-0128A Simple Signal Only, Back-UPS CS in serial mode. - All USB cables such as 940-0127[A/B] Voltage Signalling Features Supported by Apcupsd for Various Cables ------------------------------------------------------------------- The following table shows the features supported by the current version of apcupsd for various cables running the UPS in voltage-signalling mode. ============= ========== =========== ========== ================== Cable Power Loss Low Battery Kill Power Cable Disconnected ============= ========== =========== ========== ================== 940-0020B Yes No Yes No 940-0020C Yes Yes Yes No 940-0023A Yes No No No 940-0119A Yes Yes Yes No 940-0127A Yes Yes Yes No 940-0128A Yes Yes Yes No 940-0095A/B/C Yes Yes Yes No simple Yes Yes Yes No ============= ========== =========== ========== ================== Voltage Signalling ------------------ Apparently, all APC voltage-signalling UPSes with DB9 serial ports have the same signals on the output pins of the UPS. The difference at the computer end is due to different cable configurations. Thus, by measuring the connectivity of a cable, one can determine how to program the UPS. The signals presented or accepted by the UPS on its DB9 connector using the numbering scheme listed above is: :: UPS Pin Signal meaning 1 <- Shutdown when set by computer for 1-5 seconds. 2 -> On battery power (this signal is normally low but goes high when the UPS switches to batteries). 3 -> Mains down (line fail) See Note 1 below. 5 -> Low battery. See Note 1 below. 6 -> Inverse of mains down signal. See Note 2 below. 7 <- Turn on/off power (only on advanced UPSes only) Note 1: these two lines are normally open, but close when the appropriate signal is triggered. In fact, they are open collector outputs which are rated for a maximum of +40VDC and 25 mA. Thus the 4.7K ohm resistor used in the Custom Simple cable works quite well. Note 2: the same as note 1 except that the line is normally closed, and opens when the line voltage fails. The Back-UPS Office 500 signals ------------------------------- The Back-UPS Office UPS has a telephone type jack as output, which looks like the following: :: Looking at the end of the connector: 6 5 4 3 2 1 _____________ | . . . . . . | | | | |----------| |__| It appears that the signals work as follows: :: UPS Signal meaning 1 (brown) <- Shutdown when set by computer for 1-5 seconds. 2 (black) -> On battery power 3 (blue) -> Low battery 4 (red) Signal ground 5 (yellow) <- Begin signalling on other pins 6 (none) none Analyses of APC Cables ---------------------- 940-0020B Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: Simple Signaling such as BackUPS :Contributed by: Lazar M. Fleysher Although we do not know what the black box semiconductor contains, we believe that we understand its operation (many thanks to Lazar M. Fleysher for working this out). This cable can only be used on voltage-signalling UPSes, and provides the On Battery signal as well as kill UPS power. Most recent evidence (Lazar's analysis) indicates that this cable under the right conditions may provide the Low Battery signal. This is yet to be confirmed. *This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.* :: APC Part# - 940-0020B Signal Computer UPS DB9F DB9M CTS 8 -------------------- 2 On Battery DTR 4 -------------------- 1 Kill power GND 5 ---------------*---- 4 Ground | --- *---- 9 Common DCD 1 ----|///|----------- 5 Low Battery |\\\| RTS 7 ----|///| (probably a --- semi-conductor) 940-0020C Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: Simple Signaling such as BackUPS This cable can only be used on voltage-signalling UPSes, and provides the On Battery signal, the Low Battery signal as well as kill UPS power. You may specify ``UPSCABLE 940-0020C``. *This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.* :: APC Part# - 940-0020C Signal Computer UPS DB9F DB9M CTS 8 -------------------- 2 On Battery DTR 4 -------------------- 1 Kill power GND 5 ---------------*---- 4 Ground | *---- 9 Common RTS 7 -----[ 93.5K ohm ]----- 5 Low Battery or semi-conductor 940-0023A Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: Simple Signaling such as BackUPS This cable can only be used on voltage-signalling UPSes, and apparently only provides the On Battery signal. As a consequence, this cable is pretty much useless, and we recommend that you find a better cable because all APC UPSes support more than just On Battery. Please note that we are not sure the following diagram is correct. *This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.* :: APC Part# - 940-0023A Signal Computer UPS DB9F DB9M DCD 1 -------------------- 2 On Battery 3.3K ohm TxD 3 --[####]-* | DTR 4 ---------* GND 5 ---------------*---- 4 Ground | *---- 9 Common 940-0024C Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: SmartUPS (all models with DB9 serial port) If you wish to build the standard cable furnished by APC (940-0024C), use the following diagram. :: APC Part# - 940-0024C Signal Computer UPS DB9F DB9M RxD 2 -------------------- 2 TxD Send TxD 3 -------------------- 1 RxD Receive DCD 1 --* | DTR 4 --* GND 5 -------------------- 9 Ground RTS 7 --* | CTS 8 --* 940-0095A Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: APC BackUPS Pro PNP :Contributed by: Chris Hanson cph at zurich.ai.mit.edu This is the definitive wiring diagram for the 940-0095A cable submitted by Chris Hanson, who disassembled the original cable, destroying it in the process. He then built one from his diagram and it works perfectly. :: APC Part# - 940-0095A UPS end Computer end ------- ------------ 47k 47k BATTERY-LOW (5) >----R1----*----R2----*----< DTR,DSR,CTS (4,6,8) | | | | | / E | |/ | B | *-------| 2N3906 PNP | |\ \ C | | *----< DCD (1) Low Batt | | R 4.7k 3 | 4.7k | SHUTDOWN (1) >----------*----R4----*----< TxD (3) | | 1N4148 *----K|---------< RTS (7) Shutdown POWER-FAIL (2) >--------------------------< RxD,RI (2,9) On Batt GROUND (4,9) >--------------------------< GND (5) Operation: - DTR is "cable power" and must be held at SPACE. DSR or CTS may be used as a loopback input to determine if the cable is plugged in. - DCD is the "battery low" signal to the computer. A SPACE on this line means the battery is low. This is signalled by BATTERY-LOW being pulled down (it is probably open circuit normally). Normally, the transistor is turned off, and DCD is held at the MARK voltage by TxD. When BATTERY-LOW is pulled down, the voltage divider R2/R1 biases the transistor so that it is turned on, causing DCD to be pulled up to the SPACE voltage. - TxD must be held at MARK; this is the default state when no data is being transmitted. This sets the default bias for both DCD and SHUTDOWN. If this line is an open circuit, then when BATTERY-LOW is signalled, SHUTDOWN will be automatically signalled; this would be true if the cable were plugged in to the UPS and not the computer, or if the computer were turned off. - RTS is the "shutdown" signal from the computer. A SPACE on this line tells the UPS to shut down. - RxD and RI are both the "power-fail" signals to the computer. A MARK on this line means the power has failed. - SPACE is a positive voltage, typically +12V. MARK is a negative voltage, typically -12V. Linux appears to translate SPACE to a 1 and MARK to a 0. 940-0095B Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: Many simple-signaling (aka voltage signaling) models such as BackUPS *This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.* :: APC Part# - 940-0095B Signal Computer UPS DB9F DB9M DTR 4 ----* CTS 8 ----| DSR 6 ----| DCD 1 ----* GND 5 ---------------*---- 4 Ground | *---- 9 Common RI 9 ----* | RxD 2 ----*--------------- 2 On Battery TxD 3 ----------[####]---- 1 Kill UPS Power 4.7K ohm 940-0119A Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: Older BackUPS Office *This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.* :: APC Part# - 940-0119A UPS Computer pins pins Signal Signal meaning 1 (brown) 4,6 DSR DTR <- Shutdown when set by computer for 1-5 seconds. 2 (black) 8,9 RI CTS -> On battery power 3 (blue) 1,2 CD RxD -> Low battery 4 (red) 5 Ground 5 (yellow) 7 RTS <- Begin signalling on other pins 6 (none) none Serial BackUPS ES Wiring ~~~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: Older Serial BackUPS ES :Contributed by: William Stock The BackUPS ES has a straight through serial cable with no identification on the plugs. To make it work with apcupsd, specify the { UPSCABLE 940-0119A} and { UPSTYPE backups}. The equivalent of cable 940-0119A is done on a PCB inside the unit. :: computer ----------- BackUPS-ES ----------------- DB9-M DB-9F pin signal pin 4 DSR -> 4 --+ | diode resistor 6 DTR -> 6 --+---->|----/\/\/\---o kill power 1 DCD <- 1 --+ | 2 RxD <- 2 --+----------------+--o low battery | 7 RTS -> 7 --------+--/\/\/\--+ | +--/\/\/\--+ | 8 RI <- 8 --+----------------+--o on battery | 9 CTS <- 9 --+ 5 GND --- 5 ----------------------o ground 3 TxD 3 nc 940-0128A Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: Older USB BackUPS ES and CS :Contributed by: Many, thanks to all for your help! Though these UPSes are USB UPSes, APC supplies a serial cable (typically with a green DB9 F connector) that has 940-0128A stamped into one side of the plastic serial port connector. The other end of the cable is a 10 pin RJ45 connector that plugs into the UPS (thanks to Dean Waldow for sending a cable!). Apcupsd version 3.8.5 and later supports this cable when specified as { UPSCABLE 940-0128A} and { UPSTYPE dumb}. However, running in this mode much of the information that would be available in USB mode is lost. In addition, when apcupsd attempts to instruct the UPS to kill the power, it begins cycling about 4 times a second between battery and line. The solution to the problem (thanks to Tom Suzda) is to unplug the UPS and while it is still chattering, press the power button (on the front of the unit) until the unit beeps and the chattering stops. After that the UPS should behave normally and power down 1-2 minutes after requested to do so. Thanks to all the people who have helped test this and have provided information on the cable wiring, our best guess for the cable schematic is the following: :: APC Part# - 940-0128A computer --------- Inside the Connector--------- UPS DB9-F | | RJ45 pin - signal | | Pin - Color | | 4 DSR ->|---+ | | | diode resistor | 6 DTR ->|---+---->|----/\/\/\---o kill power | 8 Orange | | 1 DCD <-|----+ | | | | 2 RxD <-|----+----------------+--o low battery| 3 Brown | | | 7 RTS ->|----------+--/\/\/\--+ | | | | | +--/\/\/\--+ | | | | 8 RI <-|----+----------------+--o on battery | 2 Black | | | 9 CTS <-|----+ | | signal | 5 GND --|-----------------------o ground | 7 Red | | 3 TxD | | | chassis | Chassis/GND |-----------------------o ground | 4 Black | | | Not connected | 1, 5, 6, 9, 10 -------------------------------------- The RJ45 pins are: looking at the end of the connector: 10 9 8 7 6 5 4 3 2 1 _______________________ | . . . . . . . . . . | | | ----------------------- |____| 940-0128D Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: BackUPS XS1000(BX-1000), Possibly other USB models :Contributed by: Jan Babinski jbabinsk at pulsarbeacon dot com 940-0128D is functionally similar to the 940-0128A cable except for NC on (6) DTR and (2) RD on the computer side. Unverified: Try setting apcupsd to ``UPSTYPE dumb`` and ``UPSCABLE 940-0128A``. :: APC Part# - 940-0128D DB9(Computer) RJ45-10(UPS) (5) (1) ____________ ( o o o o o ) [ oooooooooo ] \ o o o o / [____________] (9) (6) (10) [_] (1) RI(9)<---+ | CTS(8)<---+--- E 2N2222(NPN) \|___ ____ /| B | | C | | | +---vvvv---+--[>|------<(2)OnBatt RTS(7)>---| 2k 1N5819 +---vvvv---+--[>|------<(3)LowBatt | | +--- C | \|___| /| B DCD(1)<------- E 2N2222(NPN) DTR(4)>-------------------------->(8)KillPwr GND(5)----------------------------(7)Signal GND (Shield)--------------------------(4)Chassis GND 940-0127B Cable Wiring ~~~~~~~~~~~~~~~~~~~~~~ :Supported Models: BackUPS XS1000(BX-1000), Possibly other USB models :Contributed by: Jan Babinski jbabinsk at pulsarbeacon dot com Standard USB cable for USB-capable models with 10-pin RJ45 connector. :: APC Part# - 940-0127B USB(Computer) RJ45-10(UPS) _________ ____________ | = = = = | [ oooooooooo ] |_________| [____________] (1) (4) (10) [_] (1) +5V(1)-----------(1)+5V DATA+(2)-----------(9)DATA+ DATA-(3)-----------(10)DATA- GND(4)-----------(7)Signal GND (Shield)-----------(4)Chassis GRND Win32 Implementation Restrictions for Simple UPSes -------------------------------------------------- Due to inadequacies in the Win32 API, it is not possible to set/clear/get all the serial port line signals. apcupsd can detect: CTS, DSR, RNG, and CD. It can set and clear: RTS and DTR. This imposes a few minor restrictions on the functionality of some of the cables. In particular, LineDown on the Custom Simple cable, and Low Battery on the 0023A cable are not implemented. apcupsd-3.14.14/doc/manual/charging.png000066400000000000000000000003051274230402600176330ustar00rootroot00000000000000PNG  IHDRRPLTEmmmmUmmUfeIDATx-M @w*<9˳c3B m X>@p:ȼD,Xtϐ)U؇$3ŗ\r-VQ,Ŵt%0F^IENDB`apcupsd-3.14.14/doc/manual/commlost.png000066400000000000000000000006721274230402600177150ustar00rootroot00000000000000PNG  IHDRabKGD pHYs  tIME *:GIDATx͑M+Da , 5K/0ݥ'#Dhi|) (5ea&j" 5:̝(:us_frB=pX}lSwq+rC)MPHeBtJ&,_m*NUEtHd}Lܺ+8vź=9yW^jYvr[.B 'ǰ BPF.e]SICJK )%V}} 2JӸފz ج.(o}6j [.H)[Y4M >0gt ~ σiIENDB`apcupsd-3.14.14/doc/manual/main_configs.png000066400000000000000000000326151274230402600205160ustar00rootroot00000000000000PNG  IHDRepbKGD̿ pHYs  ~tIME 'X[ IDATxOHz߿~,9TKFX /j|\AXVMK ٛ { Ae'ˢ>lnF"dr>HkB.))qPjuT*U[zzAyhGz.Srf̟D>0;7 -ؐD2 _pgIOqx$4 QA/T e4]Zp"w<":B=Kđs)s9G$"@pԙ:~'c-C @L@@J $;"PPI"!#"I=\AMd2ݓ4] -X0}l:;7=p;TۙXj ICLǖ " TFus.ww.st,$" }l2yywD {RD$`_bջB?yzХ pOpV`#82쌈:+& G ;ŀ`$0D)p~dkcR.*\HhbIJeֈ9ě[`Ty֥xDjg"5ƃcTցQYFeu`TցQYFeu`TցQYFe)[u\~UKpuL:0*:0*1Fd>gT>@#M5F9 ˕`l;y'ɇ_DSGʛUJeڪGr륪zkl34m<`g pA!URs9}߆((/<AQu0}*?oc45DZ`z󐈂#{3zZ uΛvrXci{G]%oeNfOܸWOhYь--rDjADv%CƟŦgc>16n}2QWPO;#vQJI!O'D挭6ل,~"쨫Қb B=U/(N $ U^&avH$8 ##Xp "X H r$XCXH%(귙q!G𐼐d_JjW{@ogA}f}Ҝo0T>Ly$1wPCh-%pa*)APd nAATi] c"is դ.HeP+)AP c{yR aD/t:Vog8}[ؓ/W?_|~Rӏ_7Fu*n}3ok nWo71=;Yk[]/7cOG.ˋxzü"WkXZ3>s8zܙyoǶ+±6`TE>a&4?4qQJm`p?["pVC Qy1bgX2Zb cj5E4̣[Ycͷ{jC@BL(Y3]ط JvL@VzkՋ9v+Zg܎*a֢|+b\{)K袷oZXN;De)\xKOyU9.|;Z_ÖpeV(3>xHbRoͲgv+UcDbm<9CM-SvK_G{\'gr69~pDl%KZ~Yxgޯ@5-7 PEe* );nZQn~"Y&濋^^'re&3VB*lv]yn }c9S媝pnQ A`Q+ϱE.6`;YmVuc._g|j3iVȎq4GmQ9ۏu;x?g?/geL,`5VVim{_v`y:K^V>]$Czf}Ktm'ydK&I}~g"H[c0YnX rNݾEWeRVDP IRKң6k}N[ѸH֖TND޾%ޓ}g\"ٞy'm4\^W m}݇zܟLثr)ȫmKOQ..TuwL";I|Nٗ 0*&Y;Q6+ר|z1`TցQYFeu`TցQYFeB*t;]Ձ1t`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeupG*C[Tc/6cmo7U0ϖ_r'ZrŞ}kDtDF[N*|4!mvy6$ )}ܞ"|!t4S9#ԩ"lK7P\HvBTUCFDTdX4eǞkʸD ɕ2Q`Yыf#&I9ڮHHpAE+ĒC'Dj#"a{^(s9GL/H${hQ-D :"`/LrbU4J  \#s $l/ND$PP:=mF/ }]EK%A/clNqjX$TlWmL1`0g(ɥ4[`-Y>:0*:0*:xS~eEQЁQYFeu`TցQYFeu``>gT>@9^x۴ܩ1ʱr6Tc JÈ<`et*GD){gE'z4:7~s&ܪGtMy.^wzy4`7g!(yHDD.W$*ik^B? s&ǧ5|{=edpN8;Ƒ|jIGe[3TY )T P"BL,!ɛ~MRjo_! ~t( H:>{m9[l[`Qy[GK6-l{~k!sU;oJTǞa8*-Eݩl~D DFkZ'^۫b'fe4߬hm|9f. e;zbdYiihO2"*b J&Uc.2J@#) qȉATI{Gfx6!_36j&Ơ؂D!lO"&&IBՀ>C+e6`Dҁ#)12 .`AD. *iнE6`;n|f'jUW߃^; 3 arr"{Y"$M!' "ʅ-iKezt()H4N#~BW* Z~9cDxe )EQkGUFW"v7nTIyeQg\j U -m( ;L "\pG f W8ILܮ/#=pA*\I B]`˓=qmFIců>{jxv7?= rӟ~./>o|c\'7g~+&%}߈۳ίsޙVr9w>?|z{䲼?̋O>8,rf)5˫5cl/<1_5/[vE8PӪ'$F@.jcT Xb}pk_P. x!*o3|TlxZF+TbLmfy4c3 }p/82XejUf?JH JOw.[]c}D; x A֢r`ݺen=vt*Va֢|+bN70.!p!*/KLƒ_"L]ԆqZT/ԺejUz0Iz;#gv+UcDbm<9CM-SviΑM0(Pyzk g,^o8ƘbzLf䡹yGuRf(_?_8V1upo?\؊.;8"Ug ir3'@~0k% DΣ%[37gc$TΘX *呃d6#sB B0Uih@L݄ķ/IFjre):0* xNhԕkT>xKz0*:0*\/;rOs\sa05:0*:0*:0*:0*xGT֌1TPilTD$m ?ƃNj?5FyՔIqUPsfdwSE?դl5qtf68j0A\PHF2|QvmCl;׾^s+Sz4s3f9w:ź ,r7`>RDE.jvds&'7RgGC_WFb-T X5TՍ{ GKT9[zf@F6@1<"yɮqN:"$*KqW8HeCe]aEX4N.A\53^ʃj@+(:ظ +A*" h:иWOQݦ?Q<.0APd nDQӸ-wr. MqWPcc_K0 Feu`TցQYFeu`TցQYFeu`TցQYFeR;'}{:͝T1t`TցQYFeu`TցQYFeu`TցQYFeu`TցQYFeup%7&FSZ3X=Y4=R1\ ѸL.erѼj_$θ*WkgԴ'fe4߬zO53[%yM\>Q"RB Dɵ|A1~a@Լ簁< xm\/{ּg_%&b7;.j򀌦rc,N5[XEG\ȅSc].a əyد:0*:0*:0*:0*:0*MNt. gx#ޔ/r!Ơ7:0*:0*:0*`W x0\ ˗~:{AΏAOe?H`TցQYFerԂ|bUn/js@*=l1eVYQ1ysiP11"qK{ _?zj`$OJُwPb_v0DeaPIq+k92%tZ?Sd|R\!6)p߬JqK@5)&/.Z 9Tl%M(D (;^|WU㙚'Űz l8p "ag p۶CΈg?}X)XIDAT&0+ QChU[jck~pl܇ ~FdksʂAfW+*Y[TϢ /ʷ lN҇?he Th4N0Hl"_ hɖ*pT>gX hSX>!@DZ 섨8/b=λi:U&1i S~ʰ{/;ܪeA=)xŠYpDw3u~t PS* WH -1QZP.zv$x?GŽЄΙ?Kqaѓ X,":`AQxwT& MsΏR6TYAHjozw [9pR J?BPITp;&6:'ݳv{˭v*o'O͏POOF[Y3J8p!Ie /B^ N}z4F5/!yKyғDwU}{R7 _ I 0ih@LW^9ռN V߾oUam֙J/_6:~\y|Lk7o%Վ%"nܡ{͟L^̲o/ۛN=Bۻvڱhx3Љu~OUƼma^|;StֿjhieaeDT۷%BF (q$<"neQ5M"PLBtf*>|lN9aZ_ÖpFD-l6L|jmg'N{xws2cWRY`vuj6쒥X-G o߈+!b 2}MhT<84䗫\6t!J RV[C" 0Py1bgX2Zb cjNg7"n<]#g0V[5,U:F[ %$*%֢ZXUH.1^\ͼ^W S+k9z+ .ĹʌHGDt|mz*?[5,!RC>遫^rg/Wxŭn[,+SȟP5ɫ Pg;`DI3~zV @4CJb=`^{m_6ַ:c0ֈVx3m w`)QJ0.#6ϷGv-5֭+IGKay~/ '"RpEin ż3&c_{:ѽrߙ-'q}lwUY*g{ά8 Vqћ縏rRIqThƱG3l<;[`SKLђ- X f.Nίr 2A07nܷǷJL@/>u)T_|_V06F?+7|l} Mܙw4TOʝPYxe̾S8=Ue̽jUٲȘz*Cܑl.'>ί^Tĭn&#]o5nus5=uMYܳ5kkr*MU}|/];W[w!|'&}tM^ܽw5kr*CT|]GPy]+0h*WkOvS2 "i4.g]ǎ\h^5ey'yeYf h^ԫPI^ξݢ"h ʄu0-wЪ !JAR Nޑ [2km2`9S"{b7jWyZ ]vd΋L0R_T 2iZv|gǣyYcLk*Ok*Ok*Ok*Ok*Ok*Ok*Ohd1FpId~e]tƋ:^y`2]ʕ`l|Am}2T#SHHJS}6ST:7Lmws-^>WZꦉtM5Z۩+"/GlU |lzb4߬:i~}ӠT&]glǍG!6j4J5e!G,UzMIwRL tMmgl s {dm%|X^<9PR4*鬍9R$Dj @@\?E5 zH1;jϯHEBDk^\SmϾ|vVLվl8QYFeu: APCUPSD User Manual
./apcupsd.png

APCUPSD User Manual

Adam Kropelin
Kern Sibbald

Apcupsd is a UPS control system that permits orderly shutdown of your computer in the event of a power failure.

February 8, 2015 12:53:50
This manual documents apcupsd version 3.14.x
Copyright © 2004-2015 Adam Kropelin
Copyright © 1999-2005 Kern Sibbald

Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the name Apcupsd, the copyright notice, and this notice are preserved.

Apcupsd source code is released under the GNU General Public License version 2. Please see the file COPYING in the main source directory.

For more information on the project, please visit the main web site at http://www.apcupsd.com


Table of Contents


How To Use This Manual

This is the manual for apcupsd, a daemon for communicating with UPSes (Uninterruptible Power Supplies) made by American Power Conversion Corporation (APC). If you have an APC-made UPS, whether sold under the APC nameplate or OEMed (for example, the HP PowerTrust 2997A), and you want you get it working with a computer running Linux, Unix, or Windows, you are reading the right document.

This manual is divided into parts which increase in technical depth as they go. If you have just bought a state-of-the-art smart UPS with a USB or Ethernet interface, and you are running a current version of Red Hat or SUSE Linux, then apcupsd is very nearly plug-and-play and you will have to read only the Basic User's Guide.

If your operating system is older, or if you have an old-fashioned serial-line UPS, you'll have to read about serial installation (see Installation: Serial-Line UPSes). If you need more details about administration for unusual situations (such as a master/slave or multi-UPS setup) you'll need to read the sections on those topics as well. Finally, there are a number of technical reference sections which gives full details on things like configuration file directives and event-logging formats.

You should begin by reading the Quick Start (see Quick Start for Beginners) instructions.

Basic User's Guide

Quick Start for Beginners

apcupsd is a complex piece of software, but most of its complexities are meant for dealing with older hardware and operating systems. On current hardware and software getting it running should not be very complicated.

The following is a help guide to the steps needed to get apcupsd set up and running as painlessly as possible.

  1. Check to see if apcupsd supports your UPS and cable (see Supported UPSes and Cables).
  2. Check to see if apcupsd supports your operating system (see Supported Operating Systems).
  3. Plan your configuration type (see Choosing a Configuration Type). If you have just one UPS and one computer, this is easy. If you have more than one machine being served by the same UPS, or more than one UPS supplying power to computers that are on the same local network, you have more choices to make.
  4. Figure out if you have one of the easy setups. If you have a USB UPS, and a supported operating system and you want to use one UPS with one computer, that's an easy setup. APC supplies the cable needed to talk with that UPS along with the UPS. All you need to do is check that your USB subsystem is working (see USB Configuration); if so, you can go to the build and install step.
  5. If you have a UPS designed to communicate via SNMP over Ethernet, that is also a relatively easy installation. Details are provided in Support for SNMP UPSes.
  6. If you have a UPS that communicates via an RS232C serial interface and it is a SmartUPS, then things are relatively simple, otherwise, your life is about to get interesting.
    1. If you have a vendor-supplied cable, find out what cable type you have by looking on the flat ends of the cable for a number, such as 940-0020A, stamped in the plastic.
    2. If you don't have a vendor-supplied cable, or your type is not supported, you may have to build one yourself (see Cables). Here is hoping you are good with a soldering iron!
  7. Now you are ready to read the Building and Installing (see Building and Installing apcupsd) section of the manual and follow those directions. If you are installing from an RPM or some other form of binary package, this step will probably consist of executing a single command.
  8. Tweak your /etc/apcupsd/apcupsd.conf file as necessary. Often it will not be.
  9. Change the BIOS settings (see Arranging for Reboot on Power-Up) on your computer so that boots up every time it gets power. (This is not the default on most systems.)
  10. To verify that your UPS is communicating with your computer and will do the right thing when the power goes out, read and follow the instructions in the Testing (see Testing Apcupsd) section.
  11. If you run into problems, check the apcupsd users' email list archive for similar problems. This is an excellent resource with answers to all sorts of questions. See http://sourceforge.net/mailarchive/forum.php?forum_name=apcupsd-users.
  12. If you still need help, send a message to the apcupsd users' email list (apcupsd-users@lists.sourceforge.net) describing your problem, what version of apcupsd you are using, what operating system you are using, and anything else you think might be helpful.
  13. Read the manual section on Monitoring and Tuning your UPS.

Supported Operating Systems

apcupsd supports many UNIX-like operating systems as well as several variants of Windows. Due to lack of API standardization, USB support is not available on every platform. See Platform Support below for details.

In general it is recommended to obtain a prebuilt package for your platform. Given how apcupsd must integrate into the shutdown mechanism of the operating system and the rate at which such mechanisms are changed by vendors, the platform ports in the apcupsd tree may become out of date. In some cases, binary packages are provided by the apcupsd team (RedHat, Mandriva, SuSE, Windows, Mac OS X). For other platforms it is recommended to check your vendor's package repository and third party repositories for recent binary packages. Note that some vendors continue to distribute ancient versions of apcupsd with known defects. These packages should not be used.

Platform Support

LINUX

WINDOWS

  • Windows NT 4 [2] [4]
  • Windows 98/ME/2000 [2] [4]
  • Windows XP/Vista (including 64 bit) [1] [2]
  • Windows Server 2003/2008 (including 64 bit) [2]
  • Windows 7 [2]

OTHERS

[1]Platforms on which apcupsd is regularly developed and tested
[2]Platforms for which apcupsd team distributes binary packages
[3]Port included in apcupsd source tree but may be out of date, unmaintained, or broken.
[4]USB not supported

Supported UPSes and Cables

apcupsd supports nearly every APC brand UPS model in existence and enough different cable types to connect to all of them.

The UPSTYPE <keyword> field is the value you will put in your /etc/apcupsd/apcupsd.conf file to tell apcupsd what type of UPS you have. We'll describe the possible values here, because they're a good way to explain your UPS's single most important interface property: the kind of protocol it uses to talk with its computer.

apcsmart
The 'apcsmart' protocol uses an RS232 serial connection to pass commands back and forth in a primitive language resembling modem-control codes. APC calls this language "UPS-Link". Originally introduced for Smart-UPS models (thus the name 'apcsmart'), this class of UPS is in decline, rapidly being replaced in APC's product line by USB and MODBUS UPSes.
usb
A USB UPS speaks a universal well defined control language over a USB wire. Most of APC's lineup now uses this method as of late 2003, and it seems likely to completely take over in their low- and middle range. The most recent APC UPSes support only a limited set of data over the USB interface. MODBUS (see below) is required in order to access the advanced data.
net
This is the keyword to specify if you are using your UPS in Slave mode (i.e. the machine is not directly connected to the UPS, but to another machine which is), and it is connected to the Master via an ethernet connection. You must have apcupsd's Network Information Services NIS turned on for this mode to work.
snmp
SNMP UPSes communicate via an Ethernet NIC and firmware that speaks Simple Network Management Protocol.
dumb
A dumb or voltage-signaling UPS and its computer communicate through the control lines (not the data lines) on an RS232C serial connection. Not much can actually be conveyed this way other than an order to shut down. Voltage-signaling UPSes are obsolete; you are unlikely to encounter one other than as legacy hardware. If you have a choice, we recommend you avoid simple signalling UPSes.
pcnet
PCNET is an alternative for SNMP available on APC's AP9617 family of smart slot modules. The protocol is much simpler and potentially more secure than SNMP.
modbus
MODBUS is the newest APC protocol and operates over RS232 serial links or USB. MODBUS is APC's replacement for the aging 'apcsmart' (aka UPS-Link) protocol. MODBUS is the only way to access detailed control and status information on newer (esp. SMT series) UPSes.

Choosing a Configuration Type

There are three major ways of running apcupsd on your system. The first is a standalone configuration where apcupsd controls a single UPS, which powers a single computer. This is the most common configuration. If you're working with just one machine and one UPS, skip the rest of this section.

Your choices become more interesting if you are running a small cluster or a big server farm. Under those circumstances, it may not be possible or even desirable to pair a UPS with every single machine. apcupsd supports some alternate arrangements.

The second type of configuration is the NIS (Network Information Server) server and client. In this configuration, where one UPS powers several computers, a copy of apcupsd running one one computer will act as a server while the other(s) will act as network clients which poll the server for information about the UPS. Note that "NIS" is not related to Sun's directory service also called "NIS" or "Yellow Pages".

The third configuration is where a single computer controls multiple UPSes. In this case, there are several instances of apcupsd on the same computer, each controlling a different UPS. One instance of apcupsd will run in standalone mode, and the other instance will normally run in network mode. This type of configuration may be appropriate for large server farms that use one dedicated machine for monitoring and diagnostics

Here is a diagram that summarizes the possibilities:

Configuration types

./main_configs.png

If you decide to set up one of these more complex configurations, see the dedicated section on that particular configuration.

USB Configuration

Apcupsd supports USB connections on all major operating systems: Linux, FreeBSD, OpenBSD, NetBSD, Windows, Solaris, and Mac OS X Darwin. If you plan to use a USB connection, please read the appropriate subsection in its entirety. You can skip this section if your UPS has a serial (RS232-C) or Ethernet interface or if you are not running one of the platforms listed above.

Linux USB Configuration

Known Linux USB Issues

Problem
Linux 2.4 series kernels older than 2.4.22 (RH 9, RHEL 3) do not bind the USB device to the proper driver. This is evidenced by /proc/bus/usb/devices listing the UPS correctly but it will have "driver=(none)" instead of "driver=(hid)". This affects RHEL3, among others.
Workaround
Upgrade linux kernel to 2.4.22 or higher. Alternately, you apply the linux-2.4.20-killpower.patch and linux-2.4.20-USB-reject.patch patches to your kernel and rebuild it. These patches can be found in the examples/ directory in the apcupsd source distribution.
Problem
Mandrake 10.0 and 10.1 systems with high security mode enabled (running kernel-secure kernel) use static device nodes but still assign USB minor numbers dynamically. This is evidenced by hiddev0: USB HID v1.10 Device [...] instead of hiddev96: ... in dmesg log.
Workaround
Boot standard kernel instead of kernel-secure or disable CONFIG_USB_DYNAMIC_MINORS and rebuild kernel-secure.
Problem
USB driver linux-usb.c fails to compile, reporting errors about HID_MAX_USAGES undefined. This is due to a defect in the linux kernel hiddev.h header file on 2.6.5 and higher kernels.
Workaround
Upgrade to apcupsd-3.10.14 or higher. These versions contain a workaround for the defect.
Problem
On some systems such as Slackware 10.0, no USB devices will show up (see the next section).
Workaround

Add the following to rc.local

mount -t usbdevfs none /proc/bus/usb
Problem
2.6 kernels use udev and some distributions to not configure it to automatically create /dev/usb/hiddev?? as they should, causing apcupsd to fail to locate the UPS.
Workaround

Edit the file /etc/udev/rules.d/50-udev.rules, and add the following:

KERNEL="hiddev*", NAME="usb/hiddev%n"

More details are provided in the following section ...

Verifying Device Detection and Driver

To make sure that your USB subsystem can see the UPS, just do this from a shell prompt:

cat /proc/bus/usb/devices

This information is updated by the kernel whenever a device is plugged in or unplugged, irrespective of whether apcupsd is running or not. It contains details on all the USB devices in your system including hubs (internal and external), input devices, and UPSes.

You should get some output back that includes something like this, featuring a BackUPS RS 1000:

T:  Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  3 Spd=1.5 MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=051d ProdID=0002 Rev= 1.06
S:  Manufacturer=American Power Conversion
S:  Product=Back-UPS RS 1000 FW:7.g3 .D USB FW:g3
S:  SerialNumber=JB0308036505
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr= 24mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=00 Prot=00 Driver=hid

The important things to check for are the S: lines describing your UPS and and the I: line showing what driver is handling it. If on the I: line, Driver is listed as Driver=none then you do not have the HID driver loaded or the driver did not attach to the UPS. One common cause is having a Linux kernel older than 2.4.22 (such as a stock RedHat 9 or RHEL 3 kernel). If this is the case for your system, please upgrade to at least kernel version 2.4.22 and try again. If you are already running a 2.4.22 or higher kernel, please read further for instructions for other possible courses of action.

Here is another example, this time featuring a Back-UPS 350:

T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=1.5 MxCh= 0
D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
P:  Vendor=051d ProdID=0002 Rev= 1.00
S:  Manufacturer=American Power Conversion
S:  Product=Back-UPS 350 FW: 5.2.I USB FW: c1
S:  SerialNumber=BB0115017954
C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr= 30mA
I:  If#= 0 Alt= 0 #EPs= 1 Cls=03(HID  ) Sub=00 Prot=00 Driver=hid
E:  Ad=81(I) Atr=03(Int.) MxPS=   8 Ivl= 10ms

In general, if you see your UPS model in the S: field, which means Manufacturer=, Product=, and SerialNumber=, and you see Driver=hid in the I: field, you know the UPS has been recognized and is bound to the correct driver.

If your UPS doesn't appear in the list at all, check the obvious things: The UPS must be powered on, and a cable must be properly seated in both the data port of the UPS and one of your machine's USB ports. Many UPSes have phone ports to provide surge protection for phones or modems -- make sure you haven't plugged your USB cable into one of those rather than the data port (which will usually be near the top edge of the case.)

Also, ensure that the correct drivers are loaded. Under Linux-2.4.x, you can check this out easily by examining the /proc/bus/usb/drivers file. Here's how you can do that:

cat /proc/bus/usb/drivers

...and you should get:

        usbdevfs
        hub
96-111: hiddev
        hid

On Linux-2.6.x, make sure the sysfs filesystem is mounted on /sys and do:

ls -l /sys/bus/usb/drivers/

...where you should get:

total 0
drwxr-xr-x    2 root     root            0 May  1 18:55 hid
drwxr-xr-x    2 root     root            0 May  1 18:55 hiddev
drwxr-xr-x    2 root     root            0 May  1 18:55 hub
drwxr-xr-x    2 root     root            0 May  1 18:55 usb
drwxr-xr-x    2 root     root            0 May  1 18:55 usbfs

...or perhaps something like:

total 0
drwxr-xr-x  2 root root 0 Jan  6 15:27 hiddev
drwxr-xr-x  2 root root 0 Jan  6 15:28 hub
drwxr-xr-x  2 root root 0 Jan  6 15:28 usb
drwxr-xr-x  2 root root 0 Jan  6 15:27 usbfs
drwxr-xr-x  2 root root 0 Jan  6 15:28 usbhid

If your 2.6.x system does not have the /sys/bus/usb directory, either you do not have sysfs mounted on /sys or the USB module(s) have not been loaded. (Check /proc/mounts to make sure sysfs is mounted.)

A USB UPS needs all of these drivers -- the USB device filesystem, the USB hub, the Human Interface Device subsystem driver, and the Human Interface Device driver. If you are compiling your own kernel, you want to enable

CONFIG_USB
CONFIG_USB_HID
CONFIG_USB_HIDDEV
CONFIG_USB_DEVICEFS

...as well as at least one USB Host Controller Driver...

CONFIG_USB_UHCI_HCD (linux-2.6.x)
CONFIG_USB_OHCI_HCD (linux-2.6.x)
CONFIG_USB_UHCI     (linux-2.4.x)
CONFIG_USB_OHCI     (linux-2.4.x)

Device Nodes

Apcupsd accesses USB UPSes via the hiddev device nodes. Typically these are located in /dev/hiddevN, /dev/usb/hiddevN or /dev/usb/hiddev/hiddevN (where N is a digit 0 thru 9). Some distributions (some Debian releases, possibly others) do not provides these device nodes for you, so you will have to make them yourself. Check /dev, /dev/usb, and /dev/usb/hiddev and if you cannot find the hiddevN nodes, run (as root) the examples/make-hiddev script from the apcupsd source distribution.

Modern Linux distributions using the 2.6 kernel create device nodes dynamically on the fly as they are needed. It is basically a hotplug system, giving a lot more power to the user to determine what happens when a device is probed or opened. It is also a lot more complicated.

Some early 2.6 distributions (Fedora Core 3, for one) do not include hiddev rules in their default udev rule set. The bottom line for apcupsd on such a system is that if the hiddevN is not created when you plug in your UPS, apcupsd will terminate with an error. The solution to the problem is to add a rule to the udev rules file. On Fedora FC3, this file is found in /etc/udev/rules.d/50-udev.rules. Start by adding the following line:

BUS="usb", SYSFS{idVendor}="051d", NAME="usb/hiddev%n"

Note that this rule uses obsolete udev syntax and is specific to FC3 and other distributions of similar vintage.

Then either reboot your system, or unplug and replug your UPS and then restart apcupsd. At that point a /dev/usb/hiddevN node should appear and apcupsd should work fine.

If you have several UPSes or you just want to give your UPS a fixed name, you can use rules like the following:

KERNEL=="hiddev*", SYSFS{serial}=="JB0319033692", SYMLINK="ups0"
KERNEL=="hiddev*", SYSFS{serial}=="JB0320004845", SYMLINK="ups1"

Note that this rule uses udev syntax that is appropriate only for distros such as RHEL4 and FC4 and others of a similar vintage.

More recent distros such as FC15 should use something like this:

KERNEL=="hiddev*", ATTRS{manufacturer}=="American Power Conversion", ATTRS{serial}=="BB0100009999  ", OWNER="root", SYMLINK+="ups0"

Replace the serial number in quotes with the one that corresponds to your UPS. Then whenever you plug in your UPS a symlink called ups0, ups1, etc. will be created pointing to the correct hiddev node. This technique is highly recommended if you have more than one UPS connected to the same server since rearranging your USB cables or even upgrading the kernel can affect the order in which devices are detected and thus change which hiddev node corresponds to which UPS. If you use the symlink-by-serial-number approach the link will always point to the correct device node.

You can use...

udevinfo -a -p /sys/class/usb/hiddev0/

...to get more information on the fields that can be matched besides serial number.

To find the available attributes to match (note that the serial is NOT always the UPS serial on the box or in the USB connect message in /var/log/messages), use:

udevadm info --attribute-walk --name=/dev/usb/hiddev0

An additional device-node-related problem is the use of dynamic minors. Some distributions, such as Mandrake 10, ship with a kernel having CONFIG_USB_DYNAMIC_MINORS turned on. This is not ideal for running with apcupsd, and the easiest solution is to turn CONFIG_USB_DYNAMIC_MINORS off and rebuild your kernel, or find a pre-built kernel with it off. For a kernel with CONFIG_USB_DYNAMIC_MINORS turned on to work with apcupsd, you must enable devfs. The following will tell you if devfs is enabled:

$ ps ax | grep devs

...which should give something like the following:

533 ?        S      0:00 devfsd /dev

What complicates the situation much more on Mandrake kernels is their security level since CONFIG_DYNAMIC_USB_MINORS is turned on, but on higher security levels devfs is turned off. The net result, is that in those situations hiddev is completely unusable so apcupsd will not work. So, in these cases, the choices are:

  1. Reduce the security level setting of the system (not sure if this is possible after the initial install).
  2. Custom build a high security kernel with devfs enabled and make sure devfs is mounted and devfsd is running.
  3. Custom build a high security kernel with dynamic minors disabled
  4. Use udev

Miscellaneous

If all these things check out and you still can't see the UPS, something is more seriously wrong than this manual can cover -- find expert help. If you are unable to list USB devices or drivers, you kernel may not be USB-capable and that needs to be fixed.

BSD USB Configuration

Known BSD USB Issues

Problem
FreeBSD lockups: Some users have experienced lockups (apcupsd stops responding) on FreeBSD systems.
Solution
Recent versions of Apcupsd have addressed this issue. Please upgrade to apcupsd-3.10.18 or higher.
Problem
FreeBSD kernel panics if USB cable is unplugged while apcupsd is running.
Solution
This is a kernel bug and is most easily worked around by not hot- unplugging the UPS while apcupsd is running. This issue may be fixed in recent FreeBSD kernels.

Platforms and Versions

The *BSD USB driver supports FreeBSD, OpenBSD and NetBSD. (Thanks go to the *BSD developers who kept a nearly identical interface across all three platforms.)

Kernel Configuration

Users of OpenBSD, NetBSD, and some versions of FreeBSD will need to rebuild the kernel in order to enable the ugen driver and disable the uhid driver. uhid is not sufficient for apcupsd at this time and we need to prevent it from grabbing the UPS device. You should make the following changes to your kernel config file:

FreeBSD (v5.4 and below, v6.0)
(you will not lose use of USB keyboard and mouse)
Disable: uhid
Enable: ugen
FreeBSD (v5.5, v6.1 and above)
(you will not lose use of USB keyboard and mouse)
Disable: (nothing)
Enable: ugen

This is the default configuration for a GENERIC kernel on many platforms so you most likely will not need to recompile.

NetBSD (v3.x and below)
(you will lose use of USB keyboard and mouse)
Disable: uhidev, ums, wsmouse, ukbd, wskbd, uhid
Enable: ugen
NetBSD (v4.0 and above)

You can use apcupsd on single USB port without disabling the USB keyboard and mouse on other ports, though all other devices will be disabled on the port you pick for your UPS.

First, decide which hub and port you wish to use. You can find out the hub and port numbers for any particular physical connector by plugging a USB device into it and looking at the messages printed by the kernel; you should messages something like this:

uxx0 at uhub0 port 1
uxx0: <some device name>

To use your APC UPS on this port, configure the kernel to prefer attachment of the ugen driver over other drivers on this hub and port only, by adding a line like this to your kernel config file:

ugen*   at uhub0 port 1 flags 1

(The "flags 1" forces the ugen to attach instead of anything else detected there.)

Configure and build that kernel as per the references below, and your UPS will now attach as a ugen device when plugged into that port.

Don't forget to 'cd /dev' and './MAKEDEV ugen1' (and 2 and so on) if you have more than one generic usb device on your system.

OpenBSD
(you will lose use of USB keyboard and mouse):
Disable: uhidev, ums, wsmouse, ukbd, wskbd, uhid
Enable: ugen

For detailed information on rebuilding your kernel, consult these references:

FreeBSD
http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig.html
NetBSD
http://www.netbsd.org/guide/en/chap-kernel.html
OpenBSD
http://www.openbsd.org/faq/faq5.html#Building

Verifying Device Detection and Driver

After building a properly configured kernel, reboot into that kernel and plug in your UPS USB cable. You should see a dmesg log message like the following:

ugen0: American Power Conversion Back-UPS RS 1500 FW:8.g6 .D USB FW:g6, rev 1.10/1.06, addr 2

Note that the ugen driver is called out. If you see uhid instead, it probably means you did not properly disable the uhid driver when you compiled your kernel or perhaps you're not running the new kernel.

You can also check with 'usbdevs -d' to get a list of USB devices recognized by the system as well as the drivers they are associated with. For example:

# usbdevs -d
addr 1: UHCI root hub, VIA
  uhub0
 addr 2: Back-UPS RS 1500 FW:8.g6 .D USB FW:g6, American Power Conversion
   ugen0

Device Nodes

Apcupsd communicates with the UPS through the USB generic device, ugen. You may or may not need to manually make ugen device nodes in /dev, depending on what OS you are using.

FreeBSD
No manual intervention needed. FreeBSD automatically creates the ugen nodes on demand.
NetBSD
By default, NetBSD only creates nodes for the first ugen device, ugen0. Check usbdevs -d to see which device your UPS was bound to and then create the appropriate node by running 'cd /dev ; ./MAKEDEV ugenN', where ugenN is the ugen device name shown by usbdevs. It is probably a good idea to create several sets of ugen nodes in case you add more USB devices.
OpenBSD
Similar to NetBSD, OpenBSD creates nodes for ugen0 and ugen1. Check usbdevs -d to see which device your UPS was bound to and then create the appropriate node by running 'cd /dev ; ./MAKEDEV ugenN', where ugenN is the ugen device name shown by usbdevs. It is probably a good idea to create several sets of ugen nodes in case you add more USB devices.

Windows USB Configuration

Platforms and Versions

Apcupsd supports USB UPSes on Windows XP and newer, including 64 bit systems.

USB Driver Installation

USB connected UPSes on Windows require a special driver. In most cases, this driver is automatically installed when you install Apcupsd. However in some cases you may need to install the driver manually. For detailed instructions, please see the install.txt file located in the driver folder of your Apcupsd install.

Verifying Device Detection and Driver

After installing Apcupsd (and the Apcupsd USB driver, if necessary), plug in your UPS USB cable and open the Windows Device Manager. You should see a American Power Conversion USB UPS (Apcupsd) listed under the Batteries section. If a device of that name does not appear, check that your UPS is powered on and that the USB cable is connected at both ends. Reinstall the driver as directed above if needed.

Solaris USB Configuration

Platforms and Versions

Apcupsd supports USB UPSes on Solaris 10 and higher. Both x86 and SPARC platforms are supported.

Building Apcupsd with USB

Some specific packages are necessary when building Apcupsd with USB support on Solaris. You must install the SUNWlibusb and SUNWlibusbugen packages BEFORE attempting to build Apcupsd. These packages can be found on the Solaris installation CDROMs and should be installed with the pkgadd utility.

You also should build using the gcc compiler and ccs make, not Sun's compiler. The appropriate make utility can be found in /usr/ccs/bin. gcc can be installed from packages included on the Solaris installation CDROMs.

Configure and build Apcupsd normally, as described in Building and Installing Apcupsd. Be sure to include the --enable-usb flag to configure.

After building, install Apcupsd as root using 'make install', then perform a reconfigure boot ('reboot -- -r'). During installation, Apcupsd will automatically configure your USB subsystem to attach APC USB devices to the ugen driver. This is a critical step and must be completed by a reconfigure boot. Note that the USB config changes will be reversed if you remove Apcupsd using 'make uninstall'.

Verifying Device Detection and Driver

After installing Apcupsd as described above and performing a reconfigure boot, plug in your UPS USB cable. You should see a series of dmesg log messages similar to the following:

Dec  5 17:50:50 sunblade usba: [ID 912658 kern.info] USB 1.10 device (usb51d,2) operating at low speed (USB 1.x) on USB 1.10 root hub: input@4, ugen0 at bus address 3
Dec  5 17:50:50 sunblade usba: [ID 349649 kern.info]    American Power Conversion Smart-UPS 1000 FW:600.1.D USB FW:1.2 AS0127232356
Dec  5 17:50:50 sunblade genunix: [ID 936769 kern.info] ugen0 is /pci@1f,0/usb@c,3/input@4
Dec  5 17:50:50 sunblade genunix: [ID 408114 kern.info] /pci@1f,0/usb@c,3/input@4 (ugen0) online

Note that the ugen driver is called out. If you do not see any dmesg entries related to your UPS, ensure that it is turned on and that the USB cable is connected at both ends. Also verify that you installed Apcupsd as root using the 'make install' command and that you performed a reconfigure boot afterward.

Device Nodes

Apcupsd communicates with the UPS through the USB generic device, ugen. The reconfigure boot performed after Apcupsd installation will ensure the correct device nodes are created. Once your UPS has been recognized in dmesg as shown above, you can check /dev/usb to see if the device nodes have appeared:

[user@sunblade /]$ ls /dev/usb/51d.2/*
cntrl0      cntrl0stat  devstat     if0in1      if0in1stat

(51d.2 is the vendor/product id for APC UPSes.)

Mac OS X (Darwin) USB Configuration

Platforms and Versions

Apcupsd supports USB UPSes on Mac OS X (Darwin) 10.4.x and higher. Both Intel and PowerPC platforms are supported.

Building Apcupsd with USB

Some specific packages are necessary when building Apcupsd with USB support on Darwin. You must install libusb-0.1.12 which can be obtained from MacPorts (http://www.macports.org) (formerly DarwinPorts) or Fink (http://fink.sourceforge.net) or downloaded and built by hand (http://www.libusb.org). You must not use libusb-1.x or higher (apcupsd does not support the new 1.0 APIs) nor any version earlier than 0.1.12 (earlier versions have a bug that apcupsd triggers). Generally that means you must use exactly 0.1.12. Note that Apcupsd is sensitive to the install location of libusb, so beware if you change it from the default.

Apcupsd should be built using gcc, preferably from the XCode development tools. Currently the maintainer is using gcc-4.0.1 from XCode 2.4. Other versions of gcc from other sources may also work.

Configure and build Apcupsd normally, as described in Building and Installing Apcupsd. Be sure to include the --enable-usb flag to configure.

After building, install Apcupsd as root using 'make install' and then reboot. During installation, Apcupsd will automatically install a simple dummy kext driver designed to prevent Apple's monitoring software from taking over the UPS. It is necessary to reboot in order to activate the kext. Note that this kext will be automatically removed if you uninstall Apcupsd using 'make uninstall', allowing Apple's monitoring tool to once again access the UPS.

Verifying Device Detection and Driver

After installing Apcupsd as described above and rebooting, plug in your UPS USB cable. You should notice that Darwin does NOT display the battery monitor tool in the menu bar. You can also check Apple Menu -> About This Mac -> More Info... -> USB to ensure that your UPS appears in the list of USB devices.

Building and Installing apcupsd

In general it is recommended to obtain a prebuilt binary package for your platform. Given how apcupsd must integrate into the shutdown mechanism of the operating system and the rate at which such mechanisms are changed by vendors, the platform ports in the apcupsd tree may become out of date. In some cases, binary packages are provided by the apcupsd team (RedHat, Mandriva, SuSE, Windows, Mac OS X). For other platforms it is recommended to check your vendor's package repository and third party repositories for recent binary packages before resorting to building apcupsd from scratch. Note that some vendors continue to distribute ancient versions of apcupsd with known defects. These packages should not be used.

Installation from Binary Packages

RPMS

For systems based on RPM packages, such as Red Hat and SuSE, apcupsd is available in binary RPM format. This is the simplest way to install. If you have no previous version of apcupsd on your machine and are creating a standalone configuration, simply install the RPM with a normal 'rpm -ihv' command. You're done, and can now skip the rest of this chapter and go straight to tweaking your run-time configuration file. (see After Installation)

If you have a previous installation, you can upgrade with a normal 'rpm -Uhv', but this may not upgrade the halt script. It may be better to do the upgrade as a remove 'rpm -e' followed by a fresh install 'rpm -ihv'.

After installation of the binary RPM, please verify carefully that /etc/rc.d/init.d/halt was properly updated and contains new script lines flagged with ***APCUPSD***.

Since there is no standard location for cgi-bin, the rpm will place the binary CGI programs in the directory /etc/apcupsd/cgi. To actually use them, you must copy or move them to your actual cgi-bin directory, which on many systems is located in /home/httpd/cgi-bin.

Microsoft Windows

The Windows version of apcupsd is distributed as a simple double-click installer. Installation is very simple and straight-forward: Simply double-click the installer executable and follow the instructions. See The Windows Version of apcupsd for further details.

Installation from Source

Installation from source might have to be be done different ways depending on what system you are running. The basic procedure involves getting a source distribution, running the configuration, rebuilding, and installing.

For building the system, we suggest that you run the configure and make processes as your normal UNIX user ID. The 'make install' must be run as root. But if your normal ID has an environment setup for using the C compiler, it's simpler to do that than to set up root to have the correct environment.

apcupsd requires gcc and g++ compilers as well as GNU make. Other compilers or BSD make will not work. GNU make is sometimes installed as gmake. The configure script will check for this and will inform you of what command to use to invoke GNU make.

The basic installation from a tar source file is rather simple:

  1. Unpack the source code from its tar archive.
  2. Go into the directory containing the source code.
  3. Run './configure' (with appropriate options as described below)
  4. 'make' or 'gmake'' as instructed by configure
  5. 'su' (i.e. become root)
  6. Stop any running instance of apcupsd. The command to do this will look like 'system-dependent-path/apcupsd stop'
  7. uninstall any old apcupsd This is important since the default install locations may have changed.
  8. 'make install' or 'gmake install'
  9. edit your /etc/apcupsd/apcupsd.conf file if necessary
  10. ensure that your halt script is properly updated
  11. Start the new apcupsd with: 'system-dependent-path/apcupsd start'

If all goes well, the './configure' will correctly determine which operating system you are running and configure the source code appropriately. configure currently recognizes the systems listed below in the Operating System Specifics section of this chapter and adapts the configuration appropriately. Check that the configuration report printed at the end of the configure process corresponds to your choice of directories, options, and that it has correctly detected your operating system. If not, redo the configure with the appropriate options until your configuration is correct.

Please note that a number of the configure options preset apcupsd.conf directive values in an attempt to automatically adapt apcupsd as best possible to your system. You can change the values in apcupsd.conf at a later time without redoing the configuration process by simply editing the apcupsd.conf file.

Other configuration options can be used to set up the installation of HTML documentation and optional modules, notably the CGI interface that enables the UPS state to be queried via the Web. You will find a complete reference later in this chapter.

In general, you will probably want to supply a more elaborate configure statement to ensure that the modules you want are built and that everything is placed into the correct directories.

On Red Hat, a fairly typical configuration command would look like the following:

CFLAGS="-g -O2" LDFLAGS="-g" ./configure \
  --enable-usb \
  --with-upstype=usb \
  --with-upscable=usb \
  --prefix=/usr \
  --sbindir=/sbin \
  --with-cgi-bin=/var/www/cgi-bin \
  --enable-cgi \
  --with-log-dir=/etc/apcupsd

By default, 'make install' will install the executable files in /sbin, the manuals in /usr/man, and the configuration and script files in /etc/apcupsd. In addition, if your system is recognized, certain files such as the startup script and the system halt script will be placed in appropriate system directories (usually subdirectories of /etc/rc.d).

Verifying a Source Installation

There are a number of things that you can do to check if the installation (make install) went well. The fist is to check where the system has installed apcupsd using 'which' and 'whereis'. On my Red Hat system, you should get the following (lines preceded with a $ indicate what you type):

$ which apcupsd
/sbin/apcupsd
$ whereis apcupsd
apcupsd: /sbin/apcupsd /etc/apcupsd /etc/apcupsd.conf
/etc/apcupsd.status /usr/man/man8/apcupsd.8.gz
/usr/man/man8/apcupsd.8

If you find an apcupsd in /usr/sbin, /usr/local/sbin, /usr/lib, or another such directory, it is probably a piece of an old version of apcupsd that you can delete. If you are in doubt, delete it, then rerun the 'make install' to ensure that you haven't deleted anything needed by the new apcupsd. Please note that the files specified above assume the default installation locations.

As a final check that the 'make install' went well, you should check your halt script (in /etc/rc.d on SUSE systems, and in /etc/rc.d/init.d on Red Hat systems) to see that the appropriate lines have been inserted in the correct place. Modification of the halt script is important so that at the end of the shutdown procedure, apcupsd will be called again to command the UPS to turn off the power. This should only be done in a power failure situation as indicated by the presence of the /etc/powerfail file, and is necessary if you want your machine to automatically be restarted when the power returns. On a Red Hat system, the lines containing the # ***apcupsd*** should be inserted just before the final halt command:

# Remount read only anything that's left mounted.
#echo "Remounting remaining filesystems (if any) readonly"
mount | awk '/ext2/ { print $3 }' | while read line; do
    mount -n -o ro,remount $line
done

# See if this is a powerfail situation.                               # ***apcupsd***
if [ -f /etc/apcupsd/powerfail ]; then                                # ***apcupsd***
   echo                                                               # ***apcupsd***
   echo "APCUPSD will now power off the UPS"                          # ***apcupsd***
   echo                                                               # ***apcupsd***
   /etc/apcupsd/apccontrol killpower                                  # ***apcupsd***
   echo                                                               # ***apcupsd***
   echo "Please ensure that the UPS has powered off before rebooting" # ***apcupsd***
   echo "Otherwise, the UPS may cut the power during the reboot!!!"   # ***apcupsd***
   echo                                                               # ***apcupsd***
fi                                                                    # ***apcupsd***

# Now halt or reboot.
echo "$message"
if [ -f /fastboot ]; then
 echo "On the next boot fsck will be skipped."
elif [ -f /forcefsck ]; then
 echo "On the next boot fsck will be forced."
fi

The purpose of modifying the system halt files is so that apcupsd will be recalled after the system is in a stable state. At that point, apcupsd will instruct the UPS to shut off the power. This is necessary if you wish your system to automatically reboot when the mains power is restored. If you prefer to manually reboot your system, you can skip this final system dependent installation step by specifying the disable-install-distdir option on the './configure' command (see below for more details).

The above pertains to Red Hat systems only. There are significant differences in the procedures on each system, as well as the location of the halt script. Also, the information that is inserted in your halt script varies from system to system. Other systems such as Solaris require you the make the changes manually, which has the advantage that you won't have any unpleasant surprises in your halt script should things go wrong. Please consult the specific system dependent README files for more details.

Please note that if you install from RPMs for a slave machine, you will need to remove the changes that the RPM install script made (similar to what is noted above) to the halt script. This is because on a slave machine there is no connection to the UPS, so there is no need to attempt to power off the UPS. That will be done by the master.

Configure Options

All the available configure options can be printed by entering:

./configure --help

When specifying options for './configure', if in doubt, don't put anything, since normally the configuration process will determine the proper settings for your system. The advantage of these options is that it permits you to customize your version of apcupsd. If you save the './configure' command that you use to create apcupsd, you can quickly reset the same customization in the next version of apcupsd by simply re-using the same command.

The following command line options are available for configure to customize your installation.

--prefix=path This defines the directory for the non-executable files such as the manuals. The default is /usr.
--sbindir=path This defines the directory for the executable files such as apcupsd. The default is /sbin. You may be tempted to place the executable files in /usr/sbin or /usr/local/sbin. Please use caution here as these directories may be unmounted during a shutdown and thus may prevent the halt script from calling apcupsd to turn off the UPS power. Though your data will be protected, in this case, your system will probably not be automatically rebooted when the power returns
--enable-cgi This enables the building of the CGI programs that permit Web browser access to apcupsd data. This option is not necessary for the proper execution of apcupsd.
--with-cgi-bin=path
 The with-cgi-bin configuration option allows you to define the directory where the CGI programs will be installed. The default is /etc/apcupsd, which is probably not what you want.
--enable-apcsmart
 Turns on generation of the APC Smart driver (default).
--enable-dumb Turns on generation of the dumb signalling driver code (default).
--enable-usb Turns on generation of the USB driver code. By default this is disabled.
--enable-net Turns on generation of the NIS network driver for slaves. For each slave, this is the only driver needed. This driver works by reading the information from the the configured master using the NIS (Network Information Services) interface.
--enable-snmp Turns on generation of the SNMP driver. This driver accesses the UPS over the network using SNMP. This is compatible only with UPSes equipped with an SNMP or Web/SNMP management card. By default this is enabled.
--enable-net-snmp
 Turns on generation of the obsolete NET-SNMP driver. This driver was the precursor to the current snmp driver and is now obsolete. It is available as a fallback if the new driver cannot be used for some reason. By default this is disabled.
--enable-pcnet Turns on generation of the PCNET (PowerChute Network Shutdown) driver. This driver accesses the UPS over the network using APC's custom protocol. This driver can be used as an alternative to SNMP for UPSes equipped with a modern Web/SNMP management card.
--enable-modbus
 Turns on generation of the MODBUS/RS232 driver (default)
--enable-modbus-usb
 Turns on generation of the MODBUS/USB driver
--enable-test This turns on a test driver that is used only for debugging. By default it is disabled.
--enable-gapcmon
 This option enables building the GTK GUI front-end for apcupsd. Building this package requires numerous GNOME libraries. The default is disabled.
--enable-apcagent
 This option enables building the apcagent menubar application on Mac OS X platforms. The default is disabled.
--with-libwrap=path, --with-libwrap
 This option when enabled causes apcupsd to be built with the TCP WRAPPER library for enhanced security. In most cases, the path is optional since configure will determine where the libraries are on most systems.
--with-nologin=path
 This option allows you to specify where apcupsd will create the nologin file when logins are prohibited. The default is /etc
--with-pid-dir=path
 This option allows you to specify where apcupsd will create the process id (PID) file to prevent multiple copies from running. The default is system dependent but usually /var/run.
--with-log-dir=path
 This option allows you to specify where apcupsd will create the EVENTS and STATUS log files. The default is /etc/apcupsd. This option simply sets the default of the appropriate path in the apcupsd.conf file, which can be changed at any later time.
--with-lock-dir=path
 This option allows you to specify where apcupsd will create the serial port lock file. The default is system-dependent but usually /var/lock. This option simply sets the appropriate path in the apcupsd.conf file, which can be changed at any later time.
--with-pwrfail-dir=path
 This option allows you to specify where apcupsd will create the powerfail file when a power failure occurs. The default is system dependent but usually /etc.
--with-serial-dev=device-name
 This option allows you to specify where apcupsd will look for the serial device that talks to the UPS. The default is system dependent, but often /dev/ttyS0. This option simply sets the appropriate device name in the apcupsd.conf file, which can be changed at any later time.
--with-nis-port=port
 This option allows you to specify what port apcupsd will use for the Network Information Server (the CGI programs). The default is system dependent but usually 3551 because that port has been officially assigned to apcupsd by the IANA. This option simply sets the appropriate port in the apcupsd.conf file, which can be changed at any later time.
--with-nisip=ip-address
 This option allows you to specify the value that will be placed on then NISIP directive in the configuration file. The default is 0.0.0.0. No checking is done on the value entered, so you must ensure that it is a valid IP address.
--with-net-port=port
 This option allows you to specify what port apcupsd will use for Master and Slave communications. The default is system dependent but usually 6666. This option simply sets the appropriate port in the apcupsd.conf file, which can be changed at any later time.
--with-upstype=type
 This option allows you to specify the type of UPS that will be connected to your computer. The default is: smartups. This option simply sets the appropriate UPS type in the apcupsd.conf file, which can be changed at any later time.
--with-upscable=cable
 This option allows you to specify what cable you are using to connect to the UPS. The default is: smart. This option simply sets the appropriate UPS cable in the apcupsd.conf file, which can be changed at any later time.
--disable-install-distdir
 This option modifies the apcupsd Makefiles disable installation of the distribution (platform) directory. Generally, this used to do a full installation of apcupsd except the final modification of the operating system files (normally /etc/rc.d/halt, etc.). This is useful if your operating system is not directly supported by apcupsd or if you want to run two copies of apcupsd on the same system. This option can also be used by those of you who prefer to manually reboot your system after a power failure or who do not want to modify your system halt files.

Compilers and Options

Some systems require unusual options for compilation or linking that the './configure' script does not know about. You can specify initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this:

CFLAGS="-O2 -Wall" LDFLAGS= ./configure

Or on systems that have the env program, you can do it like this:

env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure

Or for example on the Sun Solaris system, you can use:

setenv CFLAGS -O2
setenv LDFLAGS -O
./configure

You can get a listing of all available options by doing:

./configure --help

or simply see the previous section of this manual.

Operating System Specifics

With the exception of Linux SUSE and Linux Red Hat systems used by the developers, we rely on users to help create installation scripts and instructions as well as to test that apcupsd runs correctly on their system. As you can imagine, most of these people are system administrators rather than developers so they are very busy and don't always have time to test the latest releases. With that in mind, we believe that you will find that a lot of very valuable work has been already done to make your installation much easier (and probably totally automatic).

Below, you will find a list of operating systems for which we have received installation files:

Debian

This port is complete and is being used by several users. Since Debian build and install procedures are somewhat particular, we have put the extra Debian information into the following two subdirectories: platforms/debian/examples and platforms/debian/packageinfo

You can also find the official Debian packages on the Debian site at:

FreeBSD

This port is complete and is being used by several users.

You will need to install and use GNU make (aka gmake) instead of the BSD make supplied with the system.

On the FreeBSD OS, there is no known way for a user program to get control when all the disks are synced. This is needed for apcupsd to be able to issue the killpower command to the UPS so that the UPS shuts off the power. To accomplish the same thing on FreeBSD systems, make sure you have a SmartUPS and that your UPS shutdown grace period is set sufficiently long so that you system will power down (usually 2 minutes), the use the --kill-on-powerfail option on the apcupsd command line.

HPUX

Status of this port is unknown.

NetBSD

You will need to install and use GNU make (aka gmake) instead of the BSD make supplied with the system.

Mac OS X Darwin

On OS X (Darwin), apcupsd can be built with configure defaults. The USB driver can be enabled, as per the directions on Mac OS X (Darwin) USB Configuration Apcupsd may be usable on OS X with a smart serial device, but certainly does work as a NIS client or using a USB interface.

The startup information will be installed in /Library/StartupItems/apcupsd which is part of darwin's SystemStartup.

OpenBSD

You will need to install and use GNU make (aka gmake) instead of the BSD make supplied with the system.

Ensure that you read the distributions/openbsd/README file before running apcupsd. There are some critical differences in how the OpenBSD implementation operates when the UPS batteries are exhausted. Failure to take this into account may result in the system not being fully halted when power is lost.

Red Hat Systems

Red Hat systems are fully supported, and by following the standard installation instructions given above, you should experience few or no problems.

Slackware

Slackware systems are fully supported, and by following the standard installation instructions given above, you should experience few or no problems.

SUSE

SUSE systems are fully supported, and by following the standard installation instructions given above, you should experience few or no problems.

Sun Solaris

Please read this before attempting to compile or install the beta software. It contains important information that will make your efforts easier.

Before running './configure', please be sure that you do not have /usr/ucb on your path. This may cause the configure to choose the wrong shutdown program. If configure detects that /usr/usb is on your path, it will print a warning message. Please follow the advice to avoid shutdown problems.

Your normal UNIX user ID must own the source tree directories, and you must have the normal development tools in your path. This includes make, the compiler, the M4 preprocessor, the linker, and ar or ranlib. If the user you are logged in as can compile and link a C program from a source file, then you have all the required tools available.

You will want to install the executables in a directory that remains mounted during the shutdown. Solaris will unmount almost everything except the root directories. Since the ability to power the UPS off requires access to the executable programs, they need to be in a directory that will never be unmounted. And since they should also be in a directory that normal users cannot get into, /sbin is the default. However, please be aware that if you want to follow Sun's filesystem conventions you would use the following:

./configure \
   --prefix=/opt/apcupsd \
   --sbindir=/etc/opt/apcupsd/sbin \
   --sysconfdir=/etc/opt/apcupsd \
   --with-cgi-bin=/opt/apcupsd/cgi-bin

The way to setup the /sbin directory as the executables directory is to pass configure the --sbindir=/sbin option. No other arguments should be required, and your setup and platform should be detected automatically by configure.

Once you have run configure, you will need to do a 'gmake'. Once the make has completed with no errors, you must su to root to complete the install. After the su, you may not have a path to the make program anymore. In that case, you should do the 'gmake install' step as:

gmake install

Once the install completes, you must edit the /sbin/rc0 script as detailed below, then exit from the su'ed shell.

In order to support unattended operation and shutdown during a power failure, it's important that the UPS remove power after the shutdown completes. This allows the unattended UPS to reboot the system when power returns by re-powering the system. Of course, you need autoboot enabled for your system to do this, but all Solaris systems have this by default. If you have disabled this on your system, please re-enable it.

To get the UPS to remove power from the system at the correct time during shutdown, i.e., after the disks have done their final sync, we need to modify a system script. This script is /sbin/rc0.

We do not have access to every version of Solaris, but we believe this file will be almost identical on every version. Please let us know if this is not true.

At the very end of the /sbin/rc0 script, you should find lines just like the following:

# unmount file systems. /usr, /var and /var/adm are not unmounted by umountall
# because they are mounted by rcS (for single user mode) rather than
# mountall.
# If this is changed, mountall, umountall and rcS should also change.
/sbin/umountall
/sbin/umount /var/adm >/dev/null 2>\&1
/sbin/umount /var >/dev/null 2>\&1
/sbin/umount /usr >/dev/null 2>\&1

echo 'The system is down.'

We need to insert the following lines just before the last 'echo':

#see if this is a powerfail situation
if [ -f /etc/apcupsd/powerfail ]; then
        echo
        echo "APCUPSD will power off the UPS"
        echo
        /etc/apcupsd/apccontrol killpower
        echo
        echo "Please ensure that the UPS has powered off before rebooting"
        echo "Otherwise, the UPS may cut the power during the reboot!!!"
        echo
fi

We have included these lines in a file called rc0.solaris in the distributions/sun subdirectory of the source tree. You can cut and paste them into the /sbin/rc0 file at the correct place, or yank and put them using vi or any other editor. Note that you must be root to edit this file.

You must be absolutely sure you have them in the right place. If your /sbin/rc0 file does not look like the lines shown above, do not modify the file. Instead, email a copy of the file to the maintainers, and we will attempt to figure out what you should do. If you mess up this file, the system will not shut down cleanly, and you could lose data. Don't take the chance.

You will then need to make the normal changes to the /etc/apcupsd/apcupsd.conf file. This file contains the configuration settings for the package. It is important that you set the values to match your UPS model and cable type, and the serial port that you have attached the UPS to. People have used both /dev/ttya and /dev/ttyb with no problems. You should be sure that logins are disabled on the port you are going to use, otherwise you will not be able to communicate with the UPS. If you are not sure that logins are disabled for the port, run the 'admintool' program as root, and disable the port. The 'admintool' program is a GUI administration program, and required that you are running CDE, OpenWindows, or another XWindows program such as KDE.

Solaris probes the serial ports during boot, and during this process, it toggles some handshaking lines used by dumb UPSes. As a result, particularly for simple signalling "dumb" UPSes it seems to kick it into a mode that makes the UPS think it's either in a calibration run, or some self-test mode. Since at this point we are really not communicating with the UPS, it's pretty hard to tell what happened. But it's easy to prevent this, and you should. Disconnect the UPS, and boot the system. When you get to a login prompt, log in as root. Type the following command:

eeprom com1-noprobe=true

or

eeprom com2-noprobe=true

depending on which com port your UPS is attached to. Then sync and shutdown the system normally, reattach the UPS, and reboot. This should solve the problem. However, we have some reports that recent versions of Solaris (7 & 8) appear to have removed this eeprom option and there seems to be no way to suppress the serial port probing during boot.

At this point, you should have a complete installation. The daemon will load automatically at the next boot. Watch for any error messages during boot, and check the event logs in /etc/apcupsd. If everything looks OK, you can try testing the package by removing power from the UPS. NOTE! if you have a voltage-signalling UPS, please run the first power tests with your computer plugged into the wall rather than into the UPS. This is because dumb serial-port UPSes have a tendency to power off if your configuration or cable are not correct.

As a user, your input is very helpful in solving problems with the package, and providing suggestions and future directions for the development of the package. We are striving to provide a useful package that works across all platforms, and welcome your feedback.

Unknown System

During the './configure', if apcupsd does not find one of the systems for which it has specific installation programs, it will set the Operating System to unknown and will use the incomplete installation scripts that are in platforms/unknown. You will be on your own, or you can ask the developers list (apcupsd-users@lists.sourceforge.net) for installation instructions. This directory also contains a hint file for Linux From Scratch, which could be helpful for other systems as well.

Windows Systems

Appropriate scripts (actually Windows batch files) are included with the Apcupsd Win32 installer package.

After Installation

Checking Your Configuration File

Once you have installed apcupsd, either from a binary package or by building from source, your next step should be to inspect your /etc/apcupsd/apcupsd.conf file to make sure it is valid.

You can read the complete reference on configuration directives (Configuration Directive Reference), but if you are setting up a normal standalone configuration you should only need to check (and possibly fix) the first three items listed below.

Your UPSTYPE should be the UPS's protocol type: dumb, apcsmart, usb, net, pcnet, or snmp. Your UPSCABLE should be the type of cable you are using.

DEVICE should be set to the path of the device node (usually in /dev) to use to communicate with the UPS. This is used primarily for serial port connections. If you have a USB device, it is better not to specify a DEVICE directive by leaving it black or commenting it out. Apcupsd will automatically search for your device in the standard places. If you specify a DEVICE, it should be the name of the device that apcupsd is to use to communicate with the UPS.

If the first time you execute apcupsd, you get a message to the effect that the Apcupsd USB driver is missing, it means that you most likely forgot to put --enable-usb on your './configure' command line.

The Configuration Examples chapter of this manual provides the essential characteristics of each main type of configuration file. After those elements are correct, apcupsd should run, and then it is only a matter of customization of your setup.

Arranging for Reboot on Power-Up

The final consideration for a automatic reboot after a full power down is to ensure that your computer will automatically reboot when the power is restored.

This is not the normal behavior of most computers as shipped from the factory. Normally after the power is cut and restored, you must explicitly press a button for the power to actually be turned on. You can test your computer by powering it down; shutting off the power (pull the plug); then plugging the cord back in. If your computer immediately starts up, good. There is nothing more to do.

If your computer does not start up, manually turn on the power (by pressing the power on button) and enter your computer's SETUP program (often by pressing DEL during the power up sequence; sometimes by pressing F10). You must then find and change the appropriate configuration parameter to permit instant power on.

Normally, this is located under the BOOT menu item, and will be called something such as Restore on AC/Power Loss or Full-On. The exact words will vary according to the ROM BIOS provider. Generally you will have three options: Last State, Power On, and Power Off. Although Last State should normally work, we recommend setting your computers to Power On. This means that whenever the power is applied they are on. The only way to shut them off is to pull the plug or to have a special program that powers them off (/sbin/poweroff on Linux systems).

If after making all the changes suggested above, you cannot get your computer to automatically reboot, you might examine your halt script (/etc/rc.d/init.d/halt in the case of Red Hat Linux) and see if the final line that performs the halt or reboot contains the -p option for powering down the computer. It should not with the logic used by apcupsd, but if it does, the -p option could cause your computer to power off while the UPS is still suppling power (i.e. before the UPS kills the power). Depending on the setting of your BIOS, it may prevent your computer from restarting when the power returns. As already mentioned, this should not apply, but in case of problems it is worth a try.

Making sure apcupsd Is Running

The simplest way to invoke apcupsd is from the command line by entering:

/sbin/apcupsd

To do so, you must be root. However, normally, you will want apcupsd started automatically when your system boots. On some systems with installation support (e.g. SUSE and Red Hat), the installation procedure will create a script file that you will be automatically invoked when your system reboots. On other systems, you will have to invoke apcupsd from your rc.local script.

On Red Hat systems, this script file that automatically invokes apcupsd on system start and stops is /etc/rc.d/init.d/apcupsd

To start apcupsd manually (as you will probably do immediately following the installation), enter the following:

/etc/rc.d/init.d/apcupsd start

To understand how this file is automatically invoked at system startup and shutdown, see the man pages for chkconfig(8).

On SUSE systems, the script file that automatically invokes apcupsd on system start and stops is /etc/rc.d/apcupsd.

To start apcupsd manually (as you will probably do immediately following the installation), enter the following:

/etc/rc.d/apcupsd start

Normally, when properly installed, apcupsd will be started and stopped automatically by your system. Unfortunately, the details are different for each system. Below, we give the commands for selected systems. Alternatively, there are simple stopapcupsd and startapcupsd scripts in the examples directory, or you can modify one of the scripts in the distributions directory to meet your needs.

To stop apcupsd you can do the following:

On Red Hat systems:

/etc/rc.d/init.d/apcupsd stop

On SUSE systems:

/etc/rc.d/apcupsd stop

Please see the Testing Apcupsd chapter for more details on insuring that apcupsd is running properly.

Configuration Examples

A Simple USB Configuration

If you have a USB UPS, the essential elements of your apcupsd.conf file should look like the following:

## apcupsd.conf v1.1 ##
UPSCABLE usb
UPSTYPE usb
DEVICE
LOCKFILE /var/lock
UPSCLASS standalone
UPSMODE disable

Notice that we have not specified a device. In doing so, apcupsd will try all the well known USB ports. We strongly recommend you use this (empty device address) form unless you have a good reason to do otherwise.

Please use the explicit specifications of a device only if you know exactly what you are doing. In general, it is much easier to let apcupsd find the device itself.

Please see USB Configuration for detailed help on setting up your system to work with a USB UPS.

A Simple Configuration for a Serial SmartUPS

If you have a Smart UPS using the serial cable supplied by APC, or you build a CUSTOM SMART cable outlined in the cables chapter, a very simple configuration file would look like the following:

## apcupsd.conf v1.1 ##
UPSCABLE smart
UPSTYPE apcsmart
DEVICE /dev/ttyS0
LOCKFILE /var/lock
UPSCLASS standalone
UPSMODE disable

Normally you would have many more configuration directives to completely customize your installation, but this example shows you the minimum required.

A Simple Configuration for a Simple Signaling or Dumb

If you have a simple signaling or dumb UPS such as a BackUPS, you will need to know exactly what cable you have and specify it on the UPSCABLE directive. Please see the list of UPSes versus cables in the beginning of this document for more information. The cable number is normally stamped in the plastic at one end of the cable. If you specify the wrong cable, it is very likely that at the first power failure, your computer will be immediately shutdown. This is an unfortunate consequence of the dumb signaling mode. To avoid this, first replace /etc/apcupsd/apccontrol with safe.apccontrol found in the examples directory, then test until everything works correctly. Once you have the correct cable, be sure to remember to reinstall the correct apccontrol file and test that your computer is correctly shutdown during a power failure.

## apcupsd.conf v1.1 ##
UPSCABLE (number of cable you have)
UPSTYPE dumb
DEVICE /dev/ttyS0
LOCKFILE /var/lock
UPSCLASS standalone
UPSMODE disable

If your cable does not have low battery detection, as is the case with some older models, you will also need to define TIMEOUT nnn where you set nn to be the number of seconds on a power failure after which a shutdown is effected.

Normally you would have many more configuration directives to completely customize your installation, but this example shows you the minimum required.

NIS Server/Client Configuration Using the Net Driver

NIS (Network Information Server) mode allows for communication between instances of apcupsd running on different hosts. Only one of those hosts, the server, needs to talk to the UPS directly. The others, clients, obtain information about the state of the UPS by querying the server. NIS is not related to Sun's NIS/YP services.

NIS clients and servers require that apcupsd be compiled with the Net Driver --enable-net. This is typically enabled by default.

The NIS server is connected to the UPS and should be configured exactly as a standalone configuration, but with NETSERVER on. In all other respects, the server should be configured in standalone mode. You may also set the NIS server specific options NISIP to restrict which IP address of the server which apcupsd listens on. The default, 0.0.0.0, means to list on all of the server host's IP addresses; NISPORT (default 3551) to set which TCP port the server listens on; and EVENTSFILE and EVENTSFILEMAX to provide information about the last few events to clients. You may also need to modify your firewall rules on the server's host to allow traffic to the NISPORT.

For the NIS client computer, you will have a configuration that looks something like what follows. What is important is that you get the information from an UPSCABLE ether with UPSTYPE net over the network and you must specify the address of a NIS server using DEVICE. The client apcupsd will then poll the NIS server specified in DEVICE every POLLTIME seconds (formerly NETTIME).

## apcupsd.conf v1.1 ##
UPSCABLE ether
UPSTYPE net
LOCKFILE /var/lock
DEVICE server-network-address:3551
UPSCLASS standalone
UPSMODE disable
POLLTIME 10

The DEVICE is set to server-address:port, where server-address is the fully qualified domain name or IP address of the apcupsd NIS server, and port is the NISPORT that the server is listening on. The default is 3551, but older versions of apcupsd used port 7000.

If you set POLLTIME too large, your client may not see the change in state of the NIS server before the server has shutdown. Normally, you have at least 30 seconds of grace time between the time the NIS server decides to shutdown and the time it no longer responds. Your slave must poll during this interval.

Any client run using the Net driver will shutdown when its own timers expire or when the NIS server shuts down, whichever occurs first. This means that if you want the slave to shutdown before the server, you need only set BATTERYLEVEL, MINUTES or TIMEOUT on the client for a faster shutdown than the values defined on the NIS server. This can often be useful if the slave is less important than the master and you wish to reduce battery power consumption so that the master can remain up longer during a power outage.

NIS clients work principally by reading the STATFLAG record that is sent by the NIS server (present in the output of apcaccess). The low 16 bits are the standard APC status flag, and the upper 16 bits represent the internal state of apcupsd, so the slave can see when the power fails and know when to shutdown.

It would be possible to have a client also work as a server, but that would increase the delay of information getting from the UPS to the secondary client.

Differences between NIS Client/Server and the old (now removed) Master/Slave modes

The difference between the NIS mode and the removed master/slave mode is that the NIS server has no explicit knowledge of the slaves. The NIS server makes its information available via the net (NIS), and the NIS slaves read it. When the NIS server is going to shutdown, it makes the information available to any NIS slave that polls it, but the NIS server does not explicitly call each NIS slave as is the case in the Master/Slave networking described several sections above.

Think of the difference as push (Master/Slave) vs. pull (NIS-based). In the case of M/S, the master makes all the shutdown decisions and notifies the slaves when they are to shut down or when some other interesting event happens. The slaves just do whatever the master says, whenever the master says to. On the other hand, with the NIS-based network config you basically "publish" the UPS status from one server and then your clients view that status and make their own decisions.

PowerChute Network Shutdown Driver (PCNET)

As of 3.14, Apcupsd supports the PowerChute Network Shutdown protocol. This is an alternative to SNMP for use with APC's AP9617 family of network smartslot modules. Note that the older AP9606 modules do not support PCNET.

To enable PCNET support, configure with the --enable-pcnet flag. This is typically enabled by default.

The required apcupsd.conf settings are straightforward:

## apcupsd.conf v1.1 ##
UPSCABLE ether
UPSTYPE pcnet
LOCKFILE /var/lock
DEVICE ipaddr:user:passphrase
UPSCLASS standalone
UPSMODE disable

The DEVICE setting specifies the IP address of the UPS as well as the username and authentication passphrase to use. Note that the username and passphrase are not the Web/SNMP login credentials. They are separate settings. The default username on a new card is "apc" and the default passphrase is "admin user phrase". To change the passphrase, log in to the Web UI and go to the UPS tab, then to PowerChute -> Configuration. (This assumes firmware v3.3.1. Other versions may place the setting elsewhere.) The password must be a minimum of 15 characters long. The web UI will silently ignore shorter passwords and does not give an error message. There is no apparent way to change the username.

Note that you may leave DEVICE blank and Apcupsd will accept information from any PCNET UPS on the network, however it will be very insecure since an attacker could easily send packets crafted to cause your server to shut down. Using the ipaddr, user, and passphrase will prevent this behavior.

You may need to take steps to ensure networking stays active during your OS's shutdown sequence in order for the PCNET driver to power off the UPS (the so-called "killpower" operation). On a Linux distro, you can use commands such as...

chkconfig --level 0 network on
chkconfig --level 0 iptables on

...to make sure networking stays up.

MODBUS Driver

MODBUS is APC's replacement for the aging 'apcsmart' (aka UPS-Link) protocol. It is recommended for modern (ex: SMT series) Smart-UPS models. As of 3.14.11, apcupsd supports the MODBUS protocol over RS232 serial interfaces. As of 3.14.13, apcupsd supports the MODBUS protocol over USB.

Not all APC UPSes support MODBUS. New 2013 year Smart-UPS models are likely to support it out-of-the-box and firmware updates are available for some older models. APC/Schneider tech support is your best point of contact for determining if a certain model will support MODBUS. That said, APC knowledge base article FA164737 indicates MODBUS support is available for the majority of the SMC, SMT, and SMX model lines.

The required apcupsd.conf settings for MODBUS are straightforward.

For MODBUS serial RS232:

## apcupsd.conf v1.1 ##
UPSCABLE smart
UPSTYPE modbus
DEVICE /dev/ttyS0
LOCKFILE /var/lock
UPSCLASS standalone
UPSMODE disable

The DEVICE setting identifies the serial port to which the UPS is connected. This can take the form of COM1, etc. on Windows or /dev/XXX on UNIX systems.

You should use the APC-supplied serial cable (P/N 940-0625A) that ships with the UPS. Other 'smart' type cables may work, but only 940-0625A has been formally tested at this time.

For MODBUS USB:

## apcupsd.conf v1.1 ##
UPSCABLE usb
UPSTYPE modbus
DEVICE
LOCKFILE /var/lock
UPSCLASS standalone
UPSMODE disable

The DEVICE setting can be left blank or, optionally, set to the serial number of the UPS. If DEVICE is blank, apcupsd will attach to the first APC UPS it finds, otherwise it will attach to the specific UPS identified by the serial number.

Note that most UPSes ship with MODBUS support disabled by default. You must use the UPS's front panel menu to enable MODBUS protocol support before apcupsd will be able to communicate with the UPS. You may need to enable the "Advanced" menu option before the MODBUS protocol option will be visible.

Testing Apcupsd

The following testing procedures apply for the most part to SmartUPSes, whether USB or serial. If you have a dumb voltage-signalling UPS, your testing procedures will be somewhat different, and you should see the section on Testing Serial UPSes (see Testing Serial-Line UPSes).

Process-Status Test

After you start apcupsd, execute the following command:

ps fax

or the equivalent for your system. You should see something similar to the following output.

632 ?        S      0:00 /sbin/apcupsd -f /etc/apcupsd/apcupsd.conf
841 ?        S      0:00  \_ /sbin/apcupsd -f /etc/apcupsd/apcupsd.conf
842 ?        S      0:00      \_ /sbin/apcupsd -f /etc/apcupsd/apcupsd.conf

This indicates that apcupsd is up and running and has started the two standard threads in addition to the main thread.

If you see only one instance of apcupsd running, don't worry about it as this is normal on most non-Linux systems, and on Linux 2.6.x kernels.

If you do not find that apcupsd is in the above list, the most likely problem is a configuration file glitch. If no messages were printed, you should check your system log (normally /var/log/messages) where you will find one or messages indicating the nature of the problem.

Logging Test

Once you have established that the proper processes are running, do a tail of the system log file, normally /var/log/messages:

tail /var/log/messages

You should see output that looks similar to the following:

Dec 5 17:01:05 matou apcupsd[5917]: apcupsd 3.7.2 startup succeeded

These messages should also appear in the temporary file (/etc/apcupsd/apcupsd.events) if you are using the default configuration file. If you have installed the RPM, they will probably be in /var/log/apcupsd.events.

apcaccess Test

This test consists of running apcaccess to see if apcupsd is properly updating its internal variables. Please note that you must enable the apcupsd Network Information Server in your configuration file for apcaccess to work. This is done by setting:

NETSERVER on
NISPORT 3551

in your apcupsd.conf file.

To run the apcaccess test, use the following command:

apcaccess status

Depending on the type of UPS you have, you will get slightly different output, but an example For a Smart-UPS is as follows:

APC      : 001,048,1088
DATE     : Fri Dec 03 16:49:24 EST 1999
HOSTNAME : daughter
RELEASE  : 3.7.2
CABLE    : APC Cable 940-0024C
MODEL    : APC Smart-UPS 600
UPSMODE  : Stand Alone
UPSNAME  : SU600
LINEV    : 122.1 Volts
MAXLINEV : 123.3 Volts
MINLINEV : 122.1 Volts
LINEFREQ : 60.0 Hz
OUTPUTV  : 122.1 Volts
LOADPCT  :  32.7 Percent Load Capacity
BATTV    : 26.6 Volts
BCHARGE  : 095.0 Percent
MBATTCHG : 15 Percent
TIMELEFT :  19.0 Minutes
MINTIMEL : 3 Minutes
SENSE    : Medium
DWAKE    : 000 Seconds
DSHUTD   : 020 Seconds
LOTRANS  : 106.0 Volts
HITRANS  : 129.0 Volts
RETPCT   : 010.0 Percent
STATFLAG : 0x08 Status Flag
STATUS   : ONLINE
ITEMP    : 34.6 C Internal
ALARMDEL : Low Battery
LASTXFER : Unacceptable Utility Voltage Change
SELFTEST : NO
STESTI   : 336
DLOWBATT : 05 Minutes
DIPSW    : 0x00 Dip Switch
REG1     : N/A
REG2     : N/A
REG3     : 0x00 Register 3
MANDATE  : 03/30/95
SERIALNO : 13035861
BATTDATE : 05/05/98
NOMOUTV  : 115.0
NOMBATTV :  24.0
HUMIDITY : N/A
AMBTEMP  : N/A
EXTBATTS : N/A
BADBATTS : N/A
FIRMWARE : N/A
APCMODEL : 6TD
END APC  : Fri Dec 03 16:49:25 EST 1999

For a simple signaling or dumb UPS such as BackUPS, your output will be very minimal as follows:

APC      : 001,012,0319
DATE     : Mon Feb 18 09:11:50 CST 2002
RELEASE  : 3.8.5
UPSNAME  : UPS_IDEN
CABLE    : APC Cable 940-0128A
MODEL    : BackUPS
UPSMODE  : Stand Alone
STARTTIME: Mon Feb 18 09:11:45 CST 2002
LINEFAIL : OK
BATTSTAT : OK
STATFLAG : 0x008 Status Flag
END APC  : Mon Feb 18 09:15:01 CST 2002

If you see the above output, it is a good sign that apcupsd is working. Assuming that the output looks reasonable, check the following variables:

LINEV
This is the line voltage and it should be a value that is appropriate for your equipment. In the USA, it is typically about 120 Volts while in Europe, it is about 220 Volts.
BATTV
Unless you have additional battery packs, this should be near 24 Volts plus or minus 5 Volts.
STATUS
This is the status of the UPS and it should normally be ONLINE.

A very disturbing tendance is for some of the newer (Mar 2004) RS and ES UPSes to have no Voltage information. This is an annoying bug, but not serious. On the other hand, some of those UPSes now have no battery charge information BCHARGE. If BCHARGE is zero in your listing and you are running a Smart or a USB UPS, then you will have to set the BATTERYLEVEL directive in your apcupsd.conf file to -1.

If you see a message to the effect of:

APCACCESS FATAL ERROR in apcaccess.c at line 336
tcp_open: cannot connect to server localhost on port 3551.

It means that you have probably not enabled the Network Information Server in your configuration file for apcaccess to work. This is done by setting NETSERVER and NISPORT in your apcupsd.conf file as shown above.

Communications Test

At this point, you should ensure that apcupsd is handling the connection to the UPS correctly. This test assumes you have a UPS that speaks apcsmart protocol, over either USB or a serial port. If you have an old-style voltage-signaling UPS, please skip to the next section (Simulated Power Fail Test).

When apcupsd detects a problem, it generates an EVENT, which consists of sending a message to the system log then invoking the apccontrol script (normally in /etc/acpupsd/apccontrol) to handle the event.

In order to create an event, remove the serial port plug from the back of your computer or from the back of the UPS. Within 6 seconds, apcupsd should detect the lack of serial port communications and broadcast a wall message indicating that the serial port communications was lost:

Warning communications lost with UPS lost.

At the same time, it sends the same message to the system log and to the temporary EVENTS file (/etc/apcupsd/apcupsd.events).

Plug the serial port plug back into your computer, and within about 12 seconds, apcupsd should reestablish communications and broadcast and log the following message:

Communications with UPS restored.

If these messages are logged but not broadcast, either you have your mesg permission set to no (see 'man wall' or 'man mesg'), or there is a problem with apccontrol. If you are running a window manager such as GNOME and don't have a console window open, you may not receive the wall messages. However, you should find them in your system log file (normally /var/log/messages) and in the temporary EVENTS file, /etc/apcupsd/apcupsd.events. For example, to observe these events in the temporary EVENTS file, you might do a

tail -f /etc/apcupsd/apcupsd.events

Note, if you have installed from the RPM, the proper events file may be /var/log/apcupsd.events. You can find the actual filename by checking your apcupsd.conf file before running the test.

If you do not observe these messages, you should correct this problem before proceeding with additional tests.

Simulated Power Fail Test

At this point, you should verify that in the event of a power fail apcupsd properly calls apccontrol. This test is appropriate for all models of UPSes (smart or dumb).

To avoid the possibility that apcupsd might shut down your system, locate where apccontrol resides on your system (normally, /etc/apcupsd/apccontrol. Move this script to another location e.g. apccontrol.save and replace it with the script found in examples/safe.apccontrol. When that is done, ensure that your UPS battery is fully charged and that you have at least 5 minutes of remaining runtime on the batteries. This can be done by examining the values of the BATTCHG and TIMELEFT variables in the printout of 'apcaccess status'.

Athough this should not be necessary, as an extra precaution, you can shutdown your machine, remove the plug from the UPS you are testing, and plug your machine into another UPS or directly into the wall. Doing so, will ensure that the UPS doesn't cut the power to your machine at a bad time. Remember at the end of the testing to plug your machine back into the UPS.

You can also minimize the risk from an unexpected shutdown by using a journaling filesystem such as Linux's EXT3. All modern disk drives park themselves safely when they power down, rather than ploughing up oxide on your disk's recording surface. Thus, unexpected power less has to hit very narrow timing windows in order to trash an EXT3 transaction.

To begin the test, pull the power plug from the UPS. The first time that you do this, psychologically it won't be easy, but after you have pulled the plug a few times, you may even come to enjoy it. If all goes well, apcupsd should detect the power failure and print several warning messages. The first should appear after 5 to 6 seconds and read:

Warning power loss detected.

Then generally 6 seconds later, apcupsd is sure that it isn't a transient effect, so it sends:

Power failure. Running on UPS batteries.

After a few more seconds (total around 15 seconds), plug the power cord back in and ensure that apcupsd is aware that the power has returned. It should print:

Power has returned...

If you do not observe the above messages, please correct the situation before proceeding. The most likely cause of problems are:

  • apcupsd doesn't recognize the power failure because the configuration directives are not correct. E.g. wrong cable.
  • The file /etc/apcupsd/apccontrol doesn't exist or is not marked as executable.

System Shutdown Test

This is an intermediate test that you can do, for all UPS models before doing the Full Power Down Test. First modify the /etc/apcupsd/apccontrol file so that in the killpower case, the line that re-executes apcupsd with the --killpower option is commented out. The original line probably looks something like:

${APCUPSD} --killpower

when it is commented out, it looks like:

#${APCUPSD} --killpower

Now when you pull the power plug, and either the timer expires or the batteries are exhausted (see the next section for more details), the system should be fully shutdown.

After performing this test, please be sure to restore /etc/apcupsd/apccontrol to its previous state.

Full Power Down Test

To complete the testing, you should do a power fail shutdown of your system. This test is applicable to all UPS models. Please do a backup of your system or take other precautions before attempting this to avoid the possibility of lost data due to a problem (I have been through this at least 10 times and never once had problems, but we all know that someday something will go wrong).

Before proceeding, please ensure that your halt script or the equivalent has been properly updated by the install process to contain the logic to call apcupsd --killpower or apccontrol killpower when it detects a power failure situation (the presence of a /etc/powerfail file). See the Building and Installing apcupsd section of this manual, or the README files for additional details about the halt modifications necessary.

When you are ready to do the test, either simply pull the plug and wait for the batteries to become exhausted, or set the TIMEOUT configuration directive to something like 60 so that the system will shutdown before the batteries are exhausted. We recommend doing the full shutdown without using TIMEOUT to correctly simulate a real power failure, but the choice is yours (I did it once here, but now use TIMEOUT 30).

If all goes well, your system should be shutdown before the batteries are completely exhausted and the UPS should be powered off by apcupsd. Please be aware that if you do the full power down, you must ensure that your UPS is totally powered off. Otherwise, it may have been given the command to power off, but due to a long grace period it is still waiting. If you were to reboot your computer during the grace period, the UPS could then suddenly turn off the power (this happened to me). To avoid this problem, always wait for your UPS to power itself off, or power if off manually before restarting your computer. On my system, the UPS is configured as at the factory to have a 180 second grace period before shutting off the power. During this type of testing, 180 seconds seems like an eternity, so please take care to either wait or manually power off your UPS. To determine what grace period is programmed into your UPS EEPROM, run 'apcaccess eprom' and look at the "Shutdown grace delay".

If you experienced so problems with the above testing procedures, or if you are porting apcupsd to another system, or you are simply curious, you may want to know exactly what is going on during the shutdown process. If so, please see the Shutdown Sequence section of this manual.

apctest

apctest is a program that allows you to talk directly to your UPS and run certain low-level tests, adjust various settings such as the battery installation date and alarm behavior, and perform a battery runtime calibration. Here we describe how to use it for a SmartUPS utilizing the apcsmart driver and RS232 serial connection. The menus and options for USB, MODBUS, and simple signaling UPSes are different but mostly self-explanatory.

Shutdown apcupsd if it is running. This is important. Only one program can communicate with the UPS at a time and if apcupsd is running, apctest will fail to contact the UPS.

Run apctest by invoking it with no arguments.

It will read your installed apcupsd.conf configuration (so it knows where to find the UPS) and then it will present you with the following output:

2003-07-07 11:19:21 apctest 3.10.6 (07 July 2003) redhat
Checking configuration ...
Attached to driver: apcsmart
sharenet.type = DISABLE
cable.type = CUSTOM_SMART

You are using a SMART cable type, so I'm entering SMART test mode
mode.type = SMART
Setting up serial port ...
Creating serial port lock file ...
Hello, this is the apcupsd Cable Test program.
This part of apctest is for testing Smart UPSes.
Please select the function you want to perform.

1) Query the UPS for all known values
2) Perform a Battery Runtime Calibration
3) Abort Battery Calibration
4) Monitor Battery Calibration progress
5) Program EEPROM
6) Enter TTY mode communicating with UPS
7) Quit

Select function number: 1

Item 1 will probe the UPS for all values known to apcupsd and present them in rather raw format. This output can be useful for providing technical support if you are having problems with your UPS.

Item 2 will perform a Battery Runtime Calibration. This test will only be performed if your battery is 100% charged. Running the test will cause the batteries to be discharged to approximately 30% of capacity. The exact number depends on the UPS model. In any case, apctest will abort the test if it detects that the battery charge is 20% or less.

The advantage of doing this test is that the UPS will be able to recalibrate the remaining runtime counter that it maintains in its firmware. As your batteries age, they tend to hold less of a charge, so the runtime calibration may not be accurate after several years.

We recommend that perform a Battery Calibration about once a year. You should not perform this calibration too often since discharging the batteries tends to shorten their lifespan.

Item 3 can be used to abort a Battery Calibration in progress, if you some how became disconnected.

Item 4 can be used to restart the monitoring of a Battery Calibration if you should some how become disconnected during the test.

Item 5 is used to program the EEPROM. Please see the Configuration Directives Used to Set the UPS EEPROM chapter of this manual for the details.

Item 6 will initiate a direct communication between your terminal and the UPS, at which point you can enter raw UPS commands. Please be aware that you should be careful what commands you enter because you can cause your UPS to suddenly shutdown, or you can modify the EEPROM in a way to disable your UPS. The details of the raw Smart mode UPS commands can be found in the APC Smart Protocol chapter of this manual.

Item 7 will terminate apctest.

Monitoring and Tuning your UPS

After you have verified that your UPS is working correctly, you will probably want to query the state of its health occasionally. The tools apcupsd gives you to do this include one command-line utility (apcaccess) and a GUI you can use through a Web browser. You can also use apctest to tune some parameters of the UPS itself.

apcaccess

apcaccess is a program (normally found in /sbin/apcaccess) that permits you to print out the complete status of your UPS.

apcaccess will use the Network Information Server to obtain the necessary information. You can specify a second optional argument to apcaccess in the form of host:port where the :port is optional. The default is localhost:3551. Please note that in versions prior to 3.10.6, the default NIS port was 7000, so if you are mixing versions, you will need to take a lot of care to ensure that all components are using the same port.

To enable the apcupsd Network Information Server, which is normally the default, you set:

NETSERVER on
NISPORT 3551

in your apcupsd.conf file.

The full form of the apcaccess command is:

apcaccess status localhost:3551

where only apcaccess status should normally be needed. localhost may be replaced by any machine name, fully qualified domain name, or IP address, which means that apcaccess can access any UPS on the network running the Network Information Server.

The status command line option of apcaccess will produce a full printout of all the STATUS variables used by apcupsd. This can be very helpful for checking the condition of your UPS and to know whether or not apcupsd is properly connected to it.

Please note that if you invoke apcaccess within the first 30 seconds of launching apcupsd, you will likely get an error message such as:

APCACCESS FATAL ERROR in apcaccess.c at line 336
tcp_open: cannot connect to server localhost on port 3551.

This is because apcupsd is still in the process of initializing the UPS. The solution is to wait at least 30 seconds after starting apcupsd before launching apcaccess.

For a SmartUPS 1000 apcaccess will emit the following output:

DATE     : Fri Dec 03 12:34:26 CET 1999
HOSTNAME : matou
RELEASE  : 3.7.0-beta-1
CABLE    : Custom Cable Smart
MODEL    : SMART-UPS 1000
UPSMODE  : Stand Alone
UPSNAME  : UPS_IDEN
LINEV    : 232.7 Volts
MAXLINEV : 236.6 Volts
MINLINEV : 231.4 Volts
LINEFREQ : 50.0 Hz
OUTPUTV  : 232.7 Volts
LOADPCT  :  11.4 Percent Load Capacity
BATTV    : 27.7 Volts
BCHARGE  : 100.0 Percent
MBATTCHG : 5 Percent
TIMELEFT : 112.0 Minutes
MINTIMEL : 3 Minutes
SENSE    : Low
DWAKE    : 060 Seconds
DSHUTD   : 180 Seconds
LOTRANS  : 204.0 Volts
HITRANS  : 253.0 Volts
RETPCT   : 050.0 Percent
STATFLAG : 0x08 Status Flag
STATUS   : ONLINE
ITEMP    : 29.2 C Internal
ALARMDEL : Low Battery
LASTXFER : U command or Self Test
SELFTEST : NO
STESTI   : 336
DLOWBATT : 02 Minutes
DIPSW    : 0x00 Dip Switch
REG1     : 0x00 Register 1
REG2     : 0x00 Register 2
REG3     : 0x00 Register 3
MANDATE  : 01/05/99
SERIALNO : GS9902009459
BATTDATE : 01/05/99
NOMOUTV  : 230.0
NOMBATTV :  24.0
HUMIDITY : N/A
AMBTEMP  : N/A
EXTBATTS : 0
BADBATTS : N/A
FIRMWARE : 60.11.I
APCMODEL : IWI
END APC  : Fri Dec 03 12:34:33 CET 1999

For the various smaller, cheaper APC USB UPSes, such as the CS, ES, ..., you will get much of the information that is presented above, but not all of it. For example, you will not get MAXLINEV, MINLINEV, LINEFREQ, ... and in particular, the LOADPCT will be zero when you are running on mains. LOADPCT will display when the UPS is on batteries. You must remember that the non-SmartUPSes are much simpler (and less expensive) and therefore produce less information.

Apcupsd Notification and Events

When a major event is generated within apcupsd, control is passed to the script apccontrol normally found in /etc/apcupsd/apccontrol. The event name, and a number of other important parameters are passed to the script.

The major function of the apccontrol script is to perform a shutdown of the system (as well as the killpower operation). In addition, another major task for this script is to notify you by email when certain events such as powerfail occur.

Since apccontrol is a script, you can customize it to your own needs using any text editor. To do so, you must have a minimal knowledge of Unix shell programming. In addition, another feature is that you can write your own scripts that will be automatically called by apccontrol before any of its own code is executed. Details of the events and how to program them are contained in the Advanced topics section entitled Customizing Event Handling.

apcupsd Network Monitoring (CGI) Programs

There are four CGI programs (multimon.cgi, upsstats.cgi, upsfstats.cgi, and upsimage.cgi). To have them properly installed, you must run the './configure' command with --enable-cgi and you should specify an installation directory with --with-cgi-bin= or load them manually. The default directory for installation of the CGI programs is /etc/apcupsd, which is not really where you want them if you are going to use them. Normally, they should go in the cgi-bin of your Web server.

Once built and loaded, they will give you the status of your UPS or UPSes via a web browser.

Normally only multimon.cgi is directly invoked by the user. However, it is possible to directly invoke upsstats.cgi and upsfstats.cgi. upsimage.cgi should never be directly invoked as it is used by upsstats.cgi to produce the bar charts.

Setting up and Testing the CGI Programs

Before using multimon and the other CGI programs, first ensure that apcupsd is configured to run the Network Information Server. This is done by setting NETSERVER on in /etc/apcupsd/apcupsd.conf. This switch is on by default.

Next you must edit the hosts file /etc/apcupsd/hosts.conf and at the end, add the name of the hosts you want to monitor and a label string for them. For example:

MONITOR matou "Server"
MONITOR polymatou "Backup server"
MONITOR deuter  "Disk server"

matou, polymatou, and deuter are the network names of the three machines currently running apcupsd. Please note that the network names may either be IP addresses or fully qualified domain names. The network name (or IP address) may optionally be followed by :port, where the port is the NIS port address you wish to use. This is useful if you are running multiple copies of apcupsd on the same system or if you are running in a mixed vendor environment where the NIS port assignments differ. An example could be the following:

MONITOR matou "Server"
MONITOR polymatou "Backup server"
MONITOR deuter  "Disk server"
MONITOR polymatou:7001 "APC USB UPS"

where the USB copy of apcupsd has been configured to use port 7001 by modifying apcupsd.conf. Note, the default NIS port is 3551 on most platforms.

To test multimon.cgi, you can execute it as non-root directly from the source cgi build directory. To do so, enter at a shell prompt:

./multimon.cgi

If everything is set up correctly, it will print a bunch of HTML with the values of the machines that you have put in the hosts.conf file. It should look something like the following (note, only a small portion of the output is reproduced here):

Content-type: text/html

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
     "http://www.w3.org/TR/REC-html40/loose.dtd">
<HTML>
<HEAD><TITLE>Multimon: UPS Status Page</TITLE></HEAD>
<BODY BGCOLOR="#FFFFFF">
<TABLE BGCOLOR="#50A0A0" ALIGN=CENTER>
<TR><TD>
<TABLE CELLPADDING=5>
<TR>
<TH COLSPAN=10 BGCOLOR="#60B0B0">
<FONT SIZE="+2">APCUPSD UPS Network Monitor</FONT>
<BR>Sun Jan 16 12:07:27 CET 2000</TH>
</TR>
<TR BGCOLOR="#60B0B0">
<TH COLSPAN=1>System</TH>
<TH COLSPAN=1>Model</TH>
<TH COLSPAN=1>Status</TH>
...

If you do not get similar output, check the permissions of the /etc/apcupsd directory and of those of /etc/apcupsd/hosts.conf to ensure that your web server can access it. At many sites, the Apache server is not running as root, so you must be careful to ensure that that /etc/apcupsd/hosts.conf and /etc/apcupsd/multimon.conf are world readable.

To invoke multimon in your Web browser, enter:

http://your-site/cgi-bin/multimon.cgi

You should get something similar to the screen shot shown below.

If you wish additional control over the colors, type faces, and sizes of the multimon output, you may simply edit the apcupsd.css file to specify the styles you prefer.

Using the CGI Programs on Windows

The CGI programs compiled for Windows are included in the Windows package starting with apcupsd-3.14.7.

The CGI programs included with the Windows package are intended to be run on Windows. If your web server is running on Linux or another operating system, you will need to obtain binary packages for that platform (or build them from source) instead. The windows build of the CGI programs has been tested with the Apache web server for Win32. They should also work with MS Internet Information Server (IIS).

To use the programs, copy the contents of the cgi/ directory from your apcupsd installation directory to the cgi-bin/ directory of your web server. Consult your web server's documentation for how to enable CGI programs to be executed. Sometimes special security settings are required.

Configure the hosts.conf file as described above. The programs expect to find the hosts.conf file and the apcupsd.css file in the directory \apcupsd\etc\apcupsd on the same drive letter as the web server's cgi-bin directory. If you installed apcupsd into C:\apcupsd (the default) and your web server's cgi-bin/ directory is also located on the C: drive, no further changes are necessary. If you installed apcupsd into a different directory or your web server cgi-bin is on another drive, you will need to relocate hosts.conf and apcupsd.css from the apcupsd install location to \apcupsd\etc\apcupsd on the appropriate drive.

multimon.cgi

This program monitors multiple UPSes at the same time. A typical output of multimon.cgi as displayed in your Web browser might look like the following:

./multimon.png

The machines monitored as well as the values and their column headings are all configurable (see /etc/apcupsd/hosts.conf and /etc/apcupsd/multimon.conf)

upsstats.cgi

By clicking on the system name in the multimon.cgi display, you will invoke upsstats.cgi for the specified system, which will produce a bar graph display of three of the monitored values. For example,

./status.png

You can display different bar graphs by selecting different variables from the drop down menus at the top of each of the three bar graphs.

As with multimon, if you have your local host configured in the /etc/apcupsd/hosts.conf file, you can execute it from a Unix shell from the source cgi directory as follows:

./upsstats.cgi

As with multimon, quite a few lines of html should then be displayed.

upsfstatus.cgi

If you would like to see all of the STATUS variables available over the network, click on the Data field of the desired system, and your browser will display something like the following:

APC      : 001,048,1109
DATE     : Thu Dec 02 17:27:21 CET 1999
HOSTNAME : matou.sibbald.com
RELEASE  : 3.7.0-beta-1
CABLE    : Custom Cable Smart
MODEL    : SMART-UPS 1000
UPSMODE  : Stand Alone
UPSNAME  : UPS_IDEN
LINEV    : 223.6 Volts
MAXLINEV : 224.9 Volts
MINLINEV : 222.3 Volts
LINEFREQ : 50.0 Hz
OUTPUTV  : 223.6 Volts
LOADPCT  :   6.2 Percent Load Capacity
BATTV    : 27.9 Volts
BCHARGE  : 100.0 Percent
MBATTCHG : 5 Percent
TIMELEFT : 167.0 Minutes
MINTIMEL : 3 Minutes
SENSE    : High
DWAKE    : 060 Seconds
DSHUTD   : 020 Seconds
LOTRANS  : 196.0 Volts
HITRANS  : 253.0 Volts
RETPCT   : 050.0 Percent
STATFLAG : 0x08 Status Flag
STATUS   : ONLINE
ITEMP    : 35.1 C Internal
ALARMDEL : Low Battery
LASTXFER : U command or Self Test
SELFTEST : NO
STESTI   : 336
DLOWBATT : 02 Minutes
DIPSW    : 0x00 Dip Switch
REG1     : 0x00 Register 1
REG2     : 0x00 Register 2
REG3     : 0x00 Register 3
MANDATE  : 01/11/99
SERIALNO : GS9903001147
BATTDATE : 01/11/99
NOMOUTV  : 230.0
NOMBATTV :  24.0
HUMIDITY : N/A
AMBTEMP  : N/A
EXTBATTS : 0
BADBATTS : N/A
FIRMWARE : 60.11.I
APCMODEL : IWI
END APC  : Thu Dec 02 17:27:25 CET 1999

You should get pretty much the same output mixed in with html if you execute upsfstats.cgi directly from a Unix shell in the cgi subdirectory as explained above for upsstats.cgi and multimon.cgi.

A Tip from Carl Erhorn for Sun Systems:

It is possible to run the CGI code to monitor your UPS using the answerbook HTTP server that runs on Solaris. As long as your server has the Answerbook2 web server installed and running, you can insert the cgi scripts into the cgi directory of the web server, and access the cgi using something like:

http://hostname:8888/cgi/multimon.cgi

CGI Credits

Many thanks go to Russell Kroll rkroll@exploits.org who wrote the CGI programs to work with his UPS Monitoring system named Network UPS Tools (NUT). Thanks also to Jonathan Benson jbenson@technologist.com for initially adapting the upsstatus.cgi program to work with apcupsd.

We have enhanced the bar graph program and hope that our changes can be useful to the original author in his project.

Security Issues:

  • apcupsd runs as root.
  • If you have NETSERVER ON in your apcupsd.conf file (which is the default), be aware that anyone on the network can read the status of your UPS. This may or may not pose a problem. If you don't consider this information privileged, as is the case for many, there is little risk. In addition, if you have a perimeter firewall or NATting router with typical settings only users on your local network access to your UPS information. You may also restrict access using using firewall settings (see below) or TCP Wrappers (see below).

Firewall Settings

If you are running apcupsd as an NIS server, you will need to ensure that the clients can reach it by opening up NISPORT (default: TCP 3551) on any firewall running on the server. You may wish to configure your firewall(s) to only allow connections from your local network or specifically from the masters, slaves, and servers as needed.

TCP Wrappers

If your operating system does not support a host based firewall (a firewall running on the local machine) then you may try to get some of the functionality of such a firewall with TCP Wrappers. As of apcupsd version 3.8.2, TCP Wrappers are implemented if you turn them on when configuring ./configure --with-libwrap. With this code enabled, you may control who may access your apcupsd via TCP connections (the Network Information Server). This control is done by modifying the file: /etc/hosts.allow. This code is implemented but untested. If you use it, please send us some feedback.

Configuring Your EEPROM

If you have a SmartUPS, there are depending on the UPS at least 12 different values stored in the EEPROM that determine how the UPS reacts to various conditions such as high line voltage, low line voltage, power down grace periods, etc.

In general, for the moment, we do not recommend that you change your EEPROM values unless absolutely necessary. There have been several reported cases of problems setting the Low Transfer Voltage. Consequently, if at all possible, do not attempt to change this value.

Using apctest to Configure Your EEPROM

To make the EEPROM changes with apctest you must first stop the apcupsd daemon. After apcupsd is stopped you may invoke apctest (as root).

We recommend that you change the EEPROM as little as is absolutely necessary since it is a somewhat delicate process that has occasionally produced problems (i.e. improper EEPROM values are displayed after the update).

apctest will present a menu of options which are generally self-explanatory. Note that USB connections will show a difference set of options than smart serial connections.

Maintaining Your UPS Batteries

Battery Technology

Sealed Lead Acid (SLA) batteries, otherwise known as Valve Regulated Lead Acid (VRLA) batteries, were originally known as "dry batteries". When first introduced in the 1950s, they used a gel electrolyte. The otherwise free acid was immobilised with a fine silica powder and formed a gel substance.

In the 1970s the technology moved to Absorbed Glass Mat (AGM) where the separators between the lead plates are made of highly porous micro-fine glass fibres which absorb and immobilise the acid and prevent it from spilling. A crack or hole in the casing of a VRLA battery using AGM technology will not result in a measurable electrolyte spill. Spill containment with VRLA batteries is therefore not meaningful or appropriate.

AGM has became the preferred VRLA technology for use in standby or float applications and is used in UPSes in the telecommunications, power, and many other mission critical industries where the power supply must not be interrupted. APC UPSes use VRLA batteries. VRLA batteries are designed to recombine hydrogen and oxygen and emit only extremely small amounts of hydrogen under normal operating conditions. Normal room ventilation is sufficient to remove any hydrogen, so special ventilation is not required.

Battery Life

Most brand name UPS batteries should last 3-5 years. Some APC Back-UPS models may have a shorter battery life expectancy. Refer to the user's manual of your APC Back-UPS to determine the exact battery life expectancy or contact APC Technical Support.

Below are some APC guidelines for ensuring optimum battery life expectancy:

  1. Make sure that you keep your APC UPS in a cool, dry location with plenty of ventilation. Ideally, the temperature where your UPS is kept should not exceed 75 Deg F (24 Deg C). Also, for ventilation purposes, leave roughly one to two inches on each side for proper airflow.
  2. The optimum operating temperature for a lead acid battery is 25 Deg C (77 Deg F). Elevated temperature reduces longevity. As a guideline, every 8 Deg C (15 Deg F) rise in temperature will cut the battery life in half. A battery which would last for 6 years at 25 Deg C (77 Deg F), will only be good for 3 years if operated at 33 Deg C (95 Deg F). Keep in mind that the battery temperature inside your UPS will always be warmer than the ambient temperature of the location where the UPS is installed.
  3. Only perform runtime calibrations on your UPS one or two times a year, if necessary. Some of our customers want to check their systems to verify that their runtime is sufficient. However, consistently performing these calibrations can significantly decrease the life expectancy of your battery.
  4. Do not store batteries for extended periods of time. New batteries can be stored for 6 to 12 months from date of purchase. After this period, the battery should be used or it will lose a great deal of its charge. It is not advisable to store batteries that have already been in use.
  5. Do not exceed 80 percent of a UPS unit's rated capacity due to the reduction in run time. When you increase your load, your runtime decreases. In the event of a utility power failure, a UPS loaded to full capacity will drain and discharge it's battery quickly and will decrease the life expectancy.

The Smart-UPS detects line voltage distortions such as spikes, notches, dips, and swells, as well as distortions caused by operation with inexpensive fuel-powered generators. By default, the UPS reacts to distortions by transferring to on-battery operation to protect the equipment that you are plugging into the UPS. Where power quality is poor, the UPS may frequently transfer to on-battery operation. Battery longevity and service life of the UPS may be conserved by reducing the sensitivity of the UPS, as long as your equipment can operate normally under the conditions detailed below. Any type of voltage disturbance includes; High/Low/No RMS Voltage, Total Harmonic Distortion(THD), Change in Voltage over Time(dv/dt), Frequency (Hz) out of tolerance.

High Sensitivity Mode
In the event of any type of voltage disturbance, the UPS will transfer to battery power and watch the AC line until it can transfer back to line. The transfer time in this mode depends on how far the line voltage deviates from the sinewave reference.
Medium Sensitivity Mode
In the event of a RMS voltage-out-of-tolerance(High/Low/No) and RMS-rate-of-change disturbances(dv/dt) in the line voltage, the UPS will transfer to battery power and watch the AC line until it can transfer back to line. In this mode the transfer times are longer but still within acceptable limits to insure the continuity of a computer's operation.
Low Sensitivity Mode
In the event of a RMS voltage-out-of-tolerance disturbances(High/Low/No) in the line voltage, the UPS will transfer to battery power and watch the AC line until it can transfer back to line. In this mode the transfer times are longer but still within acceptable limits to insure the continuity of a computer's operation.

To change the sensitivity of the UPS, press the small, white "sensitivity" button on the rear of the UPS. Use a pointed object (such as a pen) to do so. The default setting is "high"; press the button once to set the sensitivity to "medium", and press it again to set it to "low"; pressing it a third time will set it back to "high". The sensitivity setting change will take effect immediately. The green LED next to the button is a sensitivity setting indicator - brightly lit is "high" sensitivity, dimly lit is "medium", and off is "low" sensitivity.

Flashing Battery Charge Graph LEDs

The battery charge graph LEDs on the front panel of a Smart-UPS will flash in unison when the UPS is operating online and the runtime remaining (calculated by the Smart-UPS microprocessor) is less than two minutes more than the low battery signal warning time (minimum of two minutes).

This would usually indicate that you need to either decrease the load or install new batteries. If the batteries are new, then you need to perform a runtime calibration (see below).

At a pinch, you could also decrease the low battery warning time. There are four possible settings: 2, 5, 7, or 10 minutes.

Battery Replacement

If you own your UPS for long enough, you will inevitably need to replace the UPS battery or battery cartridge. An APC battery cartridge comprises two batteries physically stuck together with double-sided tape and wired in series.

After the decision to replace the batteries, you will face another decision almost immediately: whether to purchase genuine APC replacement batteries or not. There are pros and cons to purchasing genuine replacement APC batteries.

APC Battery Pros

  • APC batteries are supported by APC
  • APC batteries come with all the necessary hardware
  • APC batteries come as pre-made cartridges
  • APC batteries will physically fit your UPS

APC Battery Cons

  • APC batteries cost up to 4 times the cost of third party batteries

There are also pros and cons to purchasing third party batteries.

Third Party Battery Pros

  • A third party battery may cost up to 1/4 the price of APC batteries
  • A third party battery may have a higher capacity for the same physical size

Third Party Battery Cons

  • You will need to recycle your battery hardware (cables, connectors etc)
  • You will need to create your own battery cartridges (with double-sided tape)
  • You will need to ensure the third party battery is the right physical size
  • You will need to ensure the third party battery is the right capacity
  • Use of a third party battery will void APC's Equipment Protection Policy
  • Use of a third party battery may void UL, CSA, VDE, and other safety certifications (according to APC)

If you do decide to use third party replacement batteries, please do not choose the cheapest available generic SLA batteries. These batteries will, almost without exception, not last as long as brand name batteries and will need replacing within 12-18 months instead of 3-5 years. Even when using brand name replacement batteries, make sure that you choose the UPS version (aka "standby") which may cost slightly more, but which will last significantly longer in typical UPS usage (long periods of standby punctuated with infrequent deep discharges).

The brands of battery found in genuine APC battery cartridges have included: Panasonic and B&B Battery (aka Best & Best Battery and BB Battery). Yuasa (aka Genesis) is also a recommended brand, albeit a bit on the pricey side.

Note: When substituting a third party battery with a higher capacity than the original, make sure that it still physically fits in the UPS casing. If the battery does not fit, do not be tempted to install it "externally". The UPS may not be able to charge it in a timely manner and/or it may damage the UPS charging circuitry without appropriate modifications which are generally beyond an end user's capability.

Battery Installation

Although you can do a hot swap of your batteries while the computer and any other connected equipment is running, it may not be very satisfactory because the UPS will not always detect that the batteries have been swapped and apcupsd will continue to report "Low Battery".

There are several ways to correct this situation:

1. If you have a "smart" UPS model, you can force a self-test to make the UPS notice that the battery has been replaced.

2. If after a self-test, the UPS does not detect that the battery has been replaced, you can use apctest to do a soft battery runtime calibration. For details of doing this, refer to the "Soft" Runtime Calibration section below.

3. If after the soft battery runtime recalibration, the UPS does not detect that the battery has been replaced, you will need to do a manual battery runtime calibration. For details of doing this, refer to the "Manual" Runtime Calibration section below.

"Soft" Runtime Calibration

A runtime calibration causes the UPS to recalculate its available runtime capacity based on its current load.

Caution: a runtime calibration will deeply discharge the UPS batteries, which can leave a UPS temporarily unable to support its equipment if a utility power failure occurs. Frequent calibrations reduce the life of batteries. APC recommends performing a runtime calibration only annually, semiannually, or whenever the load on the UPS is increased.

In order to perform a "soft" runtime calibration it is necessary to wait for the UPS to recharge its batteries to 100% capacity. Once this has been done, you can then initiate a runtime calibration through apctest.

APC Documentation Notes:

1. In order for the calibration to be accurate, the output load has to be more than 40% (some APC documentation recommends at least 30%). Also, it is advisable not to increase or reduce the load when the UPS is calibrating its run time.

2. Under no circumstances should the UPS be turned off during a run time calibration procedure! Once initiated, the calibration must be allowed to run until completion.

3. The run time calibration procedure is not necessary nor advisable for a new UPS. Only old UPSes with batteries that are not subject to discharge for long periods of time should be allowed to perform a run time calibration.

4. Matrix-UPS and Smart-UPS recalculate the runtime-related parameters every time the UPS goes on battery.

When doing a runtime calibration with "older" batteries, APC Technical Support recommend doing a complete discharge and recharge first.

If you have "dumb" UPS (aka simple signalling) like a Back-UPS, then your only option is to do a manual runtime calibration.

"Manual" Runtime Calibration

Most of the information in this section is taken from APC's website. Any non-APC additions have been inserted in square brackets.

For a "smart" or "smart signalling" Back-UPS Pro or Smart-UPS:

Perform a Runtime Calibration. This is a manual procedure and should not be confused with the runtime calibration performed through PowerChute plus [or apctest]. The batteries inside of the Smart-UPS are controlled by a microprocessor within the UPS. Sometimes it is necessary to reset this microprocessor, especially after the installation of new batteries. Stop the PowerChute plus [or apcupsd] software from running and disconnect the serial cable. There must be at least a 30% load attached to the UPS during this procedure, but the process will cause the UPS to shut off and cut power to its outlets. Therefore, attach a non-critical load to the UPS and then force the UPS on battery by disconnecting it from utility power [suggest not disconnecting, but simply turning off utility power thereby preserving earthing]. Allow the unit to run on battery until it turns off completely. Make sure a 30% load is present! Plug the UPS back into the wall outlet [switch utility power back on] and allow it to recharge (it will recharge more quickly turned off and with no load present). Once the unit has recharged, the "runtime remaining" calculation should be more accurate. Remember that if the unit is an older model, then the runtime will not improve significantly.

Background:

An APC Smart-UPS has a microprocessor which calculates runtime primarily based on the load attached to the UPS and on its battery capacity. On the right side of the front display panel there is a vertical graph of five LEDs. Each LED is an indication of battery charge in increments of twenty percent: 20, 40, 60, 80, 100% (bottom to top). For example, if the battery charge is 99%, then only four of the five LEDs are illuminated.

To ensure that an operating system receives a graceful shutdown when using PowerChute plus or a SmartSlot accessory, an alert is generated by the Smart-UPS indicating that the UPS has reached a low battery condition. The alert is audible (rapid beeping), visual (flashing battery LED or LEDs), and readable through the graphical interface of PowerChute plus software (or a native UPS shutdown program within a particular operating system.) In order to calculate this "low battery condition," all Smart-UPS products have a preconfigured low battery signal warning time of two minutes (this is the factory default setting). There are a total of four user-changeable settings: 2, 5, 7, or 10 minutes. If the low battery signal warning time is set for 2 minutes, then the alerts will activate simultaneously two minutes prior to shutdown. Similarly, if the total runtime for a particular UPS is 30 minutes with a low battery signal warning time set at 10 minutes, then the UPS will run on battery for 20 minutes before the low battery alert begins.

Total runtime is primarily based on two factors, battery capacity and UPS load. UPS load and runtime on battery are inversely proportional: as load increases, battery runtime decreases and vice versa. When utility power is lost, the UPS begins discharging the battery in order to support the attached load. Once power returns, the Smart-UPS will automatically begin to recharge its battery.

For a Matrix UPS:

It is unnecessary to subject a battery bank to an excessively long calibration. Remove battery packs or increase the load (space heaters are good dummy loads) to obtain a reasonable time length for the calibration (under an hour if possible).

At the start of a calibration, the Matrix microprocessor saves the Estimated Run Time displayed.

The unit will then go to battery power until the capacity is 25%. After this run time has been completed, the original Estimated Run Time is compared with the actual run time. It will then increase or decrease this value to correspond to the new run time achieved. If, at any time during the discharge, one of the following rules is violated the calibration will be aborted or corrupted:

  1. Battery capacity must be 100% at start of calibration (all packs must indicated as float).
  2. Initial "Estimated Run Time" must not exceed 128 minutes (remove battery packs if necessary).
  3. Load must be above 25%.
  4. Load must not fluctuate more than ± 5%.
  5. The UPS must be allowed to run down to 25% battery capacity. PowerChute [or apcupsd] and Accessories must be removed since they can abort the calibration prematurely.

For a "dumb" or "simple signalling" UPS (eg a Back-UPS):

This could be done if you have changed your equipment load or battery. Stop the PowerChute [or apcupsd] software from running; disconnect the serial cable between the computer and UPS. Next unplug the UPS from the wall [suggest not disconnecting but simply turning off the utility power thereby preserving the earthing] and let it run on battery until it reaches low battery. Once it reaches low battery plug it back into the wall outlet [turn the utility power back on] and let it recharge. Recharge time can take up to 4 hours.

Resetting the UPS Battery Constant

In some cases none of the battery runtime calibration methods result in the UPS reporting a reasonably correct battery runtime. It has been speculated that this is because the battery constant value has drifted so far from normal that the microprocessor in the UPS cannot correct it.

The good news is that if you are located in the USA, all you have to do is contact APC Technical Support and they will send you a serial port dongle which plugs into the serial port of your UPS and reprograms the battery constant value for you to the correct value.

The bad news is that for many users outside the USA, this service does not appear to be available. It is, however, recommended that you first try contacting APC Technical Support to verify the correct battery constant value. The APC representatives in the Support Forum on the APC website are also very helpful in this regard.

If all else fails, the information below is for you.

WARNING: Only the values for the Smart-UPS 700 model SU700 and Smart-UPS 1400 model SU1400, both with international firmware (and therefore international voltage), have been verified. YOU, gentle reader, USE THIS INFORMATION AT YOUR OWN RISK in the full knowledge that you may render your UPS inoperable and perhaps irreparable, and you will have no-one to blame but yourself. Caveat Utilitor!

The battery constant is the hex number in the column labelled "0", presumably for register 0, in the following table:

UPS Model         4  5  6  0    Hex   Firmware
SU250               EE F8 B1
SU400               EE F8 9F    E1
SU600               EA F4 9F    E5
SU900               F3 FC 9F    ED
SU1250              EE FA 9F    F5
SU2000              F1 F9 9F    FD
SU450,700        28 F2 FA 96 07,RM=47  52.11.I
SU450XL,700XL    28 EE F8 9F 700XL=27   51.9.I
SU1000,INET      35 EF F9 A0    0B     60.11.I
SU1000XL         34 EE FC 9A    2B      61.9.I
SU1400           35 EE FC 9A           70.11.I
SU1400RM         28 ED FA 89
SU1400R2IBX135   08 B4 10 A3
SU1400RMXLI3U    45 F6 F4 80            73.x.I
SU1400RMXLI3U    20 F3 FD 81            73.x.I
SU2200I          35 EE FB AF           90.14.I
SU2200XL,3000    35 EE FB AF 3000=17   90.14.I
SU3000RMXLI3Ublk 35 F3 F4 AF    77     93.14.I
SU5000I white    20 F2 FA 91    1F    110.14.I
SU1400XL,XLI,RM  45 F6 E4 80
SU420I           25 95 09 85    16      21.7.I
SU420SI          0E 95 0A 8C
SU620I           29 99 0B 8A    1A
BP420SI          0E 95 0A 8C    06      11.2.I
BP650SI          10 97 0C 91    0A      12.3.I
Power Stack 250  0C 95 0F B2            26.5.I
Power Stack 450  0D 96 10 99    36      26.5.I
SC250RMI1U       0C 95 0F B3    32     735.a.1
SC420I           0E 95 OA 8C    16     725.1.I
SC620I           10 97 OB 99    1A     726.x.I
SC1000I          08 95 10 94    8A     737.x.I
SC1500I          07 95 14 8F    1E     738.x.I
SU1000XL         17 EE F9 D5
MATRIX 3000,5000    E9 F5 B0
SU700RMI2U       07 B1 0D 92    8A     152.4.I
SU1000RMI2U      08 B5 0D C7    8E     157.3.I
SU1400RMI2U      08 B4 10 A3    92     162.3.I
SUA1000I         07 B5 13 BC    0A    652.12.I
SUA1000XLI       0B BD 0F 7F    4A    681.13.I
SUA750XLI        0A B9 0C 86    46     630.3.I
SUA750I          04 B6 14 82    06    651.12.I
SUA750RMI2U      07 B1 0D 82    86    619.12.I
SUA1500I         09 B9 13 A1    0E 601/653.x.I
SUA1500RMI2U     08 B4 10 A1    8E     617.3.I
SUA2200I         08 B8 12 B3    26    654.12.I
SUA2200RMI2U     09 BC 11 81    A6     665.4.I
SUA2200XLI       0A B7 0F 7F    66     690.x.I
SUA3000RMI2U     04 B9 0E 70    AA     666.4.I
SUA3000RMXLI3U   0A B6 0E 89    xx     xxx.x.x
SUOL1000I        06 B6 1B A6
SUOL2000XL       0D BD 14 75    52     416.5.I
SURT1000XLI      0A BB 19 A8    4E     411.x.I
SURT3000XLI      06 B6 0F CC    56     450.2.I
SURT5000XLI      05 BA 15 86    5A    451.13.W
SURT7500XLI      03 BB 20 97    63
SURT10000XLI     06 B8 19 AB          476.12.W
SUM1500RMXLI2U   03 B7 0D A5    62     716.3.I
SUM3000RMXLI2U   03 B7 0D A5    6A     715.3.I
BP500AVR                        26      17.1.I

The instructions for resetting the battery constant are as follows:

  1. Shutdown the apcupsd daemon;
  2. Run apctest;
  3. Choose option 6 to enter terminal mode;
  4. Enter Y (UPS should respond SM);
  5. Enter 1 (one, not el; wait 4 seconds);
  6. Enter 1 (one, not el; UPS should respond PROG);
  7. Enter 0 (zero, not oh; UPS should respond with current constant);
  8. Write down the existing value so that if something goes wrong, you can at least put it back to that value;
  9. Enter + (plus) or - (minus) to increment/decrement the value;
  10. Enter R to reprogram constant value (UPS should respond Bye);
  11. Enter Y (UPS should respond SM);
  12. Enter 0 (zero, not oh; UPS should respond with the new constant);
  13. Enter Esc to exit terminal mode;
  14. Choose option 7 to exit apctest.

Frequently-Asked Questions

See the bugs section of this document for a list of known bugs and solutions.

Question:

Why all the craziness with custom serial cables?

Answer:

It was nothing more nor less than a form of customer control. For a long time APC wanted to keep other people from talking to its UPSes so it could lock out potential competition for its PowerChute software. Scrambling the leads on its serial cables was a cheap way to accomplish this -- in fact, they tended to be wired so that if you tried a straight-through cable, opening a serial link to the UPS would be interpreted as a shutdown command!

(Hardware companies often think like this -- they lock up interfaces by instinct, cornering a small market rather than growing a bigger one. It's fundamentally stupid and self-defeating, but it's the kind of stupid that tends to sound good at an executive meeting.)

Question:

What UPS brands does apcupsd support?

Answer:

Currently apcupsd supports only APC UPSes. However, some companies such as Hewlett Packard put their own brand name on APC manufactured UPSes. Thus even if you do not have an APC branded UPS, it may work with apcupsd. You will need to know the corresponding APC model number. apcupsd supports all the popular APC models. See the installation and configurations sections of this document for more details.

Question:

Does apcupsd support Windows?

Answer:

Yes.

Question:

I don't have a cable, which one should I build?

Answer:

First you must know if you have an apcsmart UPS or a voltage-signalling UPS. If you have a apcsmart UPS, we recommend building a Custom Smart cable. (see Smart-Custom Cable for SmartUPSes) If you have a voltage-signaling UPS, we recommend that you build a Custom Simple cable. (see Simple-Custom Voltage-Signalling Cable for "dumb" UPSes)

Question:

How much CPU resources does apcupsd use?

Answer:

Depending on your CPU speed, you may see more or less of the CPU consumed by apcupsd. On a 400MHz Unix system, the CPU usage should fall well below 0.1%. On slower systems, the percentage will increase proportionally to the decrease in the CPU speed. On a 400Mhz Win98 machine, the CPU usage will be on the order of 0.5-1.0%. This is higher than for Unix systems. However, compared to the 30% CPU usage by APC's PowerChute (the version on the CDROM shipped with my UPS), apcupsd's 0.5-1.0% is very modest.

Question:

What language is apcupsd written in?

Answer:

It is written in C and C++.

Question:

To test apcupsd, I unplugged the UPS to simulate a power outage. After the machine went into the shutdown process I plugged the UPS back into the commercial power source. This caused the shutdown process to hang after the daemon tried to shut-off the ups. Have you run into this problem, and if so do you have a remedy?

Answer:

Normally, once the shutdown process has begun, we cannot stop it -- how do you stop a shutdown that has killed off half of the daemons running on your system? Most likely you will be left with an unusable system. In addition, when apcupsd is re-executed in the halt script after the disks are synced, it tries to shut off the UPS power, but the UPS will generally refuse to do so if the AC power is on. Since we cannot be 100% sure whether or not the UPS will shut off the power, we don't attempt to reboot the system if we detect that the power is back as it might then get caught by a delayed power off (at least for Smart UPSes).

Question:

After running apcupsd for a while, I get the following error: "Serial communications with UPS lost." What is the problem?

Answer:

We use standard Unix serial port read() and write() calls so once a connection is made, we generally have few problems. However, there have been reports that APC's SNMP Management Card can cause serial port problems. If you have such a card, we suggest that you remove it and see if the problem goes away. It is also possible that some other process such as a getty is reading the serial port.

Question:

I get the following error:

Starting apcupsd power management.
Mar 20 21:19:40 box apcupsd[297]: apcupsd FATAL ERROR in apcserial.c at line 83.
Cannot open UPS tty /dev/cua01: No such file or directory.

What is the problem?

Answer:

The two most likely causes of your problem are: 1. You have the wrong serial port device name in the apcupsd.conf file. 2. The device name is not defined on your system. Suggestions for proceeding:For the first item, check what your serial port device should be named. You might be able to find the name with an:

ls /dev

Normally there will be hundreds or even thousands of names that print. If that doesn't produce anything useful, you can try step 2. Perhaps your device is not defined. To get more information on your devices try 'man MAKEDEV' or 'find / -name MAKEDEV'. It is often located in /dev/MAKEDEV. Looking at the documentation may tell you what the correct name is, or at least allow you to create the device.

Question:

How do I ensure that the slaves shutdown before the master?

Answer:

Slaves make their shutdown decision independently from the master. Therefore you can use the TIMEOUT, MINUTES, and BATTERYLEVEL settings in the slaves' apcupsd.conf to configure them to shut down before the master.

Question:

How do I ensure that my database server is correctly shutdown?

Answer:

You simply add whatever commands are necessary in the appropriate case statements in /etc/apcupsd/apccontrol, which is a standard script file that is called to actually do the shutdown. Alternatively, you can add your own script file that will be called before doing the commands in apccontrol. Your script file must have the same name as the appropriate case statement in apccontrol; it must be executable; and it must be in the same directory as apccontrol.

Customizing Event Handling

When apcupsd detects anomalies from your UPS device, it will make some decisions that usually result in one or more calls to the script located in /etc/apcupsd/apccontrol. The apccontrol file is a shell script that acts on the first argument that apcupsd passes to it. These actions are set up by default to sane behavior for all situations apcupsd is likely to detect from the UPS. However, you can change the apccontrol behavior for every single action.

To customize, so create a file with the same name as the action, which is passed as a command line argument. Put your script in the /etc/apcupsd directory.

These events are sent to the system log, optionally sent to the temporary events file (/etc/apcupsd/apcupsd.events), and they also generate a call to /etc/apcupsd/apccontrol which in turn will call any scripts you have placed in the /etc/apcupsd directory.

Normally, /etc/apcupsd/apccontrol is called only by apcupsd. Consequently, you should not invoke it directly. However, it is important to understand how it functions, and in some cases, you may want to change the messages that it prints using wall. We recommend that you do so by writing your own script to be invoked by apccontrol rather than by modifying apccontrol directly. This makes it easier for you to upgrade to the next version of apcupsd

In other case, you may want to write your own shell scripts that will be invoked by apccontrol. For example, when a power fail occurs, you may want to send an email message to root.

To write your own routine for the powerout action, you create shell script named powerout and put it in the lib directory (normally /etc/apcupsd). When the powerout action is invoked by apcupsd, apccontrol will first give control to your script. If you want apccontrol to continue with the default action, simply exit your script with an exit status of zero. If you do not want apccontrol to continue with the default action, your script should exit with the special exit code of 99. However, in this case, please be aware that you must ensure proper shutdown of your machine if necessary.

Some sample scripts (onbattery and mainsback) that email power failure messages can be found in /etc/apcupsd after an install or in the platforms/etc directory of the source code.

apccontrol Command Line Options

When apcupsd detects an event, it calls the apccontrol script with four arguments as:

apccontrol event ups-name connected powered

where:

event
is the event that occurred and it may be any one of the values described in the next section.
ups-name
is the name of the UPS as specified in the configuration file (not the name in the EEPROM).
connected
is 1 if apcupsd is connected to the UPS via a serial port (or a USB port). In most configurations, this will be the case. In the case of a Slave machine where apcupsd is not directly connected to the UPS, this value will be 0.
powered
is 1 if the computer on which apcupsd is running is powered by the UPS and 0 if not. At the moment, this value is unimplemented and always 0.

The following event names are supported:

annoyme

When a shutdown is scheduled, and the time specified on the ANNOYME directive in the apcupsd.conf file expires, this event is generated.

Default: wall a message

changeme

When apcupsd detects that the mains are on, but the battery is not functioning correctly, this event is generated. It is repeated every x hours.

Default: wall a message

commfailure

This event is generated each time the communications line with the computer is severed. This event is not detected on dumb signaling UPSes.

Default: wall a message

commok

After a commfailure event is issued, when the communications to the computer is re-established, this event will be generated.

Default: wall a message

doreboot

This event is depreciated and should not be used.

Default: Shuts down the system using shutdown -h or similar

doshutdown

When the UPS is running on batteries and one of the limits expires (time, run, load), this event is generated to cause the machine to shutdown.

Default: Shuts down the system using shutdown -h or similar

emergency

Called for an emergency system shutdown. (What triggers such a shutdown is unclear...) After completing this event, apcupsd will immediately initiate a doshutdown event.

Default: wall a message

failing

This event is generated when the UPS is running on batteries and the battery power is exhausted. The event following this one will be a shutdown.

Default: wall a message

loadlimit

This event is generated when the battery charge is below the low limit specified in the apcupsd.conf file. After completing this event, apcupsd will immediately initiate a doshutdown event.

Default: wall a message

powerout

This event is generated immediately when apcupsd detects that the UPS has switched to batteries. It may be due to a short powerfailure, an automatic selftest of the UPS, or a longer powerfailure.

Default: wall a message

onbattery

This event is generated 5 or 6 seconds after an initial powerfailure is detected. It means that apcupsd definitely considers the UPS to be on batteries. The onset of this event can be delayed by the ONBATTERYDELAY apcupsd.conf configuration directive.

Default: wall a message

offbattery

This event is generated when the mains return only if the onbattery event has been generated.

Default: wall a message

mainsback

This event is generated when the mains power returns after a powerout condition. The shutdown event may or may not have been generated depending on the parameters you have defined and the length of the power outage.

Default: nothing

remotedown

This event is generated on a slave machine when it detects either that the master has shutdown, or that a onbattery situation exists and the communications line has been severed.

Default: wall a message

runlimit

This event is generated when the MINUTES value defined in the apcupsd.conf file expires while in a power fail condition. The MINUTES is the remaining runtime as internally calculated by the UPS and monitored by apcupsd. After completing this event, apcupsd will immediately initiate a doshutdown event.

Default: wall a message

timeout

This event is generated when the TIMEOUT value defined in the apcupsd.conf file expires while in a power fail condition. It indicates that the total time in a power failure has been exceeded and the machine should be shutdown. After completing this event, apcupsd will immediately initiate a doshutdown event.

Default: wall a message

startselftest

This event is generated when apcupsd detects a self test by the UPS. Normally due to the 6 second onbattery delay default time, self test events are not detected.

Default: nothing

endselftest

This event is generated when the end of a self test is detected.

Default: nothing

battdetach

This event is generated when apcupsd detects that the UPS battery has been disconnected.

Default: nothing

battattach

This event is generated when apcupsd detects that the UPS battery has been reconnected after a battdetach event.

Default: nothing

Controlling Multiple UPSes on one Machine

The following discussion does not apply to Windows servers. Apcupsd on Windows is limited to a single instance and cannot support monitoring multiple UPSes.

If you have multiple UPSes in use, you may wish to consolidate the monitoring of all of these UPSes onto a single machine, which we shall call the "UPS server". Generally one of the UPSes is powering the "UPS server" itself (and possibly other machines as well). The remaining UPSes are powering additional machines.

Apcupsd can work quite well in this environment by running one instance of apcupsd on the UPS server for each UPS to be controlled. That is, you install a single copy of apcupsd but launch it multiple times using different configuration files and scripts. (Older versions of apcupsd required you to actually compile the daemon multiple times with different configure options. This is no longer required, as all necessary adjustments can be made in apcupsd.conf.)

Additionally, you will run one instance of apcupsd on each of the machines you wish to be shut down. You will configure each of these apcupsd's to use the 'net' driver to read UPS status from the proper instance of apcupsd on the UPS server. See NIS Server/Client Configuration Using the Net Driver for more information on the 'net' driver and setting up net clients.

Multiple UPS Example

There are many ways one could set up multiple apcupsd instances. Here I will present the way I have used with great success on Red Hat Linux.

I have two apcupsd.conf files (this is for a 2 UPS setup, easily expandable to N):

[adk0212@mail apcupsd]$ ls -l /etc/apcupsd/*.conf
-rw-r--r-- 1 root root 11799 Aug  3 08:39 /etc/apcupsd/apcupsd.ups0.conf
-rw-r--r-- 1 root root 11822 Aug 25 14:31 /etc/apcupsd/apcupsd.ups1.conf

In my case, ups0 is the UPS powering the UPS server running the multiple apcupsd instances, so only ups0 should initiate a shutdown of the local machine. The differences between the confs are minor since both UPSes are USB (although that is not a requirement; mixing cable types works fine too):

[adk0212@mail apcupsd]$ diff -u apcupsd.ups0.conf apcupsd.ups1.conf
--- apcupsd.ups0.conf   2007-08-03 08:39:26.000000000 -0400
+++ apcupsd.ups1.conf   2007-08-25 14:31:17.000000000 -0400
-UPSNAME ups0
+UPSNAME ups1
-DEVICE /dev/ups0
+DEVICE /dev/ups1
-SCRIPTDIR /etc/apcupsd
+SCRIPTDIR /etc/apcupsd/null
-PWRFAILDIR /etc/apcupsd
+PWRFAILDIR /etc/apcupsd/null
-NOLOGINDIR /etc
+NOLOGINDIR /etc/apcupsd/null
-ANNOY 300
+ANNOY 0
-NISPORT 3551
+NISPORT 3552
-EVENTSFILE /var/log/apcupsd.events
+EVENTSFILE /var/log/apcupsd.2.events

The important difference to note is that ups1 has its SCRIPTDIR, PWRFAILDIR, and NOLOGINDIR set to a special "null" directory that I have created. This directory contains a copy of the event handling scripts modified to avoid shutting down the local machine. (Details below). Also the UPSes are given different EVENTSFILE and NISPORT settings. Plus I disable the "annoy" feature on ups1. Since the state of that UPS does not impact local users, there's no reason to annoy them.

I have the following files in the special "null" directory:

[adk0212@mail apcupsd]$ ls -l /etc/apcupsd/null
total 32
-rwxr--r-- 1 root root 4176 Aug  3 08:24 apccontrol
-rwxr-xr-x 1 root root  475 Aug  3 08:28 changeme
-rwxr-xr-x 1 root root  502 Aug  3 08:28 commfailure
-rwxr-xr-x 1 root root  503 Aug  3 08:28 commok
-rwxr--r-- 1 root root    8 Aug  3 08:22 doshutdown
-rwxr-xr-x 1 root root  470 Aug  3 08:27 offbattery
-rwxr-xr-x 1 root root  435 Aug  3 08:27 onbattery

The important change here is the addition of a 'doshutdown' script which overrides apccontrol's shutdown action:

[adk0212@mail null]$ cat /etc/apcupsd/null/doshutdown
exit 99

The "exit 99" tells apccontrol to skip its normal processing for that event. apccontrol itself is unchanged; it is a direct copy of the original. The other scripts are also direct copies and have simply been modified to generate status email from NISPORT 3552 instead of 3551.

I also have a custom init.d start/stop script to manage multiple instances. The start, stop, and status handlers are modified to iterate over all /etc/apcupsd/apcupsd.*.conf files. This is derived from the standard apcupsd redhat rc script:

#! /bin/sh
#
# apcupsd      This shell script takes care of starting and stopping
#              the apcupsd UPS monitoring daemon.
#
# chkconfig: 2345 60 99
# description: apcupsd monitors power and takes action if necessary
#

if test -f /etc/whitebox-release ; then
   f=/etc/whitebox-release
else
   f=/etc/redhat-release
fi
if test `cat $f | grep release |\
     cut -f 3 -d ' '`x = "Enterprise"x ; then
   DISTVER="Enterprise "`cat $f | grep release |\
     cut -f 6 -d ' '`
else
   DISTVER=`cat /etc/redhat-release | grep release |\
     cut -f 5 -d ' '`
fi

# Source function library
. /etc/rc.d/init.d/functions

case "$1" in
    start)
       rm -f /etc/apcupsd/powerfail
       rm -f /etc/nologin
       for conf in /etc/apcupsd/apcupsd.*.conf ; do
          inst=`basename $conf`
          echo -n "Starting UPS monitoring ($inst):"
          daemon /sbin/apcupsd -f $conf -P /var/run/apcupsd-$inst.pid
          RETVAL=$?
          echo
          [ $RETVAL -eq 0 ] && touch /var/lock/subsys/apcupsd-$inst
       done
       ;;
    stop)
       for conf in /etc/apcupsd/apcupsd.*.conf ; do
          inst=`basename $conf`
          echo -n "Shutting down UPS monitoring ($inst):"
          killproc -p /var/run/apcupsd-$inst.pid apcupsd
          echo
          rm -f /var/run/apcupsd-$inst.pid
          rm -f /var/lock/subsys/apcupsd-$inst
       done
       ;;
    restart|force-reload)
       $0 stop
       sleep 15
       $0 start
       ;;
    reload)
       echo "$0: reload not implemented"
       exit 3
       ;;
    status)
       for conf in /etc/apcupsd/apcupsd.*.conf ; do
          inst=`basename $conf`
          status -p /var/run/apcupsd-$inst.pid apcupsd-$inst
          RETVAL=$?
          if [ $RETVAL -eq 0 ]
          then
             NISPORT=`grep ^NISPORT < $conf | sed -e "s/NISPORT *\([0-9]\)/\1/"`
             /sbin/apcaccess status localhost:$NISPORT | egrep "(STATUS)|(UPSNAME)"
          fi
       done
       ;;
    *)
       echo "Usage: $0 {start|stop|restart|status}"
       exit 1
       ;;
esac
exit 0

That's about all there is to it. There are still some rough edges to clean up, but overall this is a lot easier with apcupsd 3.14.x than it used to be.

Support for SNMP UPSes

To run apcupsd with a SNMP UPS, you need the following things:

  • An SNMP UPS, for example a Web/SNMP (AP9716) or PowerNet SNMP (AP9605) card installed into the SmartSlot. Apcupsd also has support for some non-APC SNMP UPSes using RFC1628 or MGE MIBs, however the majority of the information in this section is for APC UPSes.

Planning and Setup for SNMP Wiring

SNMP packet requests are relayed to the UPS from monitoring APCUPSD servers over Ethernet via a switch, hub, or router. Protecting these Ethernet devices with UPS supplied power is necessary to ensure reliable SNMP communication during power failures. Servers may fail to shutdown quietly during power failures if SNMP communication is lost.

Planning and Setup for SNMP Configuration

To establish communication to the UPS SNMP card installed in the UPS, the SNMP card will need the following:

  • Assign SNMP card IP Address
  • Set SNMP card General Parameters
  • Set SNMP card Shutdown Parameters
  • Set SNMP card Event Trap Receivers (apcupsd-3.12.0 and later)

Assign SNMP Card IP Address

The following instructions come from the APC knowledge base:

The Network Management Card (AP9617, AP9618, AP9619) must be
configured with network settings before it can communicate on the
network. Once the cards have been configured with an IP address,
Subnet Mask, and Default Gateway the cards can be access, managed,
and controlled from other computers on the network.

There are two ways to configure the Network Management Card (NMC)
with its initial settings: the (windows) Wizard and Address
Resolution Protocol (ARP).

1. The wizard in included on the CD that comes with the card. The
wizard must run on a Windows operating system. You can configure
the card using the wizard over the network via FTP. If using the
wizard please note, the un-configured NMC must be on the same
subnet as the computer running the wizard.

2. Address resolution protocol (arp) can also be used to configure
the NMC. The MAC Address of the NMC is needed for this method of
configuration. The MAC address is located on the quality assurance
slip that is shipped with the NMC, and is also located on the white
sticker on the NMC itself. From a computer on the same subnet as
the un-configured NMC, follow the instructions:

Open up a command prompt and type the following (replacing
<IPaddress> and <MacAddress> with the actual values):

arp -s <IPaddress> <MacAddress>

Next, use Ping with a size of 113 bytes to assign the IP address
defined by the ARP command.


-  Linux command format: ping <IPaddress> -s 113

-  Windows command format: ping <IPaddress> -l 113

Set SNMP card General Parameters

After the SNMP Network Management Card is configured with an IP address, the SNMP Card is ready for general configuration. This is accomplished by telneting to the SNMP Card.

~$ telnet <IPaddress>

Login using "apc" for both the username and password and the following menu will display:

*******************************************************************************
American Power Conversion               Network Management Card AOS      v2.6.4
(c) Copyright 2004 All Rights Reserved  Smart-UPS & Matrix-UPS APP       v2.6.1
-------------------------------------------------------------------------------
Name      :                                       Date : 07/03/2006
Contact   :                                   Time : 04:43:33
Location  :                                   User : Administrator
Up Time   : 0 Days 01 Hours 57 Minutes                Stat : P+ N+ A+

Smart-UPS 1000 named  : On Line, No Alarms Present

------- Control Console -------------------------------------------------------

     1- Device Manager
     2- Network
     3- System
     4- Logout

     <ESC>- Main Menu, <ENTER>- Refresh, <CTRL-L>- Event Log
>
*******************************************************************************

Select Option 2 for Network. Next select Option 1 for TCP/IP settings.

At this point the following settings will be to be specified:

  • Verify System IP: <IPaddress>
  • Specify Subnet Mask: i.e. "225.225.225.0"
  • Specify Default Gateway
  • Specify Host Name
  • Specify Domain Name

Specifying these parameters will complete the General Parameters setup. Additionally the SNMP Network Management Card can now be connected to from a web browser for monitoring and additional configuration.

Set SNMP card Shutdown Parameters

There are two shutdown parameters that must be set in the SNMP card to ensure that connected servers shutdown quietly. These parameters can be set via the telnet terminal or the web browser interface.

  • Shutdown Delay (sec)
  • Return Battery Capacity (%)

One of the draw-backs of SNMP communication to the UPS is that the Stand-alone or Primary server must issue the power down command to the UPS early in server halt procedure. This server must issue an early command to the SNMP UPS to power down before its ethernet service is halted. This creates a potential problem where the UPS may kill power to any connected servers before these affected servers' halt scripts complete a successful shutdown.

The SNMP Shutdown Delay parameter is used to delay the UPS from killing power to its load by a prescribed period of seconds. The delay should be long enough to ensure that the Stand-alone or Primary server has enough time to successfully halt. The prescribed time should at least be 180 seconds. Any additional computers connected to the SNMP UPS must not be configured to issue the command to initiate UPS power down. These servers can be thought of as secondary stand-alone server. The APCUPSD daemons of secondary servers should be configured to initiate server halt a prescribed period of time before the Primary server issues the UPS power down command.

The Return on Battery Capacity is useful during intermittent sequential power failures. This parameter insures that the UPS will not restore power to its loads until it has recharged it battery to a prescribed percentage. This parameter should be set to a value greater than value that the APCUPSD daemons configured "BATTERYLEVEL" shutdown of any connected servers. This will ensure that when the UPS restores power, any additional power failures will successfully re-trigger a server shutdown.

Configure Event Trap Receivers

(Requires apcupsd-3.12.0 and later)

By default, APCUPSD will poll the SNMP UPS card once per minute. In this case, server notification of UPS alarms could potentially be delayed one minute. Event trap catching mitigates this shortcoming. Any UPS alarms are instantly sent to prescribe servers connected SNMP UPS. These servers are referred to as Event Trap Receivers. The SNMP UPS card can be configure to send event traps to a maximum of four receivers that will "catch" these events.

Event trap receivers IP address can be set using a telnet terminal or web browser interface.

Also, be aware that servers configured to be Event Trap Receivers should have static IP set. Severs obtaining IPs from DHCP server will not catch instantaneous Events if the IP address changes from the address set in the SNMP UPS.

Connecting APCUPSD to a SNMP UPS

The previous sections describe configuration of the actual SNMP card. The remaining sections describe configuration of the APCUPSD to communicate using SNMP Protocol.

To enable the SNMP support it is enough to configure the correct device in your apcupsd.conf configuration file. The directive needed for this configuration is:

DEVICE <host>:<port>:<vendor>:<community>

...where the directive is made by four parts. All but the first may be omitted completely or left empty to accept the default.

  • host: IP address or DNS hostname of the UPS (required)

  • port: Remote SNMP port (optional, default: 161)

  • vendor: The type of SNMP MIB available on the UPS (optional, default: autodetect). Allowable choices for vendor are:

    • APC : APC PowerNet MIB, used on most APC brand UPSes
    • RFC : RFC1628 MIB, used by some non-APC UPSes
    • MGE : MGE MIB, used by many MGE brand UPSes
    • blank : Autodetect

    Append "_NOTRAP" to the vendor name to disable SNMP trap catching (ex: "APC_NOTRAP"). See SNMP Trap Catching.

  • community: The read-write community string, usually "private". You can specify a read-only community string, usually "public", if you do not require killpower support. If the community string is omitted, apcupsd will attempt to autotedect by trying "private" and "public". (optional, default: autodetect).

A NIS Server/Client (Master/Slave) configuration with multiple servers is still applicable. However, an alternative configuration is possible with an SNMP enabled UPS. In this arrangement, all connected servers will be configured as a standalone server. Each will independently communicate to the UPS. One (primary) server will be chosen to manage the task of commanding the UPS to power down. All remaining (secondary) servers will be configured to quietly power down before the primary server issues the UPS power down command.

Building with SNMP support

Follow the instructions in Building and Installing apcupsd, being sure to include the following options (in addition to any others you need) on the './configure' line:

./configure --enable-snmp

SNMP Trap Catching

apcupsd-3.11.14 introduces support for SNMP trap catching. Previous versions polled the UPS status once per minute, leading to significant delays before UPS state changes were recognized. With SNMP trap handling, apcupsd monitors the SNMP trap port and will re-poll the UPS whenever a trap is received. This happens, for example, when the UPS switches on or off battery.

In order for this feature to work, you must configure your UPS to deliver traps to the server running apcupsd. This is generally done by connecting to your SNMP card via a web browser or telnet connection. You will need to enter your server's IP address as a trap receiver and make sure trap delivery is enabled.

Trap catching can lead to problems if you are already running another SNMP trap daemon on your server. Only one daemon can listen to the trap port, so whichever one is started first will succeed and the others will fail. Apcupsd will fall back to polling behavior if it is unable to open the trap port. You can also forcibly disable trap catching by appending _NOTRAP to your vendor string in the apcupsd.conf DEVICE directive.

Known Problems

Currently (as of 3.10.0) the code to power off the UPS needs special configuration. The killpower command for SNMP UPSes can not be issued during shutdown as typically at some time during shutdown operations the network stack is stopped. To overcome this problem it is needed to modify the /etc/rc.d/apcupsd system control script to tell apcupsd to issue the power down command (killpower) to the UPS immediately before apcupsd initiates the system shutdown. For this reason it is paramount to set your UPS grace time to a value greater than 120 seconds to allow for clean shutdown operations before the UPS removes the power from its plugs. To enable correct shutdown operation during powerdown do the following:

  • Connect to your Web/SNMP card using your favorite web browser, go to the UPS configuration menu and change the "Shutdown Delay" parameter to 180 seconds or more, depending on how much time your system shutdown requires to umount all the filesystems.
  • Option 1 (non-windows) Edit the server halt script. Relocate the ups_kill_power() function higher in the shutdown sequence, primarily before the command to bring down the ethernet service. This is the preferred method for shutting down the UPS. The UPS will power down after the prescribed "Shut Down Delay" time (in seconds) has elapsed.
  • Option 2 Change /etc/rc.d/apcupsd script adding the --kill-on-powerfail to the apcupsd invocation. This method is not preferred because the UPS is commanded to power down without delay. This creates the potential for UPS powering down before the server calling for UPS power down completes its shutdown. However, in the case of Microsoft Windows OS, this is the only method available for powering down the UPS.
  • Restart your apcupsd

With this setup your UPS operations should be safe.

apcupsd System Logging

The apcupsd philosophy is that all logging should be done through the syslog facility (see: 'man syslog') This is now implemented with the exceptions that STATUS logging, for compatibility with prior versions is still done to a file, and EVENTS logging can be directed to a temporary file so that it can be reported by the network information server.

Logging Types

apcupsd splits its logging into four separate types called:

  1. DEBUG
  2. DATA
  3. STATUS
  4. EVENTS

Debug logging consists of debug messages. Normally these are turned on only by developers, and currently there exist very few of these debug messages.

Data Logging

This feature is somewhat outdated and not often used.

Data logging consists of periodically logging important data concerning the operation of the UPS. For the definitive definition of the format, see log_data() in apcreports.c. The format varies according to the UPS model and the information available from the UPS.

For UPS models, NBKPRO, SMART, SHARESMART, and MATRIX, the output is written in a format very similar to what PowerChute writes. That is:

MinLineVoltage, MaxLineVoltage, OutputVoltage, BatteryVoltage, LineFrequency, LoadPercent, UPSTemperature, AmbientTemperature, Humidity, LineVoltage, BatteryCharge, toggle

Any value that is not supported by your UPS such as AmbientTemperature and Humidity will be blank or possibly as 0.0. In any case the commas before and after that field will still be output. The toggle value alternates from 0 to 1 on each line. This was added at user request so that no two adjacent samples are identical.

An actual example from the log file is:

Nov  2 12:43:05 matou apcupsd[23439]: 224.9,227.5,226.2,27.74,50.00,100.0,30.6,,,226.2,50.0,1

Status Logging

Status logging consists of logging all available information known about your UPS as a series of ASCII records. This information is also made available by the apcupsd network information server.

For more details on STATUS logging, see the apcupsd Status Logging section for details.

EVENTS Logging

Events logging consists of logging events as they happen. For example, successful startup, power fail, battery failure, system shutdown, ...

See the Customizing Event Handling section for more details.

Implementation Details

In order to ensure that the data logged to syslog() can be directed to different files, I have assigned syslog() levels to each of our four types of data as follows:

  1. DEBUG logging has level LOG_DEBUG
  2. DATA logging has level LOG_INFO
  3. STATUS logging has level LOG_NOTICE
  4. EVENTS logging has levels LOG_WARNING, LOG_ERR, LOG_CRIT, and LOG_ALERT

It should be noted that more work needs to be done on the precise definitions of each of the levels for EVENTS logging. Currently, it is roughly broken down as follows:

LOG_WARNING general information such as startup, etc.

LOG_ERR an error condition detected, e.g. communications problem with the UPS.

LOG_CRIT a serious problem has occurred such as power failure, running on UPS batteries, ...

LOG_ALERT a condition that needs immediate attention such as pending system shutdown, ...

The default Facility for syslog() logging is DAEMON, although this can be changed with the FACILITY directive in apcupsd.conf. In the following example, we should the facility as local0.

More work needs to be done to the code to ensure that it corresponds to the above levels.

As a practical example of how to setup your syslog() to use the new logging feature, suppose you wish to direct all DATA logging to a file named /var/log/apcupsd.data, all EVENTS to the standard /var/log/messages file (to be mixed with other system messages), and at the same time send all EVENTS to /var/log/apcupsd.events, and finally, you want to send all STATUS logging to the named pipe /var/log/apcupsd.status

First as root, you create the named pipe:

mkfifo /var/log/apcupsd.status

Change its permissions as necessary or use the -m option to set them when creating the pipe.

Then you modify your /etc/syslog.conf file to direct the appropriate levels of messages where you want them. To accomplish the above, my syslog.conf file looks like:

# exclude all apcupsd info by default
*.info;local0.none                    /var/log/messages

# Everything for apcupsd goes here
local0.info;local0.!notice             /var/log/apcupsd.data
local0.notice;local0.!warn            |/var/log/apcupsd.status
local0.warn                            /var/log/apcupsd.events
local0.warn                            /var/log/messages

The Windows Version of apcupsd

The Windows version of apcupsd has been tested on Win95, Win98, WinMe, WinNT, WinXP, and Win2000 systems. This version of apcupsd has been built to run natively on Windows (no Cygwin or other emulation layer needed). Even though the Win32 version of apcupsd is a port that relies on many Unix features, it is just the same a true Windows program. When running, it is perfectly integrated with Windows and displays its icon in the system icon tray, and provides a system tray menu to obtain additional information on how apcupsd is running (status and events dialog boxes).

Once installed apcupsd normally runs as a system service. This means that it is immediately started by the operating system when the system is booted, and runs in the background even if there is no user logged into the system.

Installing Apcupsd on Windows

Normally, you will install the Windows version of apcupsd from the binaries. Starting with version 3.11.15, the Windows binaries are distributed with a full GUI installer driven by NSIS, the Nullsoft Scriptable Install System (http://nsis.sourceforge.net).

Installation is very simple and straight-forward: Simply double-click the installer executable and follow the instructions.

Configuring Apcupsd on Windows

If you are installing Apcupsd for the first time, the installer will give you an opportunity to edit the apcupsd.conf configuration file to contain the values appropriate for your site. (Subsequent installations will maintain your existing apcupsd.conf, so you need not edit it again unless there are new features or syntax changes that must be accounted for.)

The default configuration calls for a USB connected UPS. This is the most common connection for modern UPSes, especially those used with Windows computers. All other apcupsd drivers are available (apcsmart, dumb, net, snmp, pcnet) and can be used simply by editing the configuration file UPSCABLE, UPSTYPE, and DEVICE settings as described elsewhere in this manual.

Note that on Windows, serial ports are specified using COM1, COM2, etc. notation instead of the UNIX-style /dev/tty* notation.

Note also if you are using WinNT or Win2000, the operating system may probe the serial port attempting to attach a serial mouse. This will cause apcupsd to be unable to communicate with the serial port. If this happens, or out of precaution, you can edit the c:\\boot.ini file. Find the line that looks something like the following:

multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows NT Workstation Version 4.00"

and add the following to the end of the line: /NoSerialMice:COM1 (or COM2 depending on what you want to use). The new line should look similar to...

multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows NT Workstation Version 4.00" /NoSerialMice:COM1

...where the only thing you have changed is to append to the end of the line. This addition will prevent the operating system from interfering with apcupsd

Starting Apcupsd on Windows

The installer will give you an opportunity start the Apcupsd service immediately. If you choose to start it manually, you may do so by selecting the "Start Apcupsd" link from the Start->Programs->Apcupsd folder.

On Windows NT/2000/XP, you may alternatively go to the Control Panel, open the Services folder, select Apcupsd UPS Server, and then click on the Start button as shown below:

./wininstall6.png

If the Services dialog reports a problem, it is normally because your DEVICE statement does not contain the correct serial port name.

You probably should also click on the Startup... button to ensure that the correct defaults are set. The dialogue box that appears should have Startup Type set to Automatic* and **Logon should be set to System Account. If these values are not set correctly by default, please change them otherwise apcupsd will not work.

For WinXP and Win2K systems, the dialogs are a bit different from those shown here for WinNT, but he concept is the same. You get to the Services dialog by clicking on: Control Panel -> Administrative Tools -> Component Services. The apcupsd service should appear in the right hand window when you click on Services (Local) in the left hand menu window.

That should complete the installation process. When the system tray icon turns from a question mark image4 into a plug image5, right click on it and a menu will appear. Select the Events item, and the Events dialogue box should appear. There should be no error messages. By right clicking again on the system tray plug and selecting the Status item, you can verify that all the values for your UPS are correct.

When the UPS switches to the battery, the battery icon image6 will appear in the system tray. While the UPS is online, if the battery is not at least 99% charged, the plug icon will become a plug with a lightning bolt in the middle image7 to indicate that the battery is charging.

Apctray

Starting with version 3.14.2, the tray icon is provided by a separate program called 'apctray'. This cleanly separates the user interface from the daemon (service) and is required for tray icon support on Windows Vista. Note that if you close or disable the tray icon this does not stop or disable the apcupsd service which will continue to monitor the UPS and shutdown the computer when appropriate. To stop or disable the service, use the service control panel.

apctray has the capability of monitoring multiple apcupsd instances using apcupsd's Network Information Server (NIS). It will create a new icon for each instance being monitored. By default, apctray monitors the local apcupsd (localhost on port 3551). To add additional monitors, you can right-click an existing icon and choose "Add Monitor". To remove a monitor, right-click its icon and choose "Remove Monitor". To change thr settings for an existing monitor (ip address, port, refresh rate), right-click its icon and choose "Configure...".

apctray can be installed standalone (without apcupsd) if you wish to use it only to monitor remote apcupsd instances. This can be convenient for keeping an eye on a room full of UPSes from your desktop. Download and run the normal apcupsd installer and simply uncheck all components except apctray. Then add as many monitors as you wish as described above.

Testing Apcupsd on Windows

It would be hard to overemphasize the need to do a full testing of your installation of apcupsd as there are a number of reasons why it may not behave properly in a real power failure situation.

Please read the Testing Apcupsd section of this document for general instructions on testing the Win32 version. However, on Win32 systems, there is no Unix system log file, so if something goes wrong, look in the file c:\apcupsd\etc\apcupsd\apcupsd.events where apcupsd normally logs its events, and you will generally find more detailed information on why the program is not working. The most common cause of problems is either improper configuration of the cable type, or an incorrect address for the serial port. Additionally, check the application event log, if you're running a platform that supports it such as Windows 2000 or XP.

Upgrading

An upgrade may be accomplished by uninstalling the old version (using the Add/Remove Programs Control Panel or clicking the "Uninstall Apcupsd" link from Start -> Programs -> Apcupsd. Near the end of the uninstall you will be prompted about removing configuration and event files. You should answer "No" in order to preserve your existing apcupsd.conf file.

After the uninstall completes you may install the new version of Apcupsd as described above. If you preserved your existing apcupsd.conf file, the new apcupsd.conf will be installed as apcupsd.conf.new.

Post-Installation

After installing apcupsd and before running it, you should check the contents of the config file c:\apcupsd\etc\apcupsd\apcupsd.conf. You will probably need to change your UPSCABLE directive, your UPSTYPE and possibly your DEVICE directives. Please refer to the configuration section of this manual for more details.

Problem Areas

On some Windows systems, the domain resolution does not seem to work if you have not configured a DNS server in the Network section of the Control Panel. This problem should be apparent only when running a slave configuration. In this case, when you specify the name of the master in your apcupsd.conf file, apcupsd will be unable to resolve the name to a valid IP address. To circumvent this problem, simply enter the address as an IP address rather than a hostname, or alternatively, ensure that you have a valid DNS server configured on your system.

On WinNT, WinXP, and Win2K systems, you can examine the System Applications log to which apcupsd writes Windows error messages during startup.

Regardless of which Windows system you are running, apcupsd logs most error messages to c:\apcupsd\etc\apcupsd\apcupsd.events. This type error messages such as configuration file not found, etc are written to this file. Note that on some systems (WinXP, possibly others) Apcupsd is unable to write to this file when running as a service.

Email Notification of Events

It is possible to receive email notification of apcupsd events using some simple Visual Basic scripts contributed by Ed Dondlinger <edondlinger@thepylegroup.com>. The scripts are automatically installed in the etc/apcupsd directory of your apcupsd installation but are disabled by default. To enable them, first open them in a text editor such as Notepad and edit the USER VARIABLES section to set your email preferences including address, server information, etc. Then rename the script files without the *.example suffix. Scripts are supplied for onbattery, offbattery, and commfailure events. You can copy the scripts to other filenames and modify the email body text to respond to other events as described in Customizing Event Handling.

Killpower under Windows

If your batteries become exhausted during a power failure and you want your machine to automatically reboot when the power comes back, it is useful to implement the killpower feature of the UPS where apcupsd sends the UPS the command to shut off the power. In doing so, the power will be cut to your PC and if your BIOS is properly setup, the machine will automatically reboot when the power comes back. This is important for servers.

This feature is implemented on Unix systems by first requesting a system shutdown. As a part of the shutdown, apcupsd is terminated by the system, but the shutdown process executes a script where apcupsd is recalled after the disks are synced and the machine is idle. Apcupsd then requests the UPS to shut off the power (killpower).

Unfortunately on Windows, there is no such shutdown script that we are aware of and no way for apcupsd to get control after the machine is idled. If this feature is important to you, it is possible to do it by telling apcupsd to immediately issue the killpower command after issuing the shutdown request. The danger in doing so is that if the machine is not sufficiently idled when the killpower takes place, the disks will need to be rescanned (and there is a possibility of lost data however small). Generally, UPSes have a shutdown grace period which gives sufficient time for the OS to shutdown before the power is cut.

To implement this feature, you need to add the -p option to the apcupsd command line that is executed by the system. Currently the procedure is manual. You do so by editing the registry and changing the line:

c:\apcupsd\apcupsd.exe /service

found under the key:

HKEY_LOCAL_MACHINE Software\Microsoft\Windows\CurrentVersion\RunServices

to

c:\apcupsd\apcupsd.exe /service -p

If you have a Smart UPS, you can configure the kill power grace period, and you might want to set it to 3 minutes. If you have a dumb UPS, there is no grace period and you should not use this procedure. If you have a Back-UPS CS or ES, these UPSes generally have a fixed grace period of 2 minutes, which is probably sufficient.

Power Down During Shutdown

Our philosophy is to shutdown a computer but not to power it down itself (as opposed to having the UPS cut the power as described above). That is we prefer to idle a computer but leave it running. This has the advantage that in a power fail situation, if the killpower function described above does not work, the computer will continue to draw down the batteries and the UPS will hopefully shutoff before the power is restore thus permitting an automatic reboot.

Nevertheless some people prefer to do a full power down. To do so, you might want to get a copy of PsShutdown, which does have a power down option. You can find it and a lot more useful software at: http://technet.microsoft.com/en-us/sysinternals/bb897541.aspx. To use their shutdown program rather than the apcupsd supplied version, you simply edit:

c:\apcupsd\etc\apcupsd\apccontrol

with any text editor and change our calls to shutdown to psshutdown.

Command Line Options Specific to the Windows Version

These options are not normally seen or used by the user, and are documented here only for information purposes. At the current time, to change the default options, you must either manually run apcupsd or you must manually edit the system registry and modify the appropriate entries.

In order to avoid option clashes between the options necessary for apcupsd to run on Windows and the standard apcupsd options, all Windows specific options are signaled with a forward slash character (/), while as usual, the standard apcupsd options are signaled with a minus (-), or a minus minus (--). All the standard apcupsd options can be used on the Windows version. In addition, the following Windows only options are implemented:

/service Start apcupsd as a service
/run Run the apcupsd application
/install Install apcupsd as a service in the system registry
/remove Uninstall apcupsd from the system registry
/about Show the apcupsd about dialogue box
/kill Stop any running apcupsd
/help Show the apcupsd help dialogue box

It is important to note that under normal circumstances the user should never need to use these options as they are normally handled by the system automatically once apcupsd is installed. However, you may note these options in some of the .pif files that have been created for your use.

Installation: Serial-Line UPSes

Overview of Serial-Interface UPSes

If you have a UPS that communicates via serial port, you need to do two things before you can even think about configuring the software. First, you need to figure out whether it's a dumb (voltage-signalling) UPS or speaks the apcsmart protocol. Second, if you have an interface cable from APC, you need to figure out what kind it is. If you don't have such a cable, you need to build one. A straight-through serial cable won't work.

According to Bill Marr the Belkin F5U109, also sold as F5U409 also works with apcupsd for kernel versions 2.4.25 or higher and kernels 2.6.1 and higher. These newer kernels are needed to have the patch that makes the mct_u232 (Magic Control Technology) module and other adapters work with RS-232 devices that do not assert the CTS signal.

Connecting a Serial-Line UPS to a USB Port

By using a special adaptor, you can connect your serial-line UPS to a USB port. If you would like to free up your serial port and connect your existing serial port UPS to a USB port, it is possible if you have one of the later kernels. You simply get a serial to USB adapter that is supported by the kernel, plug it in and make one minor change to your apcupsd.conf file and away you go. (Kern adds: Thanks to Joe Acosta for pointing this out to me.)

The device that Joe Acosta and Kern are using is IOgear GUC232A USB 2 serial adapter. Bill Marr informs us that it also works with a Back-UPS Pro 650 and the 940-0095B cable.

At Kern's site, running Red Hat 7.1 with kernel 2.4.9-12, he simply changed his /etc/apcupsd/apcupsd.conf configuration line to be:

DEVICE /dev/ttyUSB0

Depending on whether or not you have hotplug working, you may need to explicitly load the kernel modules usbserial and pl2303. In Kern's case, this was not necessary.

Testing Serial-Line UPSes

If you have a serial-line UPS, there are some tests you should run before the general ones described in the Testing Apcupsd section.

To test your computer's connection with a serial-line UPS, you first need to establish that the serial line is functioning, and then that the UPS is responding to commands. This can be a bit tricky, especially with a dumb voltage-signalling interface, because it is completely quiescent when there are no commands being passed, and the command repertoire doesn't include any self-tests.

Because it is easy to configure a serial cable incorrectly in such a way as to cause premature shutdowns of the UPS power, we strongly recommend, especially for voltage- signaling (dumb) UPSes, that you do most of the initial testing with your computer plugged into the wall rather than your UPS. Thus if the UPS power is suddenly shut off, your computer will continue to run. We also recommend using safe-apccontrol as described below, until you are sure that the signaling is correct.

Also note that if you launch the execution of apcupsd while your voltage-signaling UPS is on battery power, it is very likely that your UPS will immediately shut off the power. This is due to the initialization of the serial port line signals, which often looks to the UPS like a shutdown command.

Finally, double-check the state of your cabling and UPS indicator lights frequently during testing. For voltage-signaling UPSes, apcupsd is not currently able to detect whether or not the serial cable is connected. In addition, some simple signaling UPSes with certain cable combinations are not able to detect the low battery condition. For more details please see Voltage Signalling Features Supported by Apcupsd for Various Cables.

Establishing Serial Port Connection

Once you have compiled, installed, and invoked apcupsd, you should wait to allow apcupsd to configure itself and establish contact with the UPS.

If you see a message similar to the following about 30 seconds after starting apcupsd...

apcupsd FATAL ERROR in apcserial.c at line 156
PANIC! Cannot communicate with UPS via serial port.

it means that apcupsd tried for about 30 seconds to establish contact with the UPS via the serial port, but was unable to do so. Before continuing, you must correct this problem. Some of the possible sources of the problem are:

  • You have not configured the correct serial port name on the DEVICE directive in your apcupsd configuration file.
  • The serial port that you have chosen has logins enabled. You must disable logins on that port, otherwise, the system prevents apcupsd from using it. Normally, the file /etc/inittab specifies the ports for which a getty process is started (on Sun machines, the serial port program equivalent to getty is called ttymon). You must disable this for the port that you wish to use.
  • Make sure you are doing your testing as root otherwise, you may have permissions problems accessing the serial port.
  • You may have cabling problems, either with an incorrect cable, or the incorrect cable specification directive in the configuration file.
  • You may have a problem with the /etc/apcupsd/acpupsd.conf file. For example, check that you have specified the correct type of UPS and the correct networking directives. For more details, see the After Installation section.
  • If you have a SmartUPS 5000 RM 15U or similar model, that comes with a "Web/SNMP management card" in one of the "Smart Slots", this card may interfere with the serial port operation. If you are having problems, please remove this card and try again. Supposedly V3.0 of the card firmware has been corrected to properly release the serial port.
  • Ensure that you have no other programs that are using the serial port. One user reported that he had problems because the serial port mouse (gpm) was using the same port as apcupsd. This causes intermittent seemingly random problems.
  • Try connecting your UPS to another machine. If it works, then you probably have a bad serial port card. As unlikely as this may sound, at least two of our users have had to replace bad serial port cards.
  • Try doing an 'lsof /dev/ttyS0' where you replace the /dev/ttyS0 with your serial port name. If you get no output, the port is free (or there is no physical port). If you get output, then another program is using the port, and you should see which one.
  • Try doing a 'dmesg | grep tty'. This may show you if a program has grabbed the port. (Thanks to Joe Acosta for the suggestion.)
  • If all else fails, make sure your system is configured for serial port support.

The first thing to do is to look at your log file, usually /var/log/messages because apcupsd writes more detailed information to the log file whenever there is an error.

If you have a UPS that uses apcsmart protocol, you can manually test the serial communications with the UPS by starting a serial port communications program (such as minicom, tip, or cu) with the settings 2400 8N1 (2400 baud, 8 data bits, no parity, 1 stop bit). Be extremely careful what you send to your UPS as certain characters may cause it to power down or may even cause damage to the UPS. Try sending an upper case Y to the UPS (without a return at the end). It should respond with SM. If this is not the case, review the possible problems listed above. If you fat finger the Y and enter y instead, no cause for alarm, you will simply get the APC copyright notice.

Once you are sure that serial port communications is working, proceed to the next test.

Once you have established serial communications

Once you have established that apcupsd can talk to the UPS over the serial part, go do the series of functional tests described in the main Testing section (see Testing Apcupsd).

Troubleshooting Serial Line communications

The most frequently encountered problem with voltage-signalling UPSes (e.g. BackUPS 650) is that you have incorrectly specified which cable is being used. All cables furnished by APC have the cable number stamped on the side of the computer connector end of the cable. Using this number with apcupsd will normally work fine. If you do not know what cable you have, you can use the apctest program to determine the type of the cable.

For simple signaling UPSes, you should not use simple in the cable specification (i.e. UPSCABLE simple) unless you have made the cable yourself according to the wiring diagram given in the cables chapter of this manual.

Bizarre Intermittent Behavior:

In one case, a user reported that he received random incorrect values from the UPS in the status output. It turned out that gpm, the mouse control program for command windows, was using the serial port without using the standard Unix locking mechanism. As a consequence, both apcupsd and gpm were reading the serial port. Please ensure that if you are running gpm that it is not configured with a serial port mouse on the same serial port.

Cables

You can either use the cable that came with your UPS (the easiest if we support it) or you can make your own cable. We recommend that you obtain a supported cable directly from APC.

If you already have an APC cable, you can determine what kind it is by examining the flat sides of the two connectors where you will find the cable number embossed into the plastic. It is generally on one side of the male connector.

To make your own cable you must first know whether you have a UPS that speaks the apcsmart protocol or a "dumb" UPS that uses serial port line voltage signalling.

If you have an smart UPS, and you build your own cable, build a Smart-Custom cable (see Smart-Custom Cable for SmartUPSes). If you have a voltage-signalling or dumb UPS, build a Simple-Custom cable (see Simple-Custom Voltage-Signalling Cable for "dumb" UPSes). If you have a BackUPS CS with a RJ45 connector, you can build your own Custom-RJ45 cable (see Custom-RJ45 Smart Signalling Cable for BackUPS CS Models).

Smart-Custom Cable for SmartUPSes

You do not have this cable unless you built it yourself. The Smart-Custom cable is not an APC product.

  SMART-CUSTOM CABLE

Signal Computer                  UPS
       DB9F                     DB9M
 RxD    2   --------------------  2  TxD  Send
 TxD    3   --------------------  1  RxD  Receive
 GND    5   --------------------  9  Ground

When using this cable with apcupsd specify the following in apcupsd.conf:

UPSCABLE smart
UPSTYPE apcsmart
DEVICE /dev/ttyS0 (or whatever your serial port is)

If you have an OS that requires DCD or RTS to be set before you can receive input, you might try building the standard APC Smart 940-0024C cable listed below (see 940-0024C Cable Wiring).

Simple-Custom Voltage-Signalling Cable for "dumb" UPSes

You do not have this cable unless you built it yourself. The Simple-Custom cable is not an APC product.

For "dumb" UPSes using voltage signalling, if you are going to build your own cable, we recommend to make the cable designed by the apcupsd team as follows:

       SIMPLE-CUSTOM CABLE

Signal Computer                  UPS
       DB9F   4.7K ohm          DB9M
 DTR    4   --[####]--*              DTR set to +5V by Apcupsd
                      |
 CTS    8   ----------*---------  5  Low Battery
 GND    5   --------------------  4  Ground
 DCD    1   --------------------  2  On Battery
 RTS    7   --------------------  1  Kill UPS Power

List of components one needs to make the Simple cable:

  1. One (1) male DB9 connector, use solder type connector only.
  2. One (1) female DB9/25F connector, use solder type connector only.
  3. One (1) 4.7K ohm 1/4 watt 5% resistor.
  4. rosin core solder.
  5. three (3) to five (5) feet of 22AWG multi-stranded four or more conductor cable.

Assembly instructions:

  1. Solder the resistor into pin 4 of the female DB9 connector.
  2. Next bend the resistor so that it connects to pin 8 of the female DB9 connector.
  3. Pin 8 on the female connector is also wired to pin 5 on the male DB9 connector. Solder both ends.
  4. Solder the other pins, pin 5 on the female DB9 to pin 4 on the male connector; pin 1 on the female connector to pin 2 on the male connector; and pin 7 on the female connector to pin 1 on the male connector.
  5. Double check your work.

We use the DTR (pin 4 on the female connector) as our +5 volts power for the circuit. It is used as the Vcc pull-up voltage for testing the outputs on any "UPS by APC" in voltage-signalling mode. This cable may not work on a BackUPS Pro if the default communications are in apcsmart mode. This cable is also valid for use on a ShareUPS BASIC Port. It is reported to work on SmartUPSes, however the Smart Cable described above is preferred.

To have a better idea of what is going on inside apcupsd, for the SIMPLE cable apcupsd reads three signals and sets three:

Reads:

CD, which apcupsd uses for the On Battery signal when high.

CTS, which apcupsd uses for the Battery Low signal when high.

RxD (SR), which apcupsd uses for the Line Down
signal when high. This signal isn't used for much.
Sets:
DTR, which apcupsd sets when it detects a power failure (generally
5 to 10 seconds after the CD signal goes high). It clears this signal if the CD signal subsequently goes low -- i.e. power is restored.
TxD (ST), which apcupsd clears when it detects that the CD signal
has gone low after having gone high - i.e. power is restored.
RTS, which apcupsd sets for the killpower signal -- to cause the UPS
to shut off the power.

Please note that these actions apply only to the SIMPLE cable. The signals used on the other cables are different.

Finally, here is another way of looking at the CUSTOM-SIMPLE cable:

APCUPSD SIMPLE-CUSTOM CABLE

Computer Side  |  Description of Cable           |     UPS Side
DB9f  |  DB25f |                                 |   DB9m  | DB25m
4     |   20   |  DTR (5vcc)             *below  |    n/c  |
8     |    5   |  CTS (low battery)      *below  | <-  5   |   7
2     |    3   |  RxD (no line voltage)  *below  | <-  3   |   2
5     |    7   |  Ground (Signal)                |     4   |  20
1     |    8   |  CD (on battery from UPS)       | <-  2   |   3
7     |    4   |  RTS (kill UPS power)           | ->  1   |   8
n/c   |    1   |  Frame/Case Gnd (optional)      |     9   |  22

Note: the <- and -> indicate the signal direction.

When using this cable with apcupsd specify the following in apcupsd.conf:

UPSCABLE simple
UPSTYPE dumb
DEVICE /dev/ttyS0 (or whatever your serial port is)

Custom-RJ45 Smart Signalling Cable for BackUPS CS Models

If you have a BackUPS CS, you are probably either using it with the USB cable that is supplied or with the 940-0128A supplied by APC, which permits running the UPS in dumb mode. By building your own cable, you can now run the BackUPS CS models (and perhaps also the ES models) using smart signalling and have all the same information that is available as running it in USB mode.

The jack in the UPS is actually a 10 pin RJ45. However, you can just as easily use a 8 pin RJ45 connector, which is more standard (ethernet TX, and ISDN connector). It is easy to construct the cable by cutting off one end of a standard RJ45-8 ethernet cable and wiring the other end (three wires) into a standard DB9F female serial port connector.

Below, you will find a diagram for the CUSTOM-RJ45 cable:

  CUSTOM-RJ45 CABLE

Signal Computer              UPS     UPS
       DB9F                 RJ45-8  RJ45-10
 RxD    2   ----------------  1      2     TxD  Send
 TxD    3   ----------------  7      8     RxD  Receive
 GND    5   ----------------  6      7     Ground
 FG  Shield ----------------  3      4     Frame Ground

The RJ45-8 pins are: looking at the end of the connector:

 8 7 6 5 4 3 2 1
___________________
| . . . . . . . . |
|                 |
-------------------
       |____|

The RJ45-10  pins are: looking at the end of the connector:

10 9 8 7 6 5 4 3 2 1
_______________________
| . . . . . . . . . . |
|                     |
-----------------------
       |____|

For the serial port DB9F connector, the pin numbers are stamped in the plastic near each pin. In addition, there is a diagram near the end of this chapter.

Note, one user, Martin, has found that if the shield is not connected to the Frame Ground in the above diagram (not in our original schematic), the UPS (a BackUPS CS 500 EI) will be unstable and likely to rapidly switch from power to batteries (i.e. chatter).

When using this cable with apcupsd specify the following in apcupsd.conf:

UPSCABLE smart
UPSTYPE apcsmart
DEVICE /dev/ttyS0 (or whatever your serial port is)

The information for constructing this cable was discovered and transmitted to us by slither_man. Many thanks!

Other APC Cables that apcupsd Supports

apcupsd will also support the following off the shelf cables that are supplied by APC

  • 940-0020[B/C] Simple Signal Only, all models.
  • 940-0023A Simple Signal Only, all models.
  • 940-0119A Simple Signal Only, Back-UPS Office, and BackUPS ES.
  • 940-0024[B/C/G] Smart mode Only, SU and BKPro only.
  • 940-0095[A/B/C] PnP (Plug and Play), all models.
  • 940-1524C Smart mode Only
  • 940-0128A Simple Signal Only, Back-UPS CS in serial mode.
  • All USB cables such as 940-0127[A/B]

Voltage Signalling Features Supported by Apcupsd for Various Cables

The following table shows the features supported by the current version of apcupsd for various cables running the UPS in voltage-signalling mode.

Cable Power Loss Low Battery Kill Power Cable Disconnected
940-0020B Yes No Yes No
940-0020C Yes Yes Yes No
940-0023A Yes No No No
940-0119A Yes Yes Yes No
940-0127A Yes Yes Yes No
940-0128A Yes Yes Yes No
940-0095A/B/C Yes Yes Yes No
simple Yes Yes Yes No

Voltage Signalling

Apparently, all APC voltage-signalling UPSes with DB9 serial ports have the same signals on the output pins of the UPS. The difference at the computer end is due to different cable configurations. Thus, by measuring the connectivity of a cable, one can determine how to program the UPS.

The signals presented or accepted by the UPS on its DB9 connector using the numbering scheme listed above is:

UPS Pin         Signal meaning
 1     <-     Shutdown when set by computer for 1-5 seconds.
 2     ->     On battery power (this signal is normally low but
                   goes high when the UPS switches to batteries).
 3     ->     Mains down (line fail) See Note 1 below.
 5     ->     Low battery. See Note 1 below.
 6     ->     Inverse of mains down signal. See Note 2 below.
 7     <-     Turn on/off power (only on advanced UPSes only)

 Note 1: these two lines are normally open, but close when the
     appropriate signal is triggered. In fact, they are open collector
     outputs which are rated for a maximum of +40VDC and 25 mA. Thus
     the 4.7K ohm resistor used in the Custom Simple cable works
     quite well.

 Note 2: the same as note 1 except that the line is normally closed,
     and opens when the line voltage fails.

The Back-UPS Office 500 signals

The Back-UPS Office UPS has a telephone type jack as output, which looks like the following:

Looking at the end of the connector:

   6 5 4 3 2 1
  _____________
 | . . . . . . |
 |             |
 |  |----------|
 |__|

It appears that the signals work as follows:

  UPS            Signal meaning
1 (brown)    <-   Shutdown when set by computer for 1-5 seconds.
2 (black)    ->   On battery power
3 (blue)     ->   Low battery
4 (red)           Signal ground
5 (yellow)   <-   Begin signalling on other pins
6 (none)          none

Analyses of APC Cables

940-0020B Cable Wiring

Supported Models:Simple Signaling such as BackUPS
Contributed by:Lazar M. Fleysher

Although we do not know what the black box semiconductor contains, we believe that we understand its operation (many thanks to Lazar M. Fleysher for working this out).

This cable can only be used on voltage-signalling UPSes, and provides the On Battery signal as well as kill UPS power. Most recent evidence (Lazar's analysis) indicates that this cable under the right conditions may provide the Low Battery signal. This is yet to be confirmed.

This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.

APC Part# - 940-0020B

Signal Computer                  UPS
       DB9F                     DB9M
 CTS    8   --------------------  2  On Battery
 DTR    4   --------------------  1  Kill power
 GND    5   ---------------*----  4  Ground
                           |
                ---        *----  9  Common
 DCD    1  ----|///|-----------   5  Low Battery
               |\\\|
 RTS    7  ----|///| (probably a
                ---   semi-conductor)

940-0020C Cable Wiring

Supported Models:Simple Signaling such as BackUPS

This cable can only be used on voltage-signalling UPSes, and provides the On Battery signal, the Low Battery signal as well as kill UPS power. You may specify UPSCABLE 940-0020C.

This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.

APC Part# - 940-0020C

Signal Computer                  UPS
       DB9F                     DB9M
 CTS    8   --------------------  2  On Battery
 DTR    4   --------------------  1  Kill power
 GND    5   ---------------*----  4  Ground
                           |
                           *----  9  Common
 RTS    7 -----[ 93.5K ohm ]----- 5  Low Battery
               or semi-conductor

940-0023A Cable Wiring

Supported Models:Simple Signaling such as BackUPS

This cable can only be used on voltage-signalling UPSes, and apparently only provides the On Battery signal. As a consequence, this cable is pretty much useless, and we recommend that you find a better cable because all APC UPSes support more than just On Battery. Please note that we are not sure the following diagram is correct.

This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.

APC Part# - 940-0023A

Signal Computer                  UPS
       DB9F                     DB9M
 DCD    1   --------------------  2  On Battery

              3.3K ohm
 TxD    3   --[####]-*
                     |
 DTR    4   ---------*
 GND    5   ---------------*----  4  Ground
                           |
                           *----  9  Common

940-0024C Cable Wiring

Supported Models:SmartUPS (all models with DB9 serial port)

If you wish to build the standard cable furnished by APC (940-0024C), use the following diagram.

APC Part# - 940-0024C

Signal Computer                  UPS
       DB9F                     DB9M
 RxD    2   --------------------  2  TxD  Send
 TxD    3   --------------------  1  RxD  Receive
 DCD    1   --*
              |
 DTR    4   --*
 GND    5   --------------------  9  Ground
 RTS    7   --*
              |
 CTS    8   --*

940-0095A Cable Wiring

Supported Models:APC BackUPS Pro PNP
Contributed by:Chris Hanson cph at zurich.ai.mit.edu

This is the definitive wiring diagram for the 940-0095A cable submitted by Chris Hanson, who disassembled the original cable, destroying it in the process. He then built one from his diagram and it works perfectly.

APC Part# - 940-0095A

UPS end                                      Computer end
-------                                      ------------
                  47k        47k
BATTERY-LOW (5) >----R1----*----R2----*----< DTR,DSR,CTS (4,6,8)
                         |          |
                         |          |
                         |         /  E
                         |       |/
                         |    B  |
                         *-------|  2N3906 PNP
                                 |
                                 |\
                                   \  C
                                    |
                                    |
                                    *----< DCD (1)     Low Batt
                                    |
                                    |
                                    R 4.7k
                                    3
                                    |
                             4.7k   |
SHUTDOWN (1)    >----------*----R4----*----< TxD (3)
                         |
                         |  1N4148
                         *----K|---------< RTS (7)      Shutdown

POWER-FAIL (2)  >--------------------------< RxD,RI (2,9) On Batt

GROUND (4,9)    >--------------------------< GND (5)

Operation:

  • DTR is "cable power" and must be held at SPACE. DSR or CTS may be used as a loopback input to determine if the cable is plugged in.

  • DCD is the "battery low" signal to the computer. A SPACE on this line means the battery is low. This is signalled by BATTERY-LOW being pulled down (it is probably open circuit normally).

    Normally, the transistor is turned off, and DCD is held at the MARK voltage by TxD. When BATTERY-LOW is pulled down, the voltage divider R2/R1 biases the transistor so that it is turned on, causing DCD to be pulled up to the SPACE voltage.

  • TxD must be held at MARK; this is the default state when no data is being transmitted. This sets the default bias for both DCD and SHUTDOWN. If this line is an open circuit, then when BATTERY-LOW is signalled, SHUTDOWN will be automatically signalled; this would be true if the cable were plugged in to the UPS and not the computer, or if the computer were turned off.

  • RTS is the "shutdown" signal from the computer. A SPACE on this line tells the UPS to shut down.

  • RxD and RI are both the "power-fail" signals to the computer. A MARK on this line means the power has failed.

  • SPACE is a positive voltage, typically +12V. MARK is a negative voltage, typically -12V. Linux appears to translate SPACE to a 1 and MARK to a 0.

940-0095B Cable Wiring

Supported Models:Many simple-signaling (aka voltage signaling) models such as BackUPS

This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.

APC Part# - 940-0095B

Signal Computer                  UPS
       DB9F                     DB9M
 DTR    4   ----*
 CTS    8   ----|
 DSR    6   ----|
 DCD    1   ----*
 GND    5   ---------------*----  4  Ground
                           |
                           *----  9  Common
 RI     9   ----*
                |
 RxD    2   ----*---------------  2  On Battery
 TxD    3   ----------[####]----  1  Kill UPS Power
                      4.7K ohm

940-0119A Cable Wiring

Supported Models:Older BackUPS Office

This diagram is for informational purposes and may not be complete. We don't recommend that use it to build you build one yourself.

APC Part# - 940-0119A

  UPS      Computer
  pins     pins      Signal             Signal meaning
1 (brown)    4,6      DSR DTR     <-   Shutdown when set by computer for 1-5 seconds.
2 (black)    8,9      RI  CTS     ->   On battery power
3 (blue)     1,2      CD  RxD     ->   Low battery
4 (red)       5       Ground
5 (yellow)    7       RTS         <-   Begin signalling on other pins
6 (none)     none

Serial BackUPS ES Wiring

Supported Models:Older Serial BackUPS ES
Contributed by:William Stock

The BackUPS ES has a straight through serial cable with no identification on the plugs. To make it work with apcupsd, specify the { UPSCABLE 940-0119A} and { UPSTYPE backups}. The equivalent of cable 940-0119A is done on a PCB inside the unit.

computer           ----------- BackUPS-ES -----------------
DB9-M              DB-9F
pin    signal      pin

 4      DSR   ->    4 --+
                        |  diode   resistor
 6      DTR   ->    6 --+---->|----/\/\/\---o kill power

 1      DCD   <-    1 --+
                        |
 2      RxD   <-    2 --+----------------+--o low battery
                                         |
 7      RTS   ->    7 --------+--/\/\/\--+
                              |
                              +--/\/\/\--+
                                         |
 8      RI    <-    8 --+----------------+--o on battery
                        |
 9      CTS   <-    9 --+

 5      GND   ---   5 ----------------------o ground

 3      TxD         3 nc

940-0128A Cable Wiring

Supported Models:Older USB BackUPS ES and CS
Contributed by:Many, thanks to all for your help!

Though these UPSes are USB UPSes, APC supplies a serial cable (typically with a green DB9 F connector) that has 940-0128A stamped into one side of the plastic serial port connector. The other end of the cable is a 10 pin RJ45 connector that plugs into the UPS (thanks to Dean Waldow for sending a cable!). Apcupsd version 3.8.5 and later supports this cable when specified as { UPSCABLE 940-0128A} and { UPSTYPE dumb}. However, running in this mode much of the information that would be available in USB mode is lost. In addition, when apcupsd attempts to instruct the UPS to kill the power, it begins cycling about 4 times a second between battery and line. The solution to the problem (thanks to Tom Suzda) is to unplug the UPS and while it is still chattering, press the power button (on the front of the unit) until the unit beeps and the chattering stops. After that the UPS should behave normally and power down 1-2 minutes after requested to do so.

Thanks to all the people who have helped test this and have provided information on the cable wiring, our best guess for the cable schematic is the following:

APC Part# - 940-0128A

computer      --------- Inside the Connector---------  UPS
DB9-F         |                                     |  RJ45
pin - signal  |                                     |  Pin - Color
              |                                     |
 4     DSR  ->|---+                                 |
              |   |  diode   resistor               |
 6     DTR  ->|---+---->|----/\/\/\---o kill power  |  8  Orange
              |                                     |
 1     DCD  <-|----+                                |
              |    |                                |
 2     RxD  <-|----+----------------+--o low battery|  3  Brown
              |                     |               |
 7     RTS  ->|----------+--/\/\/\--+               |
              |          |                          |
              |          +--/\/\/\--+               |
              |                     |               |
 8     RI   <-|----+----------------+--o on battery |  2  Black
              |    |                                |
 9     CTS  <-|----+                                |
              |                         signal      |
 5     GND  --|-----------------------o ground      |  7  Red
              |                                     |
 3     TxD    |                                     |
              |                         chassis     |
 Chassis/GND  |-----------------------o ground      |  4  Black
              |                                     |
              |          Not connected              |  1, 5, 6, 9, 10
              --------------------------------------

The RJ45 pins are: looking at the end of the connector:

10 9 8 7 6 5 4 3 2 1
_______________________
| . . . . . . . . . . |
|                     |
-----------------------
       |____|

940-0128D Cable Wiring

Supported Models:BackUPS XS1000(BX-1000), Possibly other USB models
Contributed by:Jan Babinski jbabinsk at pulsarbeacon dot com

940-0128D is functionally similar to the 940-0128A cable except for NC on (6) DTR and (2) RD on the computer side.

Unverified: Try setting apcupsd to UPSTYPE dumb and UPSCABLE 940-0128A.

APC Part# - 940-0128D

DB9(Computer)               RJ45-10(UPS)

 (5)     (1)                 ____________
( o o o o o )               [ oooooooooo ]
 \ o o o o /                [____________]
  (9)   (6)                 (10)  [_]  (1)


 RI(9)<---+
          |
CTS(8)<---+--- E   2N2222(NPN)
                \|___
           ____ /| B |
          |    C     |
          |          |
          +---vvvv---+--[>|------<(2)OnBatt
RTS(7)>---|    2k      1N5819
          +---vvvv---+--[>|------<(3)LowBatt
          |          |
          +--- C     |
                \|___|
                /| B
DCD(1)<------- E    2N2222(NPN)

DTR(4)>-------------------------->(8)KillPwr

GND(5)----------------------------(7)Signal GND
(Shield)--------------------------(4)Chassis GND

940-0127B Cable Wiring

Supported Models:BackUPS XS1000(BX-1000), Possibly other USB models
Contributed by:Jan Babinski jbabinsk at pulsarbeacon dot com

Standard USB cable for USB-capable models with 10-pin RJ45 connector.

APC Part# - 940-0127B

USB(Computer)      RJ45-10(UPS)
 _________          ____________
| = = = = |        [ oooooooooo ]
|_________|        [____________]
 (1)   (4)         (10)  [_]  (1)

  +5V(1)-----------(1)+5V
DATA+(2)-----------(9)DATA+
DATA-(3)-----------(10)DATA-
  GND(4)-----------(7)Signal GND
(Shield)-----------(4)Chassis GRND

Win32 Implementation Restrictions for Simple UPSes

Due to inadequacies in the Win32 API, it is not possible to set/clear/get all the serial port line signals. apcupsd can detect: CTS, DSR, RNG, and CD. It can set and clear: RTS and DTR.

This imposes a few minor restrictions on the functionality of some of the cables. In particular, LineDown on the Custom Simple cable, and Low Battery on the 0023A cable are not implemented.

Recalibrating the UPS Runtime

Note: In a future release of apcupsd this procedure will be replaced by a daemon operation that can be performed on all types of UPS.

This section does not apply to voltage-signalling or dumb UPSes such as the older BackUPS models.

Smart UPSes internally compute the remaining runtime, and apcupsd uses the value supplied by the UPS. As the batteries age (after say two or three years), the runtime computation may no longer be accurate since the batteries no longer hold the same charge. As a consequence, in the event of a power failure, the UPS and thus apcupsd can report a runtime of 5 minutes remaining when in fact only one minute remains. This can lead to a shutdown before you might expect it, because regardless of the runtime remaining that is reported, the UPS will always correctly detect low batteries and report it, thus causing apcupsd to correctly shutdown your computer.

If you wish to have the UPS recalibrate the remaining runtime calculations, you can do so manually as the current version of apcupsd does not support this feature. To do so,

  • Shutdown apcupsd
  • contact your UPS directly using some terminal program such as minicom, tip, or cu with the settings 2400 8N1 (2400 baud, 8 bits, no parity, 1 stop bit). Be extremely careful what you send to your UPS as certain characters may cause it to power down or may even cause damage to the UPS. Try sending an upper case Y to the UPS (without a return at the end). It should respond with SM. If this is not the case, read the chapter on testing. If you fat finger the Y and enter y instead, no cause for alarm, you will simply get the APC copyright notice.
  • when you are sure you are properly connected send an upper case D (no cr). This will put the UPS into calibration mode, and it will drain the battery down to 25% capacity (35% for a Matrix) at which point it will go back on the mains. In doing so, it will recompute the runtime calibration.
  • If you wish to abort the calibration, enter a second D command.
  • When you are done, restart apcupsd.

In principle, you should be able to do this with the computer powered by the UPS, but if you wish to be completely safe, you should plug your computer into the wall prior to performing the runtime calibration. In that case, you will need to artificially load the UPS with light bulbs or other means. You should supply a load of about 30 to 35% but not more than 50%. You can determine the load by looking at the output of the apcaccess status command while apcupsd is running.

You should not run the recalibration command more than once or twice per year as discharging these kinds of batteries tends to shorten their life span.

Configuration Directive Reference

Configuration directives in /etc/apcupsd/apcupsd.conf control the behavior of the apcupsd daemon. For most installations it is only necessary to set a handful of general directives. The rest can be left at their defaults unless you have an exotic configuration.

Note that the apcupsd daemon must be restarted in order for changes to the configuration file to become active.

General Configuration Directives

In general, each of these directives is required (except that the DEVICE directive is ignored for UPSCABLE ether and not required for UPSCABLE usb).

UPSTYPE driver
The name of a driver. Should be one of dumb, apcsmart, net, usb, pcnet, snmp, or test. This describes your interface type. The UPSTYPE directive can be defined during installation by using the --with-upstype= option of the configure program.
UPSCABLE cable

Defines the type of cable connecting the UPS to your computer.

Possible generic choices for <cable> are:
simple, smart, ether, usb
Or a specific cable model number may be used:
940-0119A, 940-0127A, 940-0128A, 940-0020B, 940-0020C, 940-0023A, 940-0024B, 940-0024C, 940-1524C, 940-0024G, 940-0095A, 940-0095B, 940-0095C, M-04-02-2000

The --with-upscable= option of configure can be used to set a default for this directive during the your build.

DEVICE device

Specify which device is used for UPS communications. For serial ports, it is usually something like /dev/ttyS0. For USB ports, you may leave the name of the device blank (no specification) and apcupsd will automatically search the standard locations for the UPS.

Normally, the configure program will set an appropriate default value. You may also specify the --with-serial-dev= option of the configure program to set this directive at build time.

If you have specified UPSTYPE net, then the device name to be specified consists of hostname:port where the hostname is the fully qualified name or IP address of the host (NIS server) and the port (optional) is the port to use to contact the server.

If you specified UPSTYPE snmp, then the device name becomes hostname:vendor:community. Please see the Support for SNMP UPSes chapter in this manual for more details.

POLLTIME time in seconds
The interval, in seconds, at which apcupsd polls the UPS for status. This rate is automatically set to 1 second if the UPS goes on batteries and reset to your specified value when the mains power returns. This setting applies both to directly-attached UPSes (UPSTYPE apcsmart, usb, dumb) and networked UPSes (UPSTYPE net, snmp). Lowering this setting will improve apcupsd's responsiveness to certain events at the cost of higher CPU utilization. The default of 60 is appropriate for most situations. This directive was formerly known as NETTIME.
LOCKFILE path to lockfile
This option tells apcupsd where to create a lockfile for the USB or serial port in the specified directory. This is important to keep two programs from reading or writing the port at the same time. Please note that although the directive name is LOCKFILE, you are actually specifying the lock file path. apcupsd automatically appends the name of the device when creating the file. On most systems, this directive is automatically set by the ./configure program. You may also explicitly set it during the build process by using the --with-lock-dir= option of the configure program.

Configuration Directives Used by the Network Information Server

None of these directives are required for proper operation of apcupsd.

NETSERVER [on | off]
This configuration directive turns the network information server on or off. If it is on, apcupsd will spawn a child process that serves STATUS and EVENTS information over the network. This information is currently used by the Web-based CGI programs. The default is on. This option is required to be turned on for net clients and apcaccess to function.
NISIP IP-address
This directive specifies the IP address of the network interface on which the NIS server will listen for incoming connections. Default value is 0.0.0.0 which means the NIS will listen for connections on all network interfaces. If your machine has more than one interface, you can specify the IP of a single interface to limit connections to only that interface. Furthermore, you can specify the loopback address (127.0.0.1) to accept connections only from the local machine. You may also use the --with-nisip= option of the configure program to set this directive during the build.
NISPORT port
This configuration directive specifies the port to be used by the apcupsd Network Information Server. The default is platform dependent, but typically 3551, which we have received from IANA as the official apcupsd networking port. This value should only be changed if it conflicts with an existing service in use on your network or if you are running multiple instances of apcupsd on the same machine.
EVENTSFILE filename

If you want the apcupsd network information server to provide the last 10 events via the network, you must specify a file where apcupsd will save these events. The default is: /etc/apcupsd/apcupsd.events. Currently, apcupsd will save at most the last 50 events. Periodically (once an hour by default), apcupsd will check the size of this file. When more than 50 events are recorded, apcupsd will truncate the file to the most recent 10 events. Consequently this file will not grow indefinitely. Although we do not recommend it, you may change these values by editing apcevents.c and changing the appropriate defines. Be aware that if you set these values to very large numbers, apcupsd may make excessive memory demands on the system during the data access and file truncation operations.

This filename may also be specified at build time by using the --with-log-dir= option of the configure program.

Configuration Directives used during Power Failures

In general, none of these directives are required. However, if you have a voltage-signalling (dumb) UPS with a cable that does not support the Low Battery signal, you must set the TIMEOUT directive to force a shutdown.

BATTERYLEVEL percent of battery
If BATTERYLEVEL is specified, during a power failure, apcupsd will halt the system when the remaining battery charge falls below the specified percentage. The default is 5 percent. This directive is ignored for dumb (voltage-signalling) UPSes. To totally disable this counter, set BATTERYLEVEL -1 in your apcupsd.conf file.
MINUTES battery runtime in minutes
If MINUTES is specified, during a power failure, apcupsd will shutdown the system when the remaining runtime on batteries as internally calculated by the UPS falls below the time specified. The default is 3. This directive is ignored for dumb (voltage-signalling) UPSes. It should be noted that some UPSes report an incorrect value for remaining runtime when the battery is fully charged. This can be checked by examining the TIMELEFT value as printed in the output of an 'apcaccess status' command. If the value is zero or otherwise unreasonable, your UPS is probably broken. In this case, we recommend that you disable this timer by setting MINUTES -1 in your apcupsd.conf file.
TIMEOUT time in seconds
After a power failure, apcupsd will halt the system when TIMEOUT seconds have expired. A value of zero disables this timer. Normally for all Smart UPS models and dumb UPSes with cables that support low battery detection, this should be zero so that the shutdown time will be determined by the battery level and/or remaining runtime (see above) or in the case of a voltage-signalling UPS, when the battery is exhausted. This command is required for dumb UPSes that do not provide a battery exhausted signal (only testing can determine this point). For more information, see the Testing Apcupsd section of this manual. This timer can also be useful if you want some slave machines to shutdown before other machines to conserve battery power. It is also useful for testing apcupsd because you can force a rapid shutdown by setting a small value (e.g. 60) and pulling the plug to the UPS.

TIMEOUT, BATTERYLEVEL, and MINUTES can be set together without problems. apcupsd will react to the first case or test that is valid. Normally SmartUPS users will set TIMEOUT to zero so that the system is shutdown depending on the percentage battery charge remaining (BATTERYLEVEL) or the remaining battery runtime (MINUTES).

ANNOY time in seconds

Specify the time in seconds between messages requesting logged in users to get off the system during a power failure. This timer starts only when the UPS is running on batteries. The default is 300 seconds (5 minutes). apcupsd sends the annoy messages by invoking the apccontrol script with the annoyme argument. The default is to send a wall message on Unix systems and a popup message in Windows.

The value of ANNOYDELAY must be greater than the value of ANNOY in order to receive annoy messages (this doesn't make sense, and means that the default values do not generate annoy messages: KES).

Note that if NOLOGON  disable is set, the annoy messages will also be disabled.

ANNOYDELAY time in seconds
Specify delay time in seconds before apcupsd begins requesting logged in users to get off the system during a power failure. This timer starts only after the UPS is running on batteries. This timer is reset when the power returns. The default is 60 seconds. Thus, the first warning to log off the system occurs after 60 seconds on batteries, assuming that NOLOGON is not set to disable.
NOLOGON disable | timeout | percent | minutes | always

Specifies when apcupsd should prevent user logins

The type specified allows you define the point when apcupsd will create the 'nologin' file and thus when user logins are prohibited. Once the 'nologin' file is created, normal users are prevented from logging in. Control of when this file is created is important for allowing systems with big UPSes to run as normally until the system administrator determines the need for preventing user logins. The feature also allows the system administrator to hold the "ANNOY" factor until the 'nologin' file is created. The default is always disable if no NOLOGON directive is specified.

The 'nologin' file will be created in the directory specified by the NOLOGINDIR directive described below.

As far as I can tell, the only useful types are disable and always since the difference in the time when the logout warning is given and shutdown occurs for the other types is very short (KES).

disable prevents apcupsd from creating the nologin file. Consequently, any user can login during a power failure condition. Also, the ANNOY feature is disabled so users will not be warned to logoff the system.

timeout specifies that apcupsd should prohibit logins after the UPS is on batteries for 90% of the time specified on the TIMEOUT configuration directive. Note! Normally you don't want to specify a TIMEOUT value, so this option is probably not too useful (KES).

percent specifies that apcupsd should prohibit logins when the remaining battery charge percentage reaches 110% or less than the value specified on the BATTERYLEVEL configuration directive. Thus if the BATTERYLEVEL is specified as 15, apcupsd will prohibit logins when the battery charge drops below 16% (15% X 110% = 16%).

minutes specifies that apcupsd should prohibit logins when the remaining runtime in minutes reaches 110% or less than the value specified on the MINUTES configuration directive. Thus if MINUTES is set to 3, apcupsd will prohibit logins when the remaining runtime is less than 3 minutes (3 X 110% = 3).

always causes apcupsd to immediately prohibit logins when a power failure occurs. This will also enable the ANNOY feature.

NOLOGINDIR path to nologin dir

This directive configures the directory into which apcupsd will write the nologin file, as described above for the NOLOGON directive.

Normally, the configure program will set an appropriate default value for your platform, often /etc. You may also specify the --with-nologdir= option of the configure program to change the default at compile time.

KILLDELAY time in seconds
If KILLDELAY is set, apcupsd will continue running after a shutdown has been requested, and after the specified time in seconds, apcupsd will attempt to shut off the UPS the power. This directive should normally be disabled by setting the value to zero, but on some systems such as Win32 systems apcupsd cannot regain control after a shutdown to force the UPS to shut off the power. In this case, with proper consideration for the timing, the KILLDELAY directive can be useful. Please be aware, if you cause apcupsd to kill the power to your computer too early, the system and the disks may not have been properly prepared. In addition, apcupsd must continue running after the shutdown is requested, and on Unix systems, this is not normally the case as the system will terminate all processes during the shutdown.
SCRIPTDIR path to apccontrol dir

This option configures the directory in which apccontrol and other event scripts are located.

Normally, the configure program will set an appropriate default value for your platform, often /etc/apcupsd.

PWRFAILDIR path to powerfail dir

When apcupsd shuts down your system, it creates a temporary "flag file" which is used by the operating system halt scripts to know if this shutdown is due to a power failure. This directive configures which directory the flag file will be written into. The chosen directory must be writable by the user apcupsd is running as (normally root) and must not be cleared or unmounted early in the shutdown sequence.

Normally, the configure program will set an appropriate default value for your platform, often /etc/apcupsd. You may also specify the --with-pwrfaildir= option of the configure program to change the default at compile time.

Configuration Directives used to Control System Logging

STATTIME time in seconds
This directive supplies the time interval in seconds between writes to the STATUS file. If set to zero, the STATUS file will not be written. Please note that in a future version of apcupsd the STATUS file code will disappear since its functionality has been replaced by the Network Information Server and by apcaccess status, as a consequence, it is normally disabled by setting it to zero.
STATFILE file
This directive specifies the file to be used when writing the STATUS information. The default is /etc/apcupsd/apcupsd.status.
DATATIME time in seconds
This directives supplies the time interval in seconds between writes of PowerChute-like data information to the log file. See the DATA Logging section of this manual for additional details.
FACILITY log-facility
The FACILITY directive can be used to change the system logging class or facility. The default is DAEMON. This parameter can be useful if you wish to direct the apcupsd system logging information to other than your system default files. See the apcupsd System Logging section of this manual for additional details.

Configuration Directives for Sharing a UPS

The following directives apply to sharing an UPS using a ShareUPS hardware module. Most users will not use this mode.

UPSCLASS standalone | shareslave | sharemaster

The default is standalone and should be used for all machines powered by the UPS and having a serial port or other direct connection to the UPS. This is the normal case.

Use shareslave if and only if you are using a ShareUPS and connected to a BASIC Port with Simple Signal. This code is not fully tested.

Use sharemaster, if and only if you are using a ShareUPS and connected to the ADVANCED Port Smart Signal control. This code is not fully tested.

UPSMODE disable | share

For normal standalone operations, you will set UPSMODE disable to indicate that you are disabling the ShareUPS support.

Use share for two or seven additional simple signal ports on a SmartAccessories(tm) (internal/external box) for SmartUPSes. The share and sharenet code is not fully tested.

Configuration Directives Used to Set the UPS EEPROM

These directives have no effect on the operation of apcupsd but are reserved for use by apctest when bulk programming the values of the UPS EEPROM configuration variables in a Smart-UPS model.

UPSNAME <string>

Name of UPS. Maximum of 8 characters.

BATTDATE [ mm/dd/yy | dd/mm/yy ]

Last battery replacement date. Maximum of 8 characters.

SENSITIVITY [ H | M | L ]

H : High (most sensitive setting) M : Medium L : Low (least sensitive setting)

WAKEUP [ 000 | 060 | 180 | 300 ]

The time delay in seconds that the UPS waits after the return of utility power before "waking up" and restoring power to the connected equipment.

SLEEP [ 020 | 180 | 300 | 600 ]

The time delay in seconds for which the UPS waits or "sleeps" after it receives a request to power off the connected system.

LOTRANSFER <voltage>

Low line voltage causing transfer to battery power or activation of SmartBoost. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are:

D  106  103  100  097
M  177  172  168  182
A  092  090  088  086
I  208  204  200  196

where D = domestic (USA), M = Canada, A = Asia and I = International.

HITRANSFER <voltage>

High line voltage causing transfer to battery power or activation of SmartTrim. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are:

D  127  130  133  136
M  229  234  239  224
A  108  110  112  114
I  253  257  261  265

where D = domestic (USA), M = Canada, A = Asia and I = International.

RETURNCHARGE [ 00 | 15 | 50 | 90 ]

Percentage of battery charge needed for the UPS to restore power to the connected equipment.

BEEPSTATE [ 0 | T | L | N ]

Alarm delay.

0 : Zero delay after power fails.
T : When power fails plus 30 seconds.
L : When low battery occurs.
N : Never.

LOWBATT <minutes>

Low battery warning occurs when the specified number of minutes remains before the UPS estimates battery power will be exhausted. There are four user-changeable settings: 2, 5, 7, or 10 minutes

OUTPUTVOLTS <voltage>

UPS nominal output voltage when running on battery. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are:

D  115
M  208
A  100
I  230  240  220  225

where D = domestic (USA), M = Canada, A = Asia and I = International.

SELFTEST [ 336 | 168 | ON | OFF ]

Self test interval in hours (336 = 2 weeks, 168 = 1 week, ON = at power on, OFF = never).

apcupsd Status Logging

There is a good deal of information available about the UPS and apcupsd's status. This document describes the format of that information. Normally you will get at it via apcaccess, but there are other ways as well.

Status report format

STATUS output is in ASCII format with a single data value or piece of information on each line output. Because not all UPSes supply the same information, the output varies based on the type of UPS that you are using. In general, if the information is not available for your UPS, the line will be missing entirely or the data portion of the output record will contain an N/A indicating that the information is not available.

Status logging consists of periodically logging ALL available information concerning the UPS. Since the volume of data is rather large (over 1000 bytes per status), the STATUS data is not automatically sent to the system log file. Instead, it is written as a series of data records in a specific file (normally /etc/apcupsd/apcupsd.status).

After each write, the file is rewound so that the size of the file remains constant. The STATUS file is kept for backward compatibility and will be eliminated in a future version of apcupsd. The preferred method for obtaining this information is from apcaccess or by using the CGI interface (see apcupsd Network Monitoring (CGI) Programs).

To make reading the status data reliable via a named pipe, the first record written contains a version number, the number of records that follow the first record, and the total number of bytes in those subsequent records. An actual example of such a status file (/etc/apcupsd/apcupsd.status) is shown below.

Consequently, the first record always consists of 24 bytes (23 characters followed by a newline). This record starts with APC and as indicated in the example is followed by 37 records consisting of 906 bytes. The last record begins with END APC and contains the date and time matching the DATE record.

When this data is written to a file, it is written as two records, the first record, and all the other records together. In reading the file, it can be either be read a record at a time, or in one big read.

When this data is written to syslog(), it is written a record at a time. The first record is the first 24 bytes. By having the number of records and the size in the first record, the complete status can be reliably reassembled.

Status Report Example

An example of output from a BackUPS RS 1500 follows:

APC      : 001,037,0906
DATE     : Sun Apr 26 17:22:22 EDT 2009
HOSTNAME : mail.kroptech.com
VERSION  : 3.14.2 (10 September 2007) redhat
UPSNAME  : ups0
CABLE    : USB Cable
MODEL    : Back-UPS RS 1500
UPSMODE  : Stand Alone
STARTTIME: Sun Apr 26 10:22:46 EDT 2009
STATUS   : ONLINE
LINEV    : 123.0 Volts
LOADPCT  :  24.0 Percent Load Capacity
BCHARGE  : 100.0 Percent
TIMELEFT : 144.5 Minutes
MBATTCHG : 5 Percent
MINTIMEL : 3 Minutes
MAXTIME  : 0 Seconds
SENSE    : Medium
LOTRANS  : 097.0 Volts
HITRANS  : 138.0 Volts
ALARMDEL : Always
BATTV    : 26.8 Volts
LASTXFER : Low line voltage
NUMXFERS : 0
TONBATT  : 0 seconds
CUMONBATT: 0 seconds
XOFFBATT : N/A
SELFTEST : NO
STATFLAG : 0x07000008 Status Flag
MANDATE  : 2003-05-08
SERIALNO : JB0319033692
BATTDATE : 2001-09-25
NOMINV   : 120
NOMBATTV :  24.0
FIRMWARE : 8.g6 .D USB FW:g6
APCMODEL : Back-UPS RS 1500
END APC  : Sun Apr 26 17:22:32 EDT 2009

Status Report Fields

The meaning of the above variables are:

APC
Header record indicating the STATUS format revision level, the number of records that follow the APC statement, and the number of bytes that follow the record.
DATE
The date and time that the information was last obtained from the UPS.
HOSTNAME
The name of the machine that collected the UPS data.
UPSNAME
The name of the UPS as stored in the EEPROM or in the UPSNAME directive in the configuration file.
VERSION
The apcupsd release number, build date, and platform.
CABLE
The cable as specified in the configuration file (UPSCABLE).
MODEL
The UPS model as derived from information from the UPS.
UPSMODE
The mode in which apcupsd is operating as specified in the configuration file (UPSMODE)
STARTTIME
The time/date that apcupsd was started.
STATUS
The current status of the UPS (ONLINE, ONBATT, etc.)
LINEV
The current line voltage as returned by the UPS.
LOADPCT
The percentage of load capacity as estimated by the UPS.
BCHARGE
The percentage charge on the batteries.
TIMELEFT
The remaining runtime left on batteries as estimated by the UPS.
MBATTCHG
If the battery charge percentage (BCHARGE) drops below this value, apcupsd will shutdown your system. Value is set in the configuration file (BATTERYLEVEL)
MINTIMEL
apcupsd will shutdown your system if the remaining runtime equals or is below this point. Value is set in the configuration file (MINUTES)
MAXTIME
apcupsd will shutdown your system if the time on batteries exceeds this value. A value of zero disables the feature. Value is set in the configuration file (TIMEOUT)
MAXLINEV
The maximum line voltage since the UPS was started, as reported by the UPS
MINLINEV
The minimum line voltage since the UPS was started, as returned by the UPS
OUTPUTV
The voltage the UPS is supplying to your equipment
SENSE
The sensitivity level of the UPS to line voltage fluctuations.
DWAKE
The amount of time the UPS will wait before restoring power to your equipment after a power off condition when the power is restored.
DSHUTD
The grace delay that the UPS gives after receiving a power down command from apcupsd before it powers off your equipment.
DLOWBATT
The remaining runtime below which the UPS sends the low battery signal. At this point apcupsd will force an immediate emergency shutdown.
LOTRANS
The line voltage below which the UPS will switch to batteries.
HITRANS
The line voltage above which the UPS will switch to batteries.
RETPCT
The percentage charge that the batteries must have after a power off condition before the UPS will restore power to your equipment.
ITEMP
Internal UPS temperature as supplied by the UPS.
ALARMDEL
The delay period for the UPS alarm.
BATTV
Battery voltage as supplied by the UPS.
LINEFREQ
Line frequency in hertz as given by the UPS.
LASTXFER
The reason for the last transfer to batteries.
NUMXFERS
The number of transfers to batteries since apcupsd startup.
XONBATT
Time and date of last transfer to batteries, or N/A.
TONBATT
Time in seconds currently on batteries, or 0.
CUMONBATT
Total (cumulative) time on batteries in seconds since apcupsd startup.
XOFFBATT
Time and date of last transfer from batteries, or N/A.
SELFTEST

The results of the last self test, and may have the following values:

  • OK: self test indicates good battery
  • BT: self test failed due to insufficient battery capacity
  • NG: self test failed due to overload
  • NO: No results (i.e. no self test performed in the last 5 minutes)
STESTI
The interval in hours between automatic self tests.
STATFLAG
Status flag. English version is given by STATUS.
DIPSW
The current dip switch settings on UPSes that have them.
REG1
The value from the UPS fault register 1.
REG2
The value from the UPS fault register 2.
REG3
The value from the UPS fault register 3.
MANDATE
The date the UPS was manufactured.
SERIALNO
The UPS serial number.
BATTDATE
The date that batteries were last replaced.
NOMOUTV
The output voltage that the UPS will attempt to supply when on battery power.
NOMINV
The input voltage that the UPS is configured to expect.
NOMBATTV
The nominal battery voltage.
NOMPOWER
The maximum power in Watts that the UPS is designed to supply.
HUMIDITY
The humidity as measured by the UPS.
AMBTEMP
The ambient temperature as measured by the UPS.
EXTBATTS
The number of external batteries as defined by the user. A correct number here helps the UPS compute the remaining runtime more accurately.
BADBATTS
The number of bad battery packs.
FIRMWARE
The firmware revision number as reported by the UPS.
APCMODEL
The old APC model identification code.
END APC
The time and date that the STATUS record was written.

Logging the STATUS Information

If specified in the configuration file, the STATUS data will also be written to the system log file. Please note, that it would not normally be wise to write this data to a normal system log file as there is no mechanism in syslog() to rewind the file and hence the log file would quickly become enormous. However, in two cases, it can be very useful to use syslog() to write this information.

The first case is to set up your syslog.conf file so that the data is written to a named pipe. In this case, normally not more than about 8192 bytes of data will be kept before it is discarded by the system.

The second case is to setup your syslog.conf file so that the status data is sent to another machine, which presumably then writes it to a named pipe. Consequently, with this mechanism, provides a simple means of networking apcupsd STATUS information.

Although we mention system logging of STATUS information, we strongly recommend that you use apcaccess or the CGI interface to get this information.

The Shutdown Sequence and its Discontents

Shutdown Sequence

If you experienced so problems with the testing procedures, or if you are porting apcupsd to another system, or you are simply curious, you may want to know exactly what is going on during the shutdown process.

The shutdown sequence is as follows:

  • apcupsd detects that there is a power problem and it calls /etc/apcupsd/apccontrol powerout. By default this event does nothing, but it can be overridden to notify users, etc.

  • After the configured ONBATTERYDELAY, apcupsd calls /etc/apcupsd/apccontrol onbattery, which normally sends a message to all users informing them that the UPS is on batteries.

  • When one of the conditions listed below occurs, apcupsd issues a shutdown command by calling /etc/apcupsd/apccontrol doshutdown, which should perform a shutdown of your system using the system shutdown(8) command. You can modify the behavior as described in Customizing Event Handling.

    The conditions that trigger the shutdown can be any of the following:

    • Running time on batteries have expired (TIMEOUT)
    • The battery runtime remaining is below the configured value (BATTERYLEVEL)
    • The estimated remaining runtime is below the configured value (MINUTES)
    • The UPS signals that the batteries are exhausted.

    A shutdown could also be initiated if apcupsd detects that the batteries are no longer functioning correctly. This case, though very unusual, can happen at any time even if there is proper mains voltage, and /etc/apcupsd/apccontrol emergency is called.

    Just before initiating any shutdown through the apccontrol script, apcupsd will create the file /etc/apcupsd/powerfail. This file will be used later in the shutdown sequence to recall apcupsd after syncing of the disks to initiate a power off of the UPS.

    If the /etc/nologin file has not already been created, it will normally be created during the shutdown sequence to prevent additional users from logging in (see the NOLOGIN configuration directive).

    Even though apcupsd has requested the system to perform a shutdown, it continues running.

  • When the system signals apcupsd to do exit, it does so. This is part of the normal system shutdown (at least on Unix and Linux systems) and the exact time that apcupsd receives the termination signal depends on how the shutdown links (usually in /etc/rc.d) are set.

    Note that on Windows NT systems, apcupsd apparently continues to run as a Service even though the machine is "shutdown".

  • During the shutdown of the system after apcupsd has been forced to exit, one of the last things done by the system shutdown is to call the halt script, which is usually in /etc/rc.d/halt or /etc/rc.d/init.d/halt, or possibly in /sbin/init.d/rc.0 depending on your system. If apcupsd was properly installed, this standard halt script was modified to include a bit of new logic just before the final halt of the system. It first tests if the file /etc/apcupsd/powerfail exists, and if it does, it executes /etc/apcupsd/apccontrol killpower. It is this last step that will cause apcupsd to be re-executed with the --killpower option on the command line. This option tells apcupsd to inform the UPS to kill the power.

This final step is important if you want to ensure that your system will automatically reboot when the power comes back on. The actual code used on the Red Hat version is:

# See if this is a powerfail situation.                              # ***apcupsd***
if [ -f /etc/apcupsd/powerfail ]; then                               # ***apcupsd***
  echo                                                               # ***apcupsd***
  echo "APCUPSD will now power off the UPS"                          # ***apcupsd***
  echo                                                               # ***apcupsd***
  /etc/apcupsd/apccontrol killpower                                  # ***apcupsd***
  echo                                                               # ***apcupsd***
  echo "Please ensure that the UPS has powered off before rebooting" # ***apcupsd***
  echo "Otherwise, the UPS may cut the power during the reboot!!!"   # ***apcupsd***
  echo                                                               # ***apcupsd***
fi                                                                   # ***apcupsd***

The above code must be inserted as late as possible in the halt script. On many systems, such as Red Hat, all the disk drives were unmounted, then remounted read-only, thus permitting access to the /etc files and the apcupsd executable. If your system does not explicitly remount the disks, you must remount them in read-only mode in the code that you add. Examples of code fragments that do this can be found in the distributions/suse subdirectory of the source.

If you are not able to insert the above code in your halt script because there is no halt script, or because your halt script calls the init program as some Unix systems do, you can either just forget about powering off the UPS, which means that your machine will not automatically reboot after a power failure, or there is yet another alternative, though not at all as satisfying as inserting code in the halt script.

Only if you cannot insert the appropriate code in the halt script, when you start apcupsd, normally from the /etc/rc.d/init.d/apcupsd script, use the --kill-on-powerfail option. This will cause apcupsd to program the UPS to shutoff the power just before it (apcupsd) does the system shutdown. Please note that this is not the most ideal solution. Read on to understand why.

A very important consideration is that you must set the EEPROM in your UPS so that it waits a sufficient time for the system to halt before it shuts off the UPS power.

When using a USB connection, apcupsd automatically sets this value to 60 seconds. When using a serial connection to a SmartUPS, you must configure the value in the UPS EEPROM by hand using apctest.

Shutdown Problems

Obviously if your halt script is not properly modified, apcupsd will not be able to shut off the power to the UPS, and if the power returns before the batteries are exhausted your system will not automatically reboot. In any case, your machine should have been cleanly shut down.

Master/Slave Shutdown

In master/slave configurations, however, the master cannot be 100 percent sure that the slaves have all shutdown before it performs the power off. To avoid this situation, be sure to configure any slaves (clients) to shut down before the master by setting different TIMEOUT, BATTERYLEVEL, or MINUTES parameters in the config file.

Also, on a slave machine, you do not want to use the modified halt script since it will recall apcupsd, which will detect that it is a slave (i.e. no connection to the UPS) and will complain that it cannot do the killpower. This situation is not harmful just annoying and possibly confusing.

One possible problem during shutdown can be caused by remnants of old versions. Please be sure to delete or rename all prior versions (/usr/local/sbin/apcupsd or /sbin/powersc).

Startup

Normally, apcupsd is automatically started when your system is rebooted. This normally occurs because the startup script apcupsd is linked into the appropriate places in /etc/rc.d. On most Linux systems, there is a program called chkconfig(8) that will automatically link the startup script. This program is invoked by the make install scripts, or it is explicitly done for those systems that do not have chkconfig(8). If this is not the case, you can either link it in appropriately yourself or explicitly call it from your rc.local file. The appropriate manual way to startup apcupsd is by executing:

<path>/apcupsd start

where path is normally /etc/rc.d or /etc/rc.d/init.d depending on your system. Using this script is important so that any files remaining around after a power failure are removed. Likewise, shutting down apcupsd should be done with the same script:

<path>/apcupsd stop

Windows Considerations

Please see the Killpower under Windows chapter of this manual for considerations pertaining to shutdown and killpower on Windows.

APC smart protocol

The APC UPS protocol was originally analyzed by Pavel Korensky with additions from Andre H. Hendrick beginning in 1995, and we want to give credit for good, hard work, where credit is due. After having said that, you will see that Steven Freed built much of the original apcupsd information file.

The start of this chapter of the apcupsd manual in HTML format was pulled from the Network UPS Tools (NUT) site (http://www.networkupstools.org/ups-protocols/apcsmart.html). It has been an invaluable tool in improving apcupsd, and I consider it the Bible of APC UPS programming. In the course of using it, I have added information gleaned from apcupsd and information graciously supplied by APC.

Description

Here's the information on the elusive APC smart signaling protocol used by their higher end units (Back-UPS Pro, Smart-UPS, Matrix-UPS, etc). What you see here has been collected from a variety of sources. Some people analyzed the chatter between PowerChute and their hardware. Others sent various characters to the UPS and figured out what the results meant.

RS-232 differences

Normal 9 pin serial connections have TxD on 3 and RxD on 2. APC's smart serial ports put TxD on pin 1 and RxD on pin 2. This means you go nowhere if you use a normal straight through serial cable. In fact, you might even power down the load if you plug one of those cables in. This is due to the odd routing of pins - DTR and RTS from the PC usually wind up driving the on/off line. So, when you open the port, they go high and *poof* your computer dies.

The Smart Protocol

Despite the lack of official information from APC, this table has been constructed. It's standard RS-232 serial communications at 2400 bps/8N1. Don't rush the UPS while transmitting or it may stop talking to you. This isn't a problem with the normal single character queries, but it really does matter for multi-char things like "@000". Sprinkle a few calls to usleep() in your code and everything will work a lot better.

The following table describes the single character "Code" or command that you can send to the UPS, its meaning, and what sort of response the UPS will provide. Typically, the response shown below is followed by a newline (\n in C) and a carriage return (\r in C). If you send the UPS a command that it does not recognize or that is not available on your UPS, it will normally respond with "NA" for "not available", otherwise the response is given in the "Typical results" column.

Character Meaning Typical results Other info
^A Model string SMART-UPS 700 Spotty support for this query on older models
^N Turn on UPS n/a Send twice, with 1.5s delay between chars. Only on 3rd gen SmartUPS and Black Back-UPS Pros
^Z Permitted EEPROM Values long string Gives the EEPROM permitted values for your model. See EEPROM Values for details.
A Front panel test Light show + "OK" Also sounds the beeper for 2 seconds
B Battery voltage 27.87 Varies based on current level of charge. See also Nominal Battery Voltage.
C Internal Temperature 036.0 Units are degrees C
D Runtime calibration !, then $ Runs until battery is below 25% (35% for Matrix) Updates the 'j' values. Only works at 100% battery charge. Can be aborted with a second "D"
E Automatic self test interval 336

Writable variable. Possible values:

  • "336" (14 days)
  • "168" (7 days)
  • "ON " (at power on) note extra space
  • "OFF" (never)
F Line frequency 60.00 Units are Hz. Value varies based on locality, usually 50/60.
G Cause of last transfer to battery O

Possible values:

  • R (unacceptable utility voltage rate of change)
  • H (high utility voltage)
  • L (low utility voltage)
  • T (line voltage notch or spike)
  • O (no transfers since turnon)
  • S (transfer due to U command or activation of UPS test from front panel)
  • NA (transfer reason still not available; read again)
I Measure-UPS Alarm enable FF not decoded yet
J Measure-UPS Alarm status 0F,00 not decoded yet
K Shutdown with grace period (no return) OK or * Send twice with > 1.5s delay between chars. Older units send "*" instead of "OK". Length of grace period is set with Grace Period command. UPS will remain off and NOT power on if utility power is restored.
L Input line voltage 118.3 Value varies based on locality. Does not always read 000.0 on line failure.
M Maximum line voltage 118.9 This is the max voltage since the last time this query was run.
N Minimum line voltage 118.1 This is the min voltage since the last time this query was run.
O Output voltage 118.3 Also see on battery output voltage.
P Power load % 023.5 Relative to capacity of the UPS.
Q Status flags 08 Bitmapped, see status bits below
R Turn dumb BYE Only on 3rd gen SmartUPS, SmartUPS v/s, BackUPS Pro. Must send enter smart mode command to resume comms.
S Soft shutdown OK Command executes after grace period. UPS goes online when power returns. Only works when on battery.
U Simulate power failure !, then $ See Alert messages section for info on ! and $.
V Old firmware revision "GWD" or "IWI" See Interpretation of the Old Firmware Revision
W Self test OK Tests battery, like pushing button on the front panel. Results stored in "X"
X Self test results OK

Possible values:

  • OK = good battery
  • BT = failed due to insufficient capacity
  • NG = failed due to overload
  • NO = no results available (no test performed in last 5 minutes)
Y Enter smart mode SM This must be sent before any other commands will work. See also turn dumb command to exit smart mode.
Z Shutdown immediately n/a Send twice with > 1.5s delay between chars. UPS switches load off immediately (no grace period)
a Protocol info long string

Returns three main sections delimited by periods:

  • Protocol version
  • Alert messages (aka async notifiers)
  • Valid commands
b Firmware revision 50.9.D

See Interpretation of the New Firmware Revision.

Decoding the example:

  • 50 = SKU (variable length)
  • 9 = firmware revision
  • D = country code (D=USA, I=International, A=Asia, J=Japan, M=Canada)
c UPS local id UPS_IDEN Writable variable. Up to 8 letter identifier for keeping track of your hardware.
e Return threshold 00

Writable variable. Minimum battery charge % before UPS will return online after a soft shutdown. Possible values:

  • 00 = 00% (UPS turns on immediately)
  • 01 = 15%
  • 02 = 25%
  • 03 = 90%
f Battery level % 099.0 Percentage of battery charge remaining
g Nominal battery voltage 024 The battery voltage that's expected to be present in the UPS normally. This is a constant based on the type, number, and wiring of batteries in the UPS. Typically "012", "024" or "048".
h Measure-UPS ambient humidity (%) 042.4 Percentage. Only works on models with Measure-UPS SmartSlot card.
i Measure-UPS dry contacts 00

Bitmapped hex variable. Mapping:

  • 10 = contact 1
  • 20 = contact 2
  • 40 = contact 3
  • 80 = contact 4
j Estimated runtime 0327: Value is in minutes. Terminated with a colon.
k Alarm delay 0

Writable variable. Controls behavior of UPS beeper. Possible values:

  • 0 = 5 second delay after power fail
  • T = 30 second delay
  • L = alarm at low battery only
  • N = no alarm
l Low transfer voltage 103 Writable variable. UPS goes on battery when voltage drops below this point.
m Manufacture date 11/29/96 Format may vary by country (MM/DD/YY vs DD/MM/YY). Unique within groups of UPSes (production runs)
n Serial number WS9643050926 Unique for each UPS
o Nominal Output Voltage 115 Expected output voltage when running on batteries. May be a writable variable on 220/230/240 VAC units.
p Shutdown grace delay 020 Seconds. Writable variable. Sets the delay before soft shutdown completes. (020/180/300/600)
q Low battery warning 02 Minutes. Writable variable. The UPS will report a low battery condition this many minutes before it runs out of power
r Wakeup delay 000 Seconds. Writable variable. The UPS will wait this many seconds after reaching the minimum charge before returning online. (000/060/180/300)
s Sensitivity H

Writable variable. Possible values:

  • H = highest
  • M = medium
  • L = lowest
  • A = autoadjust (Matrix only)
t Measure-UPS ambient temperature 80.5 Degrees C. Only works on models with the Measure-UPS SmartSlot card.
u Upper transfer voltage 132 Writable variable. UPS goes on battery when voltage rises above this point.
v Measure-UPS firmware 4Kx Firmware information for Measure-UPS board
x Last battery change date 11/29/96 Writable variable. Holds whatever the user set in it. Eight characters.
y Copyright notice (C) APCC Only works if firmware letter is later than O
z Reset to factory settings CLEAR Resets most variables to initial factory values except identity or battery change date. Not available on SmartUPS v/s or BackUPS Pro.
+ Capability cycle (forward) various Cycle forward through possible capability values. UPS sends afterward to confirm change to EEPROM.
- Capability cycle (backward) various Cycle backward through possible capability values. UPS sends afterward to confirm change to EEPROM.
@nnn Shutdown and return OK or * UPS shuts down after grace period with delayed wakeup after nnn tenths of an hour plus any wakeup delay time. Older models send "*" instead of "OK".
0x7f Abort shutdown OK Use to abort @, S, K
~ Register #1 see below See Register 1 table
' Register #2 see below See Register 2 table
0 Battery constant   See Resetting the UPS Battery Constant
4 ???   Prints 35 on SmartUPS 1000
5 ???   Prints EF on SmartUPS 1000
6 ???   Prints F9 on SmartUPS 1000
7 DIP switch positions   See Dip switch info
8 Register #3 see below See Register 3 table
9 Line quality FF

Possible values:

  • 00 = unacceptable
  • FF = acceptable
> Number of external battery packs   SmartCell models return number of connected packs. Other models return value set by the user (use +/-).
[ Measure-UPS Upper temp limit NO,NO Degrees C. Writable Variable. Possible values: 55, 50, 45, ..., 05. Use +/- to change values.
] Measure-UPS lower temp limit NO,NO Degrees C. Writable Variable. Possible values: 55, 50, 45, ..., 05. Use +/- to change values.
{ Measure-UPS Upper humidity limit NO,NO Percentage. Writable Variable. Possible values: 90, 80, 70, ..., 10. Use +/- to change values.
} Measure-UPS lower humidity limit NO,NO Percentage. Writable Variable. Possible values: 90, 80, 70, ..., 10. Use +/- to change values.
Matrix-UPS and Symmetra Commands
^ Run in bypass mode BYP, INV, ERR If online, "BYP" response is received as bypass mode starts. If already in bypass, "INV" is received and UPS goes online. If UPS can't transfer, "ERR" received
< Number of bad battery packs 000 Count of bad packs connected to the UPS
/ Load current nn.nn True RMS load current drawn by UPS
\ Apparent load power nnn.nn Output load as percentage of full rated load in VA.
^V Output voltage selection  

Writable variable. Possible values:

  • A = automatic (based on input tap)
  • M = 208 VAC
  • I = 240 VAC
^L Front panel language  

Writable variable. Possible values:

  • E = English
  • F = French
  • G = German
  • S = Spanish
  • 1 = unknown
  • 2 = unknown
  • 3 = unknown
  • 4 = unknown
w Run time conservation  

Writable variable. Minutes of runtime to leave in battery (UPS shuts down "early"). Possible values:

  • NO = disabled
  • 02 = leave 2 minutes of runtime
  • 05 = leave 5 minutes
  • 08 = leave 8 minutes

Dip switch info

Bit Switch Option when bit=1
0 4 Low battery alarm changed from 2 to 5 mins. Autostartup disabled on SU370ci and 400
1 3 Audible alarm delayed 30 seconds
2 2 Output transfer set to 115 VAC (from 120 VAC) or to 240 VAC (from 230 VAC)
3 1 UPS desensitized - input voltage range expanded
4-7   Unused at this time

Status bits

This is probably the most important register of the UPS, which indicates the overall UPS status. Some common things you'll see:

  • 08 = On line, battery OK
  • 10 = On battery, battery OK
  • 50 = On battery, battery low
  • SM = Status bit is still not available (retry reading)
Bit Meaning when bit=1
0 Runtime calibration occurring (Not reported by Smart UPS v/s and BackUPS Pro)
1 SmartTrim (Not reported by 1st and 2nd generation SmartUPS models)
2 SmartBoost
3 On line (this is the normal condition)
4 On battery
5 Overloaded output
6 Battery low
7 Replace battery

Alert messages

These single character messages are sent by the UPS any time there is an Alert condition. All other responses indicated above are sent by the UPS only in response to a query or action command.

Character Meaning Description
! Line Fail Sent when the UPS goes on-battery, repeated every 30 seconds until low battery condition reached. Sometimes occurs more than once in the first 30 seconds.
$ Return from line fail UPS back on line power. Only sent if a ! has been sent previously.
% Low battery Sent to indicate low battery. Not implemented on SmartUPS v/s or BackUPS Pro models
+ Return from low batt Sent when the battery has been recharged to some level Only sent if a % has been sent previously.
? Abnormal condition Sent for conditions such as "shutdown due to overload" or "shutdown due to low battery capacity". Also occurs within 10 minutes of turnon.
= Return from abnormal condition Sent when the UPS returns from an abnormal condition where ? was sent, but not a turn-on. Not implemented on SmartUPS v/s or BackUPS Pro models.
* About to turn off Sent when the UPS is about to switch off the load. No commands are processed after this character is sent. Not implemented on SmartUPS v/s, BackUPS Pro, or 3rd generation SmartUPS models.
# Replace battery Sent when the UPS detects that the battery needs to be replaced. Sent every 5 hours until a new battery test is run or the UPS is shut off. Not implemented on SmartUPS v/s or BackUPS Pro models.
& Check alarm register for fault (Measure-UPS) Sent to signal that temp or humidity out of set limits. Also sent when one of the contact closures changes state. Sent every 2 minutes until the alarm conditions are reset. Only sent for alarms enabled with I. Cause of alarm may be determined with J. Not implemented on SmartUPS v/s or BackUPS Pro.
| Variable change in EEPROM Sent whenever any EEPROM variable is changed. Only supported on Matrix UPS and 3rd generation SmartUPS models.

Register 1

All bits are valid on the Matrix UPS. SmartUPS models only support bits 6 and 7. Other models do not respond.

Bit Meaning when bit=1
0 In wakeup mode (typically lasts < 2s)
1 In bypass mode due to internal fault (see Register 2 or Register 3)
2 Going to bypass mode due to command
3 In bypass mode due to command
4 Returning from bypass mode
5 In bypass mode due to manual bypass control
6 Ready to power load on user command
7 Ready to power load on user command or return of line power

Register 2

Matrix UPS models report bits 0-5. SmartUPS models only support bits 4-6. SmartUPS v/s and BackUPS Pro report bits 4, 6, 7. Unused bits are set to 0. Other models do not respond.

Bit Meaning when bit=1
0 Fan failure in electronics, UPS in bypass
1 Fan failure in isolation unit
2 Bypass supply failure
3 Output voltage select failure, UPS in bypass
4 DC imbalance, UPS in bypass
5 Battery is disconnected
6 Relay fault in SmartTrim or SmartBoost
7 Bad output voltage

Register 3

All bits are valid on the Matrix UPS and 3rd generation SmartUPS models. SmartUPS v/s and BackUPS Pro models report bits 0-5. All others report 0-4. State change of bits 1,2,5,6,7 are reported asynchronously with ? and = messages.

Bit Meaning when bit=1
0 Output unpowered due to shutdown by low battery
1 Unable to transfer to battery due to overload
2 Main relay malfunction - UPS turned off
3 In sleep mode from @ command (maybe others)
4 In shutdown mode from S command
5 Battery charger failure
6 Bypass relay malfunction
7 Normal operating temperature exceeded

Interpretation of the Old Firmware Revision

The Old Firmware Revision is obtained with the "V" command, which gives a typical response such as "GWD" or "IWI", and can be interpreted as follows:

Old Firmware revision and model ID String for SmartUPS & MatrixUPS

This is a three character string XYZ

   where X == Smart-UPS or Matrix-UPS ID Code.
     range 0-9 and A-P
       1 == unknown
       0 == Matrix 3000
       5 == Matrix 5000
     the rest are Smart-UPS and Smart-UPS-XL
       2 == 250       3 == 400       4 == 400
       6 == 600       7 == 900       8 == 1250
       9 == 2000      A == 1400      B == 1000
       C == 650       D == 420       E == 280
       F == 450       G == 700       H == 700XL
       I == 1000      J == 1000XL    K == 1400
       L == 1400XL    M == 2200      N == 2200XL
       O == 3000      P == 5000

   where Y == Possible Level of Smart Features, unknown???
       G == Stand Alone
       T == Stand Alone
               V == ???
       W == Rack Mount

   where Z == National Model Use Only Codes
       D == Domestic        115 Volts
       I == International   230 Volts
       A == Asia ??         100 Volts
       J == Japan ??        100 Volts

Interpretation of the New Firmware Revision

New Firmware revision and model ID String in NN.M.L is the format

    where NN == UPS ID Code.
        12 == Back-UPS Pro 650
        13 == Back-UPS Pro 1000
        52 == Smart-UPS 700
        60 == SmartUPS 1000
        72 == Smart-UPS 1400

        where NN now Nn has possible meanings.
            N  == Class of UPS
            1n == Back-UPS Pro
            5n == Smart-UPS
            7n == Smart-UPS NET

             n == Level of intelligence
            N1 == Simple Signal, if detectable WAG(*)
            N2 == Full Set of Smart Signals
            N3 == Micro Subset of Smart Signals

    where M == Possible Level of Smart Features, unknown???
        1 == Stand Alone
        8 == Rack Mount
        9 == Rack Mount

    where L == National Model Use Only Codes
        D == Domestic        115 Volts
        I == International   230 Volts
        A == Asia ??         100 Volts
        J == Japan ??        100 Volts
        M == North America   208 Volts (Servers)

EEPROM Values

Upon sending a ^Z, your UPS will probably spit back approximately 254 characters something like the following (truncated here for the example):

#uD43132135138129uM43229234239224uA43110112114108 ....

It looks bizarre and ugly, but is easily parsed. The # is some kind of marker/ident character. Skip it. The rest fits this form:

  • Command character - use this to select the value
  • Locale - use 'b' to find out what yours is (the last character), '4' applies to all
  • Number of choices - '4' means there are 4 possibilities coming up
  • Choice length - '3' means they are all 3 chars long

Then it's followed by the choices, and it starts over.

Matrix-UPS models have ## between each grouping for some reason.

Here is an example broken out to be more readable:

CMD DFO RSP FSZ FVL
u   D   4   3   127 130 133 136
u   M   4   3   229 234 239 224
u   A   4   3   108 110 112 114
u   I   4   3   253 257 261 265
l   D   4   3   106 103 100 097
l   M   4   3   177 172 168 182
l   A   4   3   092 090 088 086
l   I   4   3   208 204 200 196
e   4   4   2   00   15  50  90
o   D   1   3   115
o   J   1   3   100
o   I   1   3   230 240 220 225
o   M   1   3   208
s   4   4   1     H   M   L   L
q   4   4   2    02  05  07  10
p   4   4   3   020 180 300 600
k   4   4   1     0   T   L   N
r   4   4   3   000 060 180 300
E   4   4   3   336 168  ON OFF

CMD == UPSlink Command.
    u = upper transfer voltage
    l = lower transfer voltage
    e = return threshold
    o = output voltage
    s = sensitivity
    p = shutdown grace delay
    q = low battery warning
    k = alarm delay
    r = wakeup delay
    E = self test interval

DFO == (4)-all-countries (D)omestic (I)nternational (A)sia (J)apan
     (M) North America - servers.
RSP == Total number possible answers returned by a given CMD.
FSZ == Max. number of field positions to be filled.
FVL == Values that are returned and legal.

Programming the UPS EEPROM

There are at this time a maximum of 12 different values that can be programmed into the UPS EEPROM. They are:

Command Meaning
c The UPS Id or name
x The last date the batteries were replaced
u The Upper Transfer Voltage
l The Lower Transfer Voltage
e The Return Battery Charge Percentage
o The Output Voltage when on Batteries
s The Sensitivity to Line Quality
p The Shutdown Grace Delay
q The Low Battery Warning Delay
k The Alarm Delay
r The Wakeup Delay
E The Automatic Self Test Interval

The first two cases (Ident and Batt date) are somewhat special in that you tell the UPS you want to change the value, then you supply 8 characters that are saved in the EEPROM. The last ten item are programmed by telling the UPS that you want it to cycle to the next permitted value.

In each case, you indicate to the UPS that you want to change the EEPROM by first sending the appropriate query command (e.g. "c" for the UPS ID or "u" for the Upper Transfer voltage. This command is then immediately followed by the cycle EEPROM command or "-". In the case of the UPS Id or the battery date, you follow the cycle command by the eight characters that you want to put in the EEPROM. In the case of the other ten items, there is nothing more to enter.

The UPS will respond by "OK" and approximately 5 seconds later by a vertical bar (|) to indicate that the EEPROM was changed.

NIS Network Server Protocol

The NIS network server in apcupsd is capable of sending status and events data to clients that request it. The communication between the client and the server is performed over a TCP connection to the NISPORT (normally port 3551). The client opens a connection to the server and sends a message, to which the server will reply with one or more messages. Each message consists of a 2-byte length (in network byte order) followed by that many bytes of data. Both the client->server and server->client messages follow this format.

apcupsd supports two commands, sent as the body of a message:

  1. "status" - The status command requests that the server send a copy of all status values, in the form displayed by apcaccess. After the client sends the "status" command, the server will reply with a series of messges, each one containing one line of apcaccess status data. The end of the command series is indicated by an empty message (length of 0).
  2. "events" - The events command operates the same as "status" except the server replies with lines from the log of recent events.

As an example, the following bytes would be sent by a client to solicit the status:

0x00 0x06 0x73 0x74 0x61 0x74 0x75 0x73

The first two bytes are the data length (6) in network byte order. The 6 bytes of data that follow are the ASCII characters for "status". The server will respond to this command with a series of its own messages containing the status data.

Apcupsd RPM Packaging FAQ

How do I build Apcupsd for platform xxx?

The apcupsd spec file contains defines to build for several platforms: RedHat 7.x (rh7), RedHat 8.0 (rh8), RedHat 9 (rh9), Fedora Core (fedora_core), RedHat Enterprise Linux and clones (rhel3 and rhel4), SuSE 9 & 10 (suse), and Mandrake (mdk). The package build is controlled by a define set at the beginning of the file. These defines basically just control the dependency information that gets coded into the finished rpm package. So while you could technically build a package without defining a platform, or with an incorrect platform, and have it install and run it would not contain correct dependency information for the rpm database. The platform define may be edited in the spec file directly (by default all defines are set to 0 or "not set"). For example, to build the RedHat 7.x package find the line in the spec file which reads

%define rh7 0

and edit it to read

%define rh7 1

Alternately you may pass the define on the command line when calling rpmbuild:

rpmbuild -ba --define "build_rh7 1" apcupsd.spec
rpmbuild --rebuild --define build_rh7 1" apcupsd-x.x.x-x.src.rpm
How do I control whether usb support gets built?

Up through version 3.12, by default standard serial port support was built and the apcupsd-std package was produced. The usb package pre-configured the configuration files for usb devices and installed a couple additional tools in /etc/apcupsd but the usb driver was built regardless. To get the usb package and support in those versions either set the

%define usb 0

to

%define usb 1

in the spec file directly or pass it to rpmbuild on the command line:

rpmbuild -ba --define "build_rh7 1" --define "build_usb 1" apcupsd.spec

With the release of 3.14 USB support is now considered standard and the apcupsd-std and apcupsd-usb packages are obsoleted in favor of a single apcupsd package configured for usb connected UPS's. The serial port driver is still built and can be configured accordingly after installation. If you are performing an upgrade it will of course not replace your current config file.

The build directive:

--define "build_usb 1"

is no longer recognized.

What other defines are used?

There is a define for the initdir for the daemon control script. On RedHat or Mandrake systems this is set to /etc/rc.d/init.d/. On SuSE systems this is set to /etc/rc.d. You would only need to edit this if packaging for a platform that uses a different directory.

A second define controls whether the Gnome monitoring application, new in the 3.14 release, is built. This application requires the Gtk2 version to be >= 2.4. If you want to build the apcupsd-gapcmon package add:

--define "build_gapcmon 1"

A third define controls whether the SNMP driver is built. If you want to build the net-snmp driver add:

--define "build_snmp 1"
Can I supply packages for other platforms you do not publish?
Yes, there are tools provided for contributors to supply rpm packages for platforms for which support is provided in the spec file but for which the development team chooses not to release binary packages, usually due to lack of interest or lack of an available platform. Please see platforms/contrib/README in the source package.
I'm getting errors about not having permission when I try to build the packages. Do I need to be root?

No, you do not need to be root and, in fact, it is better practice to build rpm packages as a non-root user. Apcupsd's packages are designed to be built by a regular user but you must make a few changes on your system to do this. If you are building on your own system then the simplest method is to add write permissions for all to the build directory (/usr/src/redhat/). To accomplish this execute one of the following commands as root depending on your distribution, RedHat, SuSE or Mandriva, respectively:

chmod -R 777 /usr/src/redhat
chmod -R 777 /usr/src/packages
chmod -R 777 /usr/src/RPM

If you are working on a shared system where you can not use the method above then you need to recreate the /usr/src/redhat (or other) directory tree with all of it's subdirectories inside your home directory. Then create a file named

.rpmmacros

in your home directory (or edit the file if it already exists) and add the following line:

%_topdir /home/myuser/redhat

Credits

./thanks.png

The success of apcupsd is due to the many people that helped in development, testing and in many other ways.

Thank all the developers that worked hard to make APCUPSD one of the best piece of software for UPS management.

Contributors

Current Code Maintainer and Project Manager
Adam Kropelin (adam@kroptech.com)
RPM Packager
D. Scott Barninger
CGI and HTML fixer
William King (wrking@dadaboom.com)
Former Project Manager
Kern Sibbald (kern@sibbald.com)
Project Starter and Former Code Maintainer
Andre Hedrick (andre@linux-ide.org)
Former Code Maintainer and Project Manager
Riccardo Facchetti (riccardo@master.oasi.gpa.it)
Serial Communications
Andre Hedrick (andre@linux-ide.org)
2.0 User's Manual
Eric S. Raymond (esr@thyrsus.com)
Alpha Port
Kern Sibbald (kern@sibbald.com) J. Rochate (jrochate@ualg.pt) testing and machine loan
Caldera
John Pinner (john@clocksoft.com)
HP-UX Port
Carl Erhorn (Carl_Erhorn@hyperion.com) Robert K Nelson (rnelson@airflowsciences.com)
SOLARIS Port
Carl Erhorn (Carl_Erhorn@hyperion.com)
OpenBSD Port
Devin Reade (gdr@gno.org)
NetBSD Port
Neil Darlow (neil@darlow.co.uk)
Win32 Port
Kern Sibbald (kern@sibbald.com) Paul Z. Stagner
WEB Interfaces
Kern Sibbald (kern@sibbald.com) Joseph Acosta (joeja@mindspring.com)

Apcupsd License

Apcupsd is licensed under the terms of the GNU General Public License, version 2 (GPLv2). The full text of this license may be found in the COPYING file at the top of the source tree and online at http://www.gnu.org/licenses/gpl-2.0.html.

Source files are copyright of their specific author(s), as noted in the files.

This program is free software; you can redistribute it and/or
modify it under the terms of version 2 of the GNU General
Public License as published by the Free Software Foundation.

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, 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1335, USA.

Other Open Source Licenses

Apcupsd incorporates the libusbhid library which is subject to the following copyright and license:

Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
apcupsd-3.14.14/doc/manual/manual.rst000066400000000000000000007130711274230402600173650ustar00rootroot00000000000000.. title:: APCUPSD User Manual .. image:: ./apcupsd.png =================== APCUPSD User Manual =================== | **Adam Kropelin** | **Kern Sibbald** **Apcupsd is a UPS control system that permits orderly shutdown of your computer in the event of a power failure.** | |date| |time| | This manual documents apcupsd version 3.14.x | Copyright |(C)| 2004-2015 Adam Kropelin | Copyright |(C)| 1999-2005 Kern Sibbald *Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the name Apcupsd, the copyright notice, and this notice are preserved.* *Apcupsd source code is released under the GNU General Public License version 2. Please see the file COPYING in the main source directory.* For more information on the project, please visit the main web site at http://www.apcupsd.com --------------------------------------------------------------------------- .. contents:: Table of Contents :local: :depth: 3 --------------------------------------------------------------------------- Important Legal Disclaimer ========================== No person should rely on the contents of the APCUPSD Manual ("the manual") without first obtaining advice from APC Technical Support. The manual is provided on the terms and understanding that: 1. the authors, contributors and editors are not responsible for the results of any actions taken on the basis of information in the manual, nor for any error in or omission from the manual; and 2. the authors, contributors and editors are not engaged in rendering technical or other advice or services. The the authors, contributors and editors, expressly disclaim all and any liability and responsibility to any person, whether a reader of the manual or not, in respect of anything, and of the consequences of anything, done or omitted to be done by any such person in reliance, whether wholly or partially, on the whole or any part of the contents of the manual. Without limiting the generality of the above, no author, contributor or editor shall have any responsibility for any act or omission of any other author, contributor or editor. How To Use This Manual ====================== This is the manual for apcupsd, a daemon for communicating with UPSes (Uninterruptible Power Supplies) made by American Power Conversion Corporation (APC). If you have an APC-made UPS, whether sold under the APC nameplate or OEMed (for example, the HP PowerTrust 2997A), and you want you get it working with a computer running Linux, Unix, or Windows, you are reading the right document. This manual is divided into parts which increase in technical depth as they go. If you have just bought a state-of-the-art smart UPS with a USB or Ethernet interface, and you are running a current version of Red Hat or SUSE Linux, then apcupsd is very nearly plug-and-play and you will have to read only the `Basic User's Guide`_. If your operating system is older, or if you have an old-fashioned serial-line UPS, you'll have to read about serial installation (see `Installation: Serial-Line UPSes`_). If you need more details about administration for unusual situations (such as a master/slave or multi-UPS setup) you'll need to read the sections on those topics as well. Finally, there are a number of technical reference sections which gives full details on things like configuration file directives and event-logging formats. You should begin by reading the Quick Start (see `Quick Start for Beginners`_) instructions. Basic User's Guide ================== Quick Start for Beginners ------------------------- apcupsd is a complex piece of software, but most of its complexities are meant for dealing with older hardware and operating systems. On current hardware and software getting it running should not be very complicated. The following is a help guide to the steps needed to get apcupsd set up and running as painlessly as possible. #. Check to see if apcupsd supports your UPS and cable (see `Supported UPSes and Cables`_). #. Check to see if apcupsd supports your operating system (see `Supported Operating Systems`_). #. Plan your configuration type (see `Choosing a Configuration Type`_). If you have just one UPS and one computer, this is easy. If you have more than one machine being served by the same UPS, or more than one UPS supplying power to computers that are on the same local network, you have more choices to make. #. Figure out if you have one of the easy setups. If you have a USB UPS, and a supported operating system and you want to use one UPS with one computer, that's an easy setup. APC supplies the cable needed to talk with that UPS along with the UPS. All you need to do is check that your USB subsystem is working (see `USB Configuration`_); if so, you can go to the build and install step. #. If you have a UPS designed to communicate via SNMP over Ethernet, that is also a relatively easy installation. Details are provided in `Support for SNMP UPSes`_. #. If you have a UPS that communicates via an RS232C serial interface and it is a SmartUPS, then things are relatively simple, otherwise, your life is about to get interesting. #. If you have a vendor-supplied cable, find out what cable type you have by looking on the flat ends of the cable for a number, such as 940-0020A, stamped in the plastic. #. If you don't have a vendor-supplied cable, or your type is not supported, you may have to build one yourself (see `Cables`_). Here is hoping you are good with a soldering iron! #. Now you are ready to read the Building and Installing (see `Building and Installing apcupsd`_) section of the manual and follow those directions. If you are installing from an RPM or some other form of binary package, this step will probably consist of executing a single command. #. Tweak your /etc/apcupsd/apcupsd.conf file as necessary. Often it will not be. #. Change the BIOS settings (see `Arranging for Reboot on Power-Up`_) on your computer so that boots up every time it gets power. (This is not the default on most systems.) #. To verify that your UPS is communicating with your computer and will do the right thing when the power goes out, read and follow the instructions in the Testing (see `Testing Apcupsd`_) section. #. If you run into problems, check the apcupsd users' email list archive for similar problems. This is an excellent resource with answers to all sorts of questions. See http://sourceforge.net/mailarchive/forum.php?forum_name=apcupsd-users. #. If you still need help, send a message to the apcupsd users' email list (apcupsd-users@lists.sourceforge.net) describing your problem, what version of apcupsd you are using, what operating system you are using, and anything else you think might be helpful. #. Read the manual section on `Monitoring and Tuning your UPS`_. Supported Operating Systems --------------------------- apcupsd supports many UNIX-like operating systems as well as several variants of Windows. Due to lack of API standardization, USB support is not available on every platform. See `Platform Support`_ below for details. In general it is recommended to obtain a prebuilt package for your platform. Given how apcupsd must integrate into the shutdown mechanism of the operating system and the rate at which such mechanisms are changed by vendors, the platform ports in the apcupsd tree may become out of date. In some cases, binary packages are provided by the apcupsd team (RedHat, Mandriva, SuSE, Windows, Mac OS X). For other platforms it is recommended to check your vendor's package repository and third party repositories for recent binary packages. Note that some vendors continue to distribute ancient versions of apcupsd with known defects. These packages should *not* be used. Platform Support ~~~~~~~~~~~~~~~~ **LINUX** - RedHat [1]_ [2]_ - SuSE [2]_ - Mandriva/Mandrake [2]_ - Debian [3]_ - Slackware [3]_ - Engarde [3]_ - Yellowdog [3]_ - Gentoo [3]_ **WINDOWS** - Windows NT 4 [2]_ [4]_ - Windows 98/ME/2000 [2]_ [4]_ - Windows XP/Vista (including 64 bit) [1]_ [2]_ - Windows Server 2003/2008 (including 64 bit) [2]_ - Windows 7 [2]_ **OTHERS** - Mac OS X Darwin [1]_ [2]_ - Solaris 8/9 [4]_ - Solaris 10 - NetBSD - FreeBSD - OpenBSD - HPUX [3]_ [4]_ - Unifix [3]_ [4]_ - QNX [4]_ .. [1] Platforms on which apcupsd is regularly developed and tested .. [2] Platforms for which apcupsd team distributes binary packages .. [3] Port included in apcupsd source tree but may be out of date, unmaintained, or broken. .. [4] USB not supported Supported UPSes and Cables -------------------------- apcupsd supports nearly every APC brand UPS model in existence and enough different cable types to connect to all of them. The ``UPSTYPE `` field is the value you will put in your /etc/apcupsd/apcupsd.conf file to tell apcupsd what type of UPS you have. We'll describe the possible values here, because they're a good way to explain your UPS's single most important interface property: the kind of protocol it uses to talk with its computer. apcsmart The 'apcsmart' protocol uses an RS232 serial connection to pass commands back and forth in a primitive language resembling modem-control codes. APC calls this language "UPS-Link". Originally introduced for Smart-UPS models (thus the name 'apcsmart'), this class of UPS is in decline, rapidly being replaced in APC's product line by USB and MODBUS UPSes. usb A USB UPS speaks a universal well defined control language over a USB wire. Most of APC's lineup now uses this method as of late 2003, and it seems likely to completely take over in their low- and middle range. The most recent APC UPSes support only a limited set of data over the USB interface. MODBUS (see below) is required in order to access the advanced data. net This is the keyword to specify if you are using your UPS in Slave mode (i.e. the machine is not directly connected to the UPS, but to another machine which is), and it is connected to the Master via an ethernet connection. You must have apcupsd's Network Information Services NIS turned on for this mode to work. snmp SNMP UPSes communicate via an Ethernet NIC and firmware that speaks Simple Network Management Protocol. dumb A dumb or voltage-signaling UPS and its computer communicate through the control lines (not the data lines) on an RS232C serial connection. Not much can actually be conveyed this way other than an order to shut down. Voltage-signaling UPSes are obsolete; you are unlikely to encounter one other than as legacy hardware. If you have a choice, we recommend you avoid simple signalling UPSes. pcnet PCNET is an alternative for SNMP available on APC's AP9617 family of smart slot modules. The protocol is much simpler and potentially more secure than SNMP. modbus MODBUS is the newest APC protocol and operates over RS232 serial links or USB. MODBUS is APC's replacement for the aging 'apcsmart' (aka UPS-Link) protocol. MODBUS is the only way to access detailed control and status information on newer (esp. SMT series) UPSes. Choosing a Configuration Type ----------------------------- There are three major ways of running apcupsd on your system. The first is a standalone configuration where apcupsd controls a single UPS, which powers a single computer. This is the most common configuration. If you're working with just one machine and one UPS, skip the rest of this section. Your choices become more interesting if you are running a small cluster or a big server farm. Under those circumstances, it may not be possible or even desirable to pair a UPS with every single machine. apcupsd supports some alternate arrangements. The second type of configuration is the NIS (Network Information Server) server and client. In this configuration, where one UPS powers several computers, a copy of apcupsd running one one computer will act as a server while the other(s) will act as network clients which poll the server for information about the UPS. Note that "NIS" is *not* related to Sun's directory service also called "NIS" or "Yellow Pages". The third configuration is where a single computer controls multiple UPSes. In this case, there are several instances of apcupsd on the same computer, each controlling a different UPS. One instance of apcupsd will run in standalone mode, and the other instance will normally run in network mode. This type of configuration may be appropriate for large server farms that use one dedicated machine for monitoring and diagnostics Here is a diagram that summarizes the possibilities: Configuration types ------------------- .. image:: ./main_configs.png If you decide to set up one of these more complex configurations, see the dedicated section on that particular configuration. USB Configuration ================= Apcupsd supports USB connections on all major operating systems: Linux, FreeBSD, OpenBSD, NetBSD, Windows, Solaris, and Mac OS X Darwin. If you plan to use a USB connection, please read the appropriate subsection in its entirety. You can skip this section if your UPS has a serial (RS232-C) or Ethernet interface or if you are not running one of the platforms listed above. Linux USB Configuration ----------------------- Known Linux USB Issues ~~~~~~~~~~~~~~~~~~~~~~ **Problem** Linux 2.4 series kernels older than 2.4.22 (RH 9, RHEL 3) do not bind the USB device to the proper driver. This is evidenced by /proc/bus/usb/devices listing the UPS correctly but it will have "driver=(none)" instead of "driver=(hid)". This affects RHEL3, among others. **Workaround** Upgrade linux kernel to 2.4.22 or higher. Alternately, you apply the linux-2.4.20-killpower.patch and linux-2.4.20-USB-reject.patch patches to your kernel and rebuild it. These patches can be found in the examples/ directory in the apcupsd source distribution. **Problem** Mandrake 10.0 and 10.1 systems with high security mode enabled (running kernel-secure kernel) use static device nodes but still assign USB minor numbers dynamically. This is evidenced by ``hiddev0: USB HID v1.10 Device [...]`` instead of ``hiddev96: ...`` in dmesg log. **Workaround** Boot standard kernel instead of kernel-secure or disable CONFIG_USB_DYNAMIC_MINORS and rebuild kernel-secure. **Problem** USB driver linux-usb.c fails to compile, reporting errors about ``HID_MAX_USAGES undefined``. This is due to a defect in the linux kernel hiddev.h header file on 2.6.5 and higher kernels. **Workaround** Upgrade to apcupsd-3.10.14 or higher. These versions contain a workaround for the defect. **Problem** On some systems such as Slackware 10.0, no USB devices will show up (see the next section). **Workaround** Add the following to rc.local :: mount -t usbdevfs none /proc/bus/usb **Problem** 2.6 kernels use udev and some distributions to not configure it to automatically create /dev/usb/hiddev?? as they should, causing apcupsd to fail to locate the UPS. **Workaround** Edit the file /etc/udev/rules.d/50-udev.rules, and add the following: :: KERNEL="hiddev*", NAME="usb/hiddev%n" More details are provided in the following section ... Verifying Device Detection and Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To make sure that your USB subsystem can see the UPS, just do this from a shell prompt: :: cat /proc/bus/usb/devices This information is updated by the kernel whenever a device is plugged in or unplugged, irrespective of whether apcupsd is running or not. It contains details on all the USB devices in your system including hubs (internal and external), input devices, and UPSes. You should get some output back that includes something like this, featuring a BackUPS RS 1000: :: T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 3 Spd=1.5 MxCh= 0 D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=051d ProdID=0002 Rev= 1.06 S: Manufacturer=American Power Conversion S: Product=Back-UPS RS 1000 FW:7.g3 .D USB FW:g3 S: SerialNumber=JB0308036505 C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr= 24mA I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00 Driver=hid The important things to check for are the ``S:`` lines describing your UPS and and the ``I:`` line showing what driver is handling it. If on the ``I:`` line, ``Driver`` is listed as ``Driver=none`` then you do not have the HID driver loaded or the driver did not attach to the UPS. One common cause is having a Linux kernel older than 2.4.22 (such as a stock RedHat 9 or RHEL 3 kernel). If this is the case for your system, please upgrade to at least kernel version 2.4.22 and try again. If you are already running a 2.4.22 or higher kernel, please read further for instructions for other possible courses of action. Here is another example, this time featuring a Back-UPS 350: :: T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=1.5 MxCh= 0 D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 P: Vendor=051d ProdID=0002 Rev= 1.00 S: Manufacturer=American Power Conversion S: Product=Back-UPS 350 FW: 5.2.I USB FW: c1 S: SerialNumber=BB0115017954 C:* #Ifs= 1 Cfg#= 1 Atr=a0 MxPwr= 30mA I: If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00 Driver=hid E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl= 10ms In general, if you see your UPS model in the ``S:`` field, which means ``Manufacturer=``, ``Product=``, and ``SerialNumber=``, and you see ``Driver=hid`` in the ``I:`` field, you know the UPS has been recognized and is bound to the correct driver. If your UPS doesn't appear in the list at all, check the obvious things: The UPS must be powered on, and a cable must be properly seated in both the data port of the UPS and one of your machine's USB ports. Many UPSes have phone ports to provide surge protection for phones or modems -- make sure you haven't plugged your USB cable into one of those rather than the data port (which will usually be near the top edge of the case.) Also, ensure that the correct drivers are loaded. Under Linux-2.4.x, you can check this out easily by examining the /proc/bus/usb/drivers file. Here's how you can do that: :: cat /proc/bus/usb/drivers ...and you should get: :: usbdevfs hub 96-111: hiddev hid On Linux-2.6.x, make sure the sysfs filesystem is mounted on /sys and do: :: ls -l /sys/bus/usb/drivers/ ...where you should get: :: total 0 drwxr-xr-x 2 root root 0 May 1 18:55 hid drwxr-xr-x 2 root root 0 May 1 18:55 hiddev drwxr-xr-x 2 root root 0 May 1 18:55 hub drwxr-xr-x 2 root root 0 May 1 18:55 usb drwxr-xr-x 2 root root 0 May 1 18:55 usbfs ...or perhaps something like: :: total 0 drwxr-xr-x 2 root root 0 Jan 6 15:27 hiddev drwxr-xr-x 2 root root 0 Jan 6 15:28 hub drwxr-xr-x 2 root root 0 Jan 6 15:28 usb drwxr-xr-x 2 root root 0 Jan 6 15:27 usbfs drwxr-xr-x 2 root root 0 Jan 6 15:28 usbhid If your 2.6.x system does not have the /sys/bus/usb directory, either you do not have sysfs mounted on /sys or the USB module(s) have not been loaded. (Check /proc/mounts to make sure sysfs is mounted.) A USB UPS needs all of these drivers -- the USB device filesystem, the USB hub, the Human Interface Device subsystem driver, and the Human Interface Device driver. If you are compiling your own kernel, you want to enable :: CONFIG_USB CONFIG_USB_HID CONFIG_USB_HIDDEV CONFIG_USB_DEVICEFS ...as well as at least one USB Host Controller Driver... :: CONFIG_USB_UHCI_HCD (linux-2.6.x) CONFIG_USB_OHCI_HCD (linux-2.6.x) CONFIG_USB_UHCI (linux-2.4.x) CONFIG_USB_OHCI (linux-2.4.x) Device Nodes ~~~~~~~~~~~~ Apcupsd accesses USB UPSes via the hiddev device nodes. Typically these are located in ``/dev/hiddevN``, ``/dev/usb/hiddevN`` or ``/dev/usb/hiddev/hiddevN`` (where ``N`` is a digit 0 thru 9). Some distributions (some Debian releases, possibly others) do not provides these device nodes for you, so you will have to make them yourself. Check ``/dev``, ``/dev/usb``, and ``/dev/usb/hiddev`` and if you cannot find the ``hiddevN`` nodes, run (as root) the ``examples/make-hiddev`` script from the apcupsd source distribution. Modern Linux distributions using the 2.6 kernel create device nodes dynamically on the fly as they are needed. It is basically a hotplug system, giving a lot more power to the user to determine what happens when a device is probed or opened. It is also a lot more complicated. Some early 2.6 distributions (Fedora Core 3, for one) do not include hiddev rules in their default udev rule set. The bottom line for apcupsd on such a system is that if the ``hiddevN`` is not created when you plug in your UPS, apcupsd will terminate with an error. The solution to the problem is to add a rule to the udev rules file. On Fedora FC3, this file is found in ``/etc/udev/rules.d/50-udev.rules``. Start by adding the following line: :: BUS="usb", SYSFS{idVendor}="051d", NAME="usb/hiddev%n" *Note that this rule uses obsolete udev syntax and is specific to FC3 and other distributions of similar vintage.* Then either reboot your system, or unplug and replug your UPS and then restart apcupsd. At that point a ``/dev/usb/hiddevN`` node should appear and apcupsd should work fine. If you have several UPSes or you just want to give your UPS a fixed name, you can use rules like the following: :: KERNEL=="hiddev*", SYSFS{serial}=="JB0319033692", SYMLINK="ups0" KERNEL=="hiddev*", SYSFS{serial}=="JB0320004845", SYMLINK="ups1" *Note that this rule uses udev syntax that is appropriate only for distros such as RHEL4 and FC4 and others of a similar vintage.* More recent distros such as FC15 should use something like this: :: KERNEL=="hiddev*", ATTRS{manufacturer}=="American Power Conversion", ATTRS{serial}=="BB0100009999 ", OWNER="root", SYMLINK+="ups0" Replace the serial number in quotes with the one that corresponds to your UPS. Then whenever you plug in your UPS a symlink called ups0, ups1, etc. will be created pointing to the correct hiddev node. This technique is highly recommended if you have more than one UPS connected to the same server since rearranging your USB cables or even upgrading the kernel can affect the order in which devices are detected and thus change which hiddev node corresponds to which UPS. If you use the symlink-by-serial-number approach the link will always point to the correct device node. You can use... :: udevinfo -a -p /sys/class/usb/hiddev0/ ...to get more information on the fields that can be matched besides serial number. To find the available attributes to match (note that the serial is NOT always the UPS serial on the box or in the USB connect message in /var/log/messages), use: :: udevadm info --attribute-walk --name=/dev/usb/hiddev0 An additional device-node-related problem is the use of dynamic minors. Some distributions, such as Mandrake 10, ship with a kernel having ``CONFIG_USB_DYNAMIC_MINORS`` turned on. This is not ideal for running with apcupsd, and the easiest solution is to turn ``CONFIG_USB_DYNAMIC_MINORS`` off and rebuild your kernel, or find a pre-built kernel with it off. For a kernel with ``CONFIG_USB_DYNAMIC_MINORS`` turned on to work with apcupsd, you must enable ``devfs``. The following will tell you if devfs is enabled: :: $ ps ax | grep devs ...which should give something like the following: :: 533 ? S 0:00 devfsd /dev What complicates the situation much more on Mandrake kernels is their security level since ``CONFIG_DYNAMIC_USB_MINORS`` is turned on, but on higher security levels devfs is turned off. The net result, is that in those situations hiddev is completely unusable so apcupsd will not work. So, in these cases, the choices are: #. Reduce the security level setting of the system (not sure if this is possible after the initial install). #. Custom build a high security kernel with devfs enabled and make sure devfs is mounted and devfsd is running. #. Custom build a high security kernel with dynamic minors disabled #. Use udev Miscellaneous ~~~~~~~~~~~~~ If all these things check out and you still can't see the UPS, something is more seriously wrong than this manual can cover -- find expert help. If you are unable to list USB devices or drivers, you kernel may not be USB-capable and that needs to be fixed. BSD USB Configuration --------------------- Known BSD USB Issues ~~~~~~~~~~~~~~~~~~~~ **Problem** FreeBSD lockups: Some users have experienced lockups (apcupsd stops responding) on FreeBSD systems. **Solution** Recent versions of Apcupsd have addressed this issue. Please upgrade to apcupsd-3.10.18 or higher. **Problem** FreeBSD kernel panics if USB cable is unplugged while apcupsd is running. **Solution** This is a kernel bug and is most easily worked around by not hot- unplugging the UPS while apcupsd is running. This issue may be fixed in recent FreeBSD kernels. Platforms and Versions ~~~~~~~~~~~~~~~~~~~~~~ The \*BSD USB driver supports FreeBSD, OpenBSD and NetBSD. (Thanks go to the \*BSD developers who kept a nearly identical interface across all three platforms.) Kernel Configuration ~~~~~~~~~~~~~~~~~~~~ Users of OpenBSD, NetBSD, and some versions of FreeBSD will need to rebuild the kernel in order to *enable the ugen driver* and *disable the uhid driver*. uhid is not sufficient for apcupsd at this time and we need to prevent it from grabbing the UPS device. You should *make the following changes* to your kernel config file: *FreeBSD (v5.4 and below, v6.0)* | (you **will not** lose use of USB keyboard and mouse) | **Disable:** uhid | **Enable:** ugen *FreeBSD (v5.5, v6.1 and above)* | (you **will not** lose use of USB keyboard and mouse) | **Disable:** (nothing) | **Enable:** ugen This is the default configuration for a GENERIC kernel on many platforms so you most likely will not need to recompile. *NetBSD (v3.x and below)* | (you **will** lose use of USB keyboard and mouse) | **Disable:** uhidev, ums, wsmouse, ukbd, wskbd, uhid | **Enable:** ugen *NetBSD (v4.0 and above)* You can use apcupsd on single USB port without disabling the USB keyboard and mouse on other ports, though all other devices will be disabled on the port you pick for your UPS. First, decide which hub and port you wish to use. You can find out the hub and port numbers for any particular physical connector by plugging a USB device into it and looking at the messages printed by the kernel; you should messages something like this: :: uxx0 at uhub0 port 1 uxx0: To use your APC UPS on this port, configure the kernel to prefer attachment of the ugen driver over other drivers on this hub and port only, by adding a line like this to your kernel config file: :: ugen* at uhub0 port 1 flags 1 (The "flags 1" forces the ugen to attach instead of anything else detected there.) Configure and build that kernel as per the references below, and your UPS will now attach as a ugen device when plugged into that port. Don't forget to '``cd /dev``' and '``./MAKEDEV ugen1``' (and 2 and so on) if you have more than one generic usb device on your system. *OpenBSD* | (you **will** lose use of USB keyboard and mouse): | **Disable:** uhidev, ums, wsmouse, ukbd, wskbd, uhid | **Enable:** ugen For detailed information on rebuilding your kernel, consult these references: *FreeBSD* http://www.freebsd.org/doc/en\_US.ISO8859-1/books/handbook/kernelconfig.html *NetBSD* http://www.netbsd.org/guide/en/chap-kernel.html *OpenBSD* http://www.openbsd.org/faq/faq5.html#Building Verifying Device Detection and Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After building a properly configured kernel, reboot into that kernel and plug in your UPS USB cable. You should see a dmesg log message like the following: :: ugen0: American Power Conversion Back-UPS RS 1500 FW:8.g6 .D USB FW:g6, rev 1.10/1.06, addr 2 Note that the ``ugen`` driver is called out. If you see ``uhid`` instead, it probably means you did not properly disable the uhid driver when you compiled your kernel or perhaps you're not running the new kernel. You can also check with '``usbdevs -d``' to get a list of USB devices recognized by the system as well as the drivers they are associated with. For example: :: # usbdevs -d addr 1: UHCI root hub, VIA uhub0 addr 2: Back-UPS RS 1500 FW:8.g6 .D USB FW:g6, American Power Conversion ugen0 Device Nodes ~~~~~~~~~~~~ Apcupsd communicates with the UPS through the USB generic device, ``ugen``. You may or may not need to manually make ``ugen`` device nodes in ``/dev``, depending on what OS you are using. FreeBSD No manual intervention needed. FreeBSD automatically creates the ugen nodes on demand. NetBSD By default, NetBSD only creates nodes for the first ugen device, ``ugen0``. Check ``usbdevs -d`` to see which device your UPS was bound to and then create the appropriate node by running '``cd /dev ; ./MAKEDEV ugenN``', where ``ugenN`` is the ugen device name shown by ``usbdevs``. It is probably a good idea to create several sets of ugen nodes in case you add more USB devices. OpenBSD Similar to NetBSD, OpenBSD creates nodes for ``ugen0`` and ``ugen1``. Check ``usbdevs -d`` to see which device your UPS was bound to and then create the appropriate node by running '``cd /dev ; ./MAKEDEV ugenN``', where ``ugenN`` is the ugen device name shown by ``usbdevs``. It is probably a good idea to create several sets of ugen nodes in case you add more USB devices. Windows USB Configuration ------------------------- Platforms and Versions ~~~~~~~~~~~~~~~~~~~~~~ Apcupsd supports USB UPSes on Windows XP and newer, including 64 bit systems. USB Driver Installation ~~~~~~~~~~~~~~~~~~~~~~~ USB connected UPSes on Windows require a special driver. In most cases, this driver is automatically installed when you install Apcupsd. However in some cases you may need to install the driver manually. For detailed instructions, please see the ``install.txt`` file located in the driver folder of your Apcupsd install. Verifying Device Detection and Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After installing Apcupsd (and the Apcupsd USB driver, if necessary), plug in your UPS USB cable and open the Windows Device Manager. You should see a ``American Power Conversion USB UPS (Apcupsd)`` listed under the ``Batteries`` section. If a device of that name does not appear, check that your UPS is powered on and that the USB cable is connected at both ends. Reinstall the driver as directed above if needed. Solaris USB Configuration ------------------------- Platforms and Versions ~~~~~~~~~~~~~~~~~~~~~~ Apcupsd supports USB UPSes on Solaris 10 and higher. Both x86 and SPARC platforms are supported. Building Apcupsd with USB ~~~~~~~~~~~~~~~~~~~~~~~~~ Some specific packages are necessary when building Apcupsd with USB support on Solaris. You must install the ``SUNWlibusb`` and ``SUNWlibusbugen`` packages **BEFORE** attempting to build Apcupsd. These packages can be found on the Solaris installation CDROMs and should be installed with the ``pkgadd`` utility. You also should build using the gcc compiler and ccs make, not Sun's compiler. The appropriate make utility can be found in ``/usr/ccs/bin``. gcc can be installed from packages included on the Solaris installation CDROMs. Configure and build Apcupsd normally, as described in `Building and Installing Apcupsd`_. Be sure to include the ``--enable-usb`` flag to ``configure``. After building, install Apcupsd as root using '``make install``', then *perform a reconfigure boot* ('``reboot -- -r``'). During installation, Apcupsd will automatically configure your USB subsystem to attach APC USB devices to the ``ugen`` driver. This is a critical step and must be completed by a reconfigure boot. Note that the USB config changes will be reversed if you remove Apcupsd using '``make uninstall``'. Verifying Device Detection and Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After installing Apcupsd as described above and performing a reconfigure boot, plug in your UPS USB cable. You should see a series of dmesg log messages similar to the following: :: Dec 5 17:50:50 sunblade usba: [ID 912658 kern.info] USB 1.10 device (usb51d,2) operating at low speed (USB 1.x) on USB 1.10 root hub: input@4, ugen0 at bus address 3 Dec 5 17:50:50 sunblade usba: [ID 349649 kern.info] American Power Conversion Smart-UPS 1000 FW:600.1.D USB FW:1.2 AS0127232356 Dec 5 17:50:50 sunblade genunix: [ID 936769 kern.info] ugen0 is /pci@1f,0/usb@c,3/input@4 Dec 5 17:50:50 sunblade genunix: [ID 408114 kern.info] /pci@1f,0/usb@c,3/input@4 (ugen0) online Note that the ``ugen`` driver is called out. If you do not see any dmesg entries related to your UPS, ensure that it is turned on and that the USB cable is connected at both ends. Also verify that you installed Apcupsd as root using the '``make install``' command and that you performed a reconfigure boot afterward. Device Nodes ~~~~~~~~~~~~ Apcupsd communicates with the UPS through the USB generic device, ``ugen``. The reconfigure boot performed after Apcupsd installation will ensure the correct device nodes are created. Once your UPS has been recognized in dmesg as shown above, you can check /dev/usb to see if the device nodes have appeared: :: [user@sunblade /]$ ls /dev/usb/51d.2/* cntrl0 cntrl0stat devstat if0in1 if0in1stat (``51d.2`` is the vendor/product id for APC UPSes.) Mac OS X (Darwin) USB Configuration ----------------------------------- Platforms and Versions ~~~~~~~~~~~~~~~~~~~~~~ Apcupsd supports USB UPSes on Mac OS X (Darwin) 10.4.x and higher. Both Intel and PowerPC platforms are supported. Building Apcupsd with USB ~~~~~~~~~~~~~~~~~~~~~~~~~ Some specific packages are necessary when building Apcupsd with USB support on Darwin. You must install libusb-0.1.12 which can be obtained from MacPorts (http://www.macports.org) (formerly DarwinPorts) or Fink (http://fink.sourceforge.net) or downloaded and built by hand (http://www.libusb.org). *You must not use libusb-1.x or higher (apcupsd does not support the new 1.0 APIs) nor any version earlier than 0.1.12 (earlier versions have a bug that apcupsd triggers). Generally that means you must use exactly 0.1.12.* Note that Apcupsd is sensitive to the install location of libusb, so beware if you change it from the default. Apcupsd should be built using gcc, preferably from the XCode development tools. Currently the maintainer is using gcc-4.0.1 from XCode 2.4. Other versions of gcc from other sources may also work. Configure and build Apcupsd normally, as described in `Building and Installing Apcupsd`_. Be sure to include the ``--enable-usb`` flag to ``configure``. After building, install Apcupsd as root using '``make install``' and then reboot. During installation, Apcupsd will automatically install a simple dummy kext driver designed to prevent Apple's monitoring software from taking over the UPS. It is necessary to reboot in order to activate the kext. Note that this kext will be automatically removed if you uninstall Apcupsd using '``make uninstall``', allowing Apple's monitoring tool to once again access the UPS. Verifying Device Detection and Driver ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After installing Apcupsd as described above and rebooting, plug in your UPS USB cable. You should notice that Darwin does **NOT** display the battery monitor tool in the menu bar. You can also check Apple Menu -> About This Mac -> More Info... -> USB to ensure that your UPS appears in the list of USB devices. Building and Installing apcupsd =============================== In general it is recommended to obtain a prebuilt binary package for your platform. Given how apcupsd must integrate into the shutdown mechanism of the operating system and the rate at which such mechanisms are changed by vendors, the platform ports in the apcupsd tree may become out of date. In some cases, binary packages are provided by the apcupsd team (RedHat, Mandriva, SuSE, Windows, Mac OS X). For other platforms it is recommended to check your vendor's package repository and third party repositories for recent binary packages before resorting to building apcupsd from scratch. Note that some vendors continue to distribute *ancient* versions of apcupsd with known defects. These packages should **not** be used. Installation from Binary Packages --------------------------------- RPMS ~~~~ For systems based on RPM packages, such as Red Hat and SuSE, apcupsd is available in binary RPM format. This is the simplest way to install. If you have no previous version of apcupsd on your machine and are creating a standalone configuration, simply install the RPM with a normal '``rpm -ihv``' command. You're done, and can now skip the rest of this chapter and go straight to tweaking your run-time configuration file. (see `After Installation`_) If you have a previous installation, you can upgrade with a normal '``rpm -Uhv``', but this may not upgrade the halt script. It may be better to do the upgrade as a remove '``rpm -e``' followed by a fresh install '``rpm -ihv``'. After installation of the binary RPM, please verify carefully that /etc/rc.d/init.d/halt was properly updated and contains new script lines flagged with ``***APCUPSD***``. Since there is no standard location for cgi-bin, the rpm will place the binary CGI programs in the directory /etc/apcupsd/cgi. To actually use them, you must copy or move them to your actual cgi-bin directory, which on many systems is located in /home/httpd/cgi-bin. Microsoft Windows ~~~~~~~~~~~~~~~~~ The Windows version of apcupsd is distributed as a simple double-click installer. Installation is very simple and straight-forward: Simply double-click the installer executable and follow the instructions. See `The Windows Version of apcupsd`_ for further details. Installation from Source ------------------------ Installation from source might have to be be done different ways depending on what system you are running. The basic procedure involves getting a source distribution, running the configuration, rebuilding, and installing. For building the system, we suggest that you run the configure and make processes as your normal UNIX user ID. The '``make install``' must be run as root. But if your normal ID has an environment setup for using the C compiler, it's simpler to do that than to set up root to have the correct environment. apcupsd requires ``gcc`` and ``g++`` compilers as well as GNU ``make``. Other compilers or BSD ``make`` will **not** work. GNU make is sometimes installed as ``gmake``. The configure script will check for this and will inform you of what command to use to invoke GNU make. The basic installation from a tar source file is rather simple: #. Unpack the source code from its tar archive. #. Go into the directory containing the source code. #. Run '``./configure``' (with appropriate options as described below) #. '``make``' or '``gmake``'' as instructed by configure #. '``su``' (i.e. become root) #. Stop any running instance of apcupsd. The command to do this will look like '``system-dependent-path/apcupsd stop``' #. uninstall any old apcupsd This is important since the default install locations may have changed. #. '``make install``' or '``gmake install``' #. edit your /etc/apcupsd/apcupsd.conf file if necessary #. ensure that your halt script is properly updated #. Start the new apcupsd with: '``system-dependent-path/apcupsd start``' If all goes well, the '``./configure``' will correctly determine which operating system you are running and configure the source code appropriately. ``configure`` currently recognizes the systems listed below in the `Operating System Specifics`_ section of this chapter and adapts the configuration appropriately. Check that the configuration report printed at the end of the ``configure`` process corresponds to your choice of directories, options, and that it has correctly detected your operating system. If not, redo the ``configure`` with the appropriate options until your configuration is correct. Please note that a number of the ``configure`` options preset apcupsd.conf directive values in an attempt to automatically adapt apcupsd as best possible to your system. You can change the values in apcupsd.conf at a later time without redoing the configuration process by simply editing the apcupsd.conf file. Other configuration options can be used to set up the installation of HTML documentation and optional modules, notably the CGI interface that enables the UPS state to be queried via the Web. You will find a complete reference later in this chapter. In general, you will probably want to supply a more elaborate ``configure`` statement to ensure that the modules you want are built and that everything is placed into the correct directories. On Red Hat, a fairly typical configuration command would look like the following: :: CFLAGS="-g -O2" LDFLAGS="-g" ./configure \ --enable-usb \ --with-upstype=usb \ --with-upscable=usb \ --prefix=/usr \ --sbindir=/sbin \ --with-cgi-bin=/var/www/cgi-bin \ --enable-cgi \ --with-log-dir=/etc/apcupsd By default, '``make install``' will install the executable files in /sbin, the manuals in /usr/man, and the configuration and script files in /etc/apcupsd. In addition, if your system is recognized, certain files such as the startup script and the system halt script will be placed in appropriate system directories (usually subdirectories of /etc/rc.d). Verifying a Source Installation ------------------------------- There are a number of things that you can do to check if the installation (make install) went well. The fist is to check where the system has installed apcupsd using '``which``' and '``whereis``'. On my Red Hat system, you should get the following (lines preceded with a $ indicate what you type): :: $ which apcupsd /sbin/apcupsd $ whereis apcupsd apcupsd: /sbin/apcupsd /etc/apcupsd /etc/apcupsd.conf /etc/apcupsd.status /usr/man/man8/apcupsd.8.gz /usr/man/man8/apcupsd.8 If you find an apcupsd in /usr/sbin, /usr/local/sbin, /usr/lib, or another such directory, it is probably a piece of an old version of apcupsd that you can delete. If you are in doubt, delete it, then rerun the '``make install``' to ensure that you haven't deleted anything needed by the new apcupsd. Please note that the files specified above assume the default installation locations. As a final check that the '``make install``' went well, you should check your halt script (in /etc/rc.d on SUSE systems, and in /etc/rc.d/init.d on Red Hat systems) to see that the appropriate lines have been inserted in the correct place. Modification of the halt script is important so that at the end of the shutdown procedure, apcupsd will be called again to command the UPS to turn off the power. This should only be done in a power failure situation as indicated by the presence of the /etc/powerfail file, and is necessary if you want your machine to automatically be restarted when the power returns. On a Red Hat system, the lines containing the ``# ***apcupsd***`` should be inserted just before the final halt command: :: # Remount read only anything that's left mounted. #echo "Remounting remaining filesystems (if any) readonly" mount | awk '/ext2/ { print $3 }' | while read line; do mount -n -o ro,remount $line done # See if this is a powerfail situation. # ***apcupsd*** if [ -f /etc/apcupsd/powerfail ]; then # ***apcupsd*** echo # ***apcupsd*** echo "APCUPSD will now power off the UPS" # ***apcupsd*** echo # ***apcupsd*** /etc/apcupsd/apccontrol killpower # ***apcupsd*** echo # ***apcupsd*** echo "Please ensure that the UPS has powered off before rebooting" # ***apcupsd*** echo "Otherwise, the UPS may cut the power during the reboot!!!" # ***apcupsd*** echo # ***apcupsd*** fi # ***apcupsd*** # Now halt or reboot. echo "$message" if [ -f /fastboot ]; then echo "On the next boot fsck will be skipped." elif [ -f /forcefsck ]; then echo "On the next boot fsck will be forced." fi The purpose of modifying the system halt files is so that apcupsd will be recalled after the system is in a stable state. At that point, apcupsd will instruct the UPS to shut off the power. This is necessary if you wish your system to automatically reboot when the mains power is restored. If you prefer to manually reboot your system, you can skip this final system dependent installation step by specifying the ``disable-install-distdir`` option on the '``./configure``' command (see below for more details). The above pertains to Red Hat systems only. There are significant differences in the procedures on each system, as well as the location of the halt script. Also, the information that is inserted in your halt script varies from system to system. Other systems such as Solaris require you the make the changes manually, which has the advantage that you won't have any unpleasant surprises in your halt script should things go wrong. Please consult the specific system dependent README files for more details. Please note that if you install from RPMs for a slave machine, you will need to remove the changes that the RPM install script made (similar to what is noted above) to the halt script. This is because on a slave machine there is no connection to the UPS, so there is no need to attempt to power off the UPS. That will be done by the master. Configure Options ----------------- All the available ``configure`` options can be printed by entering: :: ./configure --help When specifying options for '``./configure``', if in doubt, don't put anything, since normally the configuration process will determine the proper settings for your system. The advantage of these options is that it permits you to customize your version of apcupsd. If you save the '``./configure``' command that you use to create apcupsd, you can quickly reset the same customization in the next version of apcupsd by simply re-using the same command. The following command line options are available for ``configure`` to customize your installation. --prefix=path This defines the directory for the non-executable files such as the manuals. The default is /usr. --sbindir=path This defines the directory for the executable files such as apcupsd. The default is /sbin. You may be tempted to place the executable files in /usr/sbin or /usr/local/sbin. Please use caution here as these directories may be unmounted during a shutdown and thus may prevent the ``halt`` script from calling apcupsd to turn off the UPS power. Though your data will be protected, in this case, your system will probably not be automatically rebooted when the power returns --enable-cgi This enables the building of the CGI programs that permit Web browser access to apcupsd data. This option is not necessary for the proper execution of apcupsd. --with-cgi-bin=path The with-cgi-bin configuration option allows you to define the directory where the CGI programs will be installed. The default is /etc/apcupsd, which is probably not what you want. --enable-apcsmart Turns on generation of the APC Smart driver (default). --enable-dumb Turns on generation of the dumb signalling driver code (default). --enable-usb Turns on generation of the USB driver code. By default this is disabled. --enable-net Turns on generation of the NIS network driver for slaves. For each slave, this is the only driver needed. This driver works by reading the information from the the configured master using the NIS (Network Information Services) interface. --enable-snmp Turns on generation of the SNMP driver. This driver accesses the UPS over the network using SNMP. This is compatible only with UPSes equipped with an SNMP or Web/SNMP management card. By default this is enabled. --enable-pcnet Turns on generation of the PCNET (PowerChute Network Shutdown) driver. This driver accesses the UPS over the network using APC's custom protocol. This driver can be used as an alternative to SNMP for UPSes equipped with a modern Web/SNMP management card. --enable-modbus Turns on generation of the MODBUS/RS232 driver (default) --enable-modbus-usb Turns on generation of the MODBUS/USB driver --enable-test This turns on a test driver that is used only for debugging. By default it is disabled. --enable-gapcmon This option enables building the GTK GUI front-end for apcupsd. Building this package requires numerous GNOME libraries. The default is disabled. --enable-apcagent This option enables building the apcagent menubar application on Mac OS X platforms. The default is disabled. --with-libwrap=path, --with-libwrap This option when enabled causes apcupsd to be built with the TCP WRAPPER library for enhanced security. In most cases, the path is optional since configure will determine where the libraries are on most systems. --with-nologin=path This option allows you to specify where apcupsd will create the nologin file when logins are prohibited. The default is /etc --with-pid-dir=path This option allows you to specify where apcupsd will create the process id (PID) file to prevent multiple copies from running. The default is system dependent but usually /var/run. --with-log-dir=path This option allows you to specify where apcupsd will create the EVENTS and STATUS log files. The default is /etc/apcupsd. This option simply sets the default of the appropriate path in the apcupsd.conf file, which can be changed at any later time. --with-lock-dir=path This option allows you to specify where apcupsd will create the serial port lock file. The default is system-dependent but usually /var/lock. This option simply sets the appropriate path in the apcupsd.conf file, which can be changed at any later time. --with-pwrfail-dir=path This option allows you to specify where apcupsd will create the powerfail file when a power failure occurs. The default is system dependent but usually /etc. --with-serial-dev=device-name This option allows you to specify where apcupsd will look for the serial device that talks to the UPS. The default is system dependent, but often /dev/ttyS0. This option simply sets the appropriate device name in the apcupsd.conf file, which can be changed at any later time. --with-nis-port=port This option allows you to specify what port apcupsd will use for the Network Information Server (the CGI programs). The default is system dependent but usually 3551 because that port has been officially assigned to apcupsd by the IANA. This option simply sets the appropriate port in the apcupsd.conf file, which can be changed at any later time. --with-nisip=ip-address This option allows you to specify the value that will be placed on then NISIP directive in the configuration file. The default is 0.0.0.0. No checking is done on the value entered, so you must ensure that it is a valid IP address. --with-net-port=port This option allows you to specify what port apcupsd will use for Master and Slave communications. The default is system dependent but usually 6666. This option simply sets the appropriate port in the apcupsd.conf file, which can be changed at any later time. --with-upstype=type This option allows you to specify the type of UPS that will be connected to your computer. The default is: smartups. This option simply sets the appropriate UPS type in the apcupsd.conf file, which can be changed at any later time. --with-upscable=cable This option allows you to specify what cable you are using to connect to the UPS. The default is: smart. This option simply sets the appropriate UPS cable in the apcupsd.conf file, which can be changed at any later time. --disable-install-distdir This option modifies the apcupsd Makefiles disable installation of the distribution (platform) directory. Generally, this used to do a full installation of apcupsd except the final modification of the operating system files (normally /etc/rc.d/halt, etc.). This is useful if your operating system is not directly supported by apcupsd or if you want to run two copies of apcupsd on the same system. This option can also be used by those of you who prefer to manually reboot your system after a power failure or who do not want to modify your system halt files. Recommended Options for most Systems ------------------------------------ For most systems, we recommend the following options: :: ./configure --prefix=/usr --sbindir=/sbin --enable-usb and you can optionally build and install the CGI programs as follows: :: ./configure --prefix=/usr --sbindir=/sbin --enable-usb \ --enable-cgi --with-cgi-bin=/home/httpd/cgi-bin Compilers and Options --------------------- Some systems require unusual options for compilation or linking that the '``./configure``' script does not know about. You can specify initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: :: CFLAGS="-O2 -Wall" LDFLAGS= ./configure Or on systems that have the ``env`` program, you can do it like this: :: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Or for example on the Sun Solaris system, you can use: :: setenv CFLAGS -O2 setenv LDFLAGS -O ./configure You can get a listing of all available options by doing: :: ./configure --help or simply see the previous section of this manual. Operating System Specifics -------------------------- With the exception of Linux SUSE and Linux Red Hat systems used by the developers, we rely on users to help create installation scripts and instructions as well as to test that apcupsd runs correctly on their system. As you can imagine, most of these people are system administrators rather than developers so they are very busy and don't always have time to test the latest releases. With that in mind, we believe that you will find that a lot of very valuable work has been already done to make your installation much easier (and probably totally automatic). Below, you will find a list of operating systems for which we have received installation files: - Debian (see `Debian`_) - FreeBSD (see `FreeBSD`_) - HPUX (see `HPUX`_) - NetBSD (see `NetBSD`_) - Mac OS X Darwin (see `Mac OS X Darwin`_) - OpenBSD (see `OpenBSD`_) - Red Hat (see `Red Hat Systems`_) - Slackware (see `Slackware`_) - SUSE (see `SUSE`_) - Solaris (see `Sun Solaris`_) - unknown (see `Unknown System`_) - Win32 (see `Windows Systems`_) Debian ~~~~~~ This port is complete and is being used by several users. Since Debian build and install procedures are somewhat particular, we have put the extra Debian information into the following two subdirectories: ``platforms/debian/examples`` and ``platforms/debian/packageinfo`` You can also find the official Debian packages on the Debian site at: - https://packages.debian.org/stable/apcupsd - https://packages.debian.org/testing/apcupsd - https://packages.debian.org/unstable/apcupsd FreeBSD ~~~~~~~ This port is complete and is being used by several users. You will need to install and use GNU make (aka gmake) instead of the BSD make supplied with the system. On the FreeBSD OS, there is no known way for a user program to get control when all the disks are synced. This is needed for apcupsd to be able to issue the killpower command to the UPS so that the UPS shuts off the power. To accomplish the same thing on FreeBSD systems, make sure you have a SmartUPS and that your UPS shutdown grace period is set sufficiently long so that you system will power down (usually 2 minutes), the use the ``--kill-on-powerfail`` option on the apcupsd command line. HPUX ~~~~ Status of this port is unknown. NetBSD ~~~~~~ You will need to install and use GNU make (aka gmake) instead of the BSD make supplied with the system. Mac OS X Darwin ~~~~~~~~~~~~~~~ On OS X (Darwin), apcupsd can be built with ``configure`` defaults. The USB driver can be enabled, as per the directions on `Mac OS X (Darwin) USB Configuration`_ Apcupsd *may* be usable on OS X with a smart serial device, but certainly *does* work as a NIS client or using a USB interface. The startup information will be installed in ``/Library/StartupItems/apcupsd`` which is part of darwin's SystemStartup. OpenBSD ~~~~~~~ You will need to install and use GNU make (aka gmake) instead of the BSD make supplied with the system. Ensure that you read the distributions/openbsd/README file before running apcupsd. There are some critical differences in how the OpenBSD implementation operates when the UPS batteries are exhausted. Failure to take this into account may result in the system not being fully halted when power is lost. Red Hat Systems ~~~~~~~~~~~~~~~ Red Hat systems are fully supported, and by following the standard installation instructions given above, you should experience few or no problems. Slackware ~~~~~~~~~ Slackware systems are fully supported, and by following the standard installation instructions given above, you should experience few or no problems. SUSE ~~~~ SUSE systems are fully supported, and by following the standard installation instructions given above, you should experience few or no problems. Sun Solaris ~~~~~~~~~~~ Please read this before attempting to compile or install the beta software. It contains important information that will make your efforts easier. Before running '``./configure``', please be sure that you do not have /usr/ucb on your path. This may cause the ``configure`` to choose the wrong shutdown program. If ``configure`` detects that /usr/usb is on your path, it will print a warning message. Please follow the advice to avoid shutdown problems. Your normal UNIX user ID must own the source tree directories, and you must have the normal development tools in your path. This includes make, the compiler, the M4 preprocessor, the linker, and ar or ranlib. If the user you are logged in as can compile and link a C program from a source file, then you have all the required tools available. You will want to install the executables in a directory that remains mounted during the shutdown. Solaris will unmount almost everything except the root directories. Since the ability to power the UPS off requires access to the executable programs, they need to be in a directory that will never be unmounted. And since they should also be in a directory that normal users cannot get into, /sbin is the default. However, please be aware that if you want to follow Sun's filesystem conventions you would use the following: :: ./configure \ --prefix=/opt/apcupsd \ --sbindir=/etc/opt/apcupsd/sbin \ --sysconfdir=/etc/opt/apcupsd \ --with-cgi-bin=/opt/apcupsd/cgi-bin The way to setup the /sbin directory as the executables directory is to pass configure the ``--sbindir=/sbin`` option. No other arguments should be required, and your setup and platform should be detected automatically by configure. Once you have run configure, you will need to do a '``gmake``'. Once the make has completed with no errors, you must su to root to complete the install. After the su, you may not have a path to the make program anymore. In that case, you should do the '``gmake install``' step as: :: gmake install Once the install completes, you must edit the /sbin/rc0 script as detailed below, then exit from the su'ed shell. In order to support unattended operation and shutdown during a power failure, it's important that the UPS remove power after the shutdown completes. This allows the unattended UPS to reboot the system when power returns by re-powering the system. Of course, you need autoboot enabled for your system to do this, but all Solaris systems have this by default. If you have disabled this on your system, please re-enable it. To get the UPS to remove power from the system at the correct time during shutdown, i.e., after the disks have done their final sync, we need to modify a system script. This script is /sbin/rc0. We do not have access to every version of Solaris, but we believe this file will be almost identical on every version. Please let us know if this is not true. At the very end of the /sbin/rc0 script, you should find lines just like the following: :: # unmount file systems. /usr, /var and /var/adm are not unmounted by umountall # because they are mounted by rcS (for single user mode) rather than # mountall. # If this is changed, mountall, umountall and rcS should also change. /sbin/umountall /sbin/umount /var/adm >/dev/null 2>\&1 /sbin/umount /var >/dev/null 2>\&1 /sbin/umount /usr >/dev/null 2>\&1 echo 'The system is down.' We need to insert the following lines just before the last 'echo': :: #see if this is a powerfail situation if [ -f /etc/apcupsd/powerfail ]; then echo echo "APCUPSD will power off the UPS" echo /etc/apcupsd/apccontrol killpower echo echo "Please ensure that the UPS has powered off before rebooting" echo "Otherwise, the UPS may cut the power during the reboot!!!" echo fi We have included these lines in a file called rc0.solaris in the distributions/sun subdirectory of the source tree. You can cut and paste them into the /sbin/rc0 file at the correct place, or yank and put them using vi or any other editor. Note that you must be root to edit this file. You must be absolutely sure you have them in the right place. If your /sbin/rc0 file does not look like the lines shown above, do not modify the file. Instead, email a copy of the file to the maintainers, and we will attempt to figure out what you should do. If you mess up this file, the system will not shut down cleanly, and you could lose data. Don't take the chance. You will then need to make the normal changes to the /etc/apcupsd/apcupsd.conf file. This file contains the configuration settings for the package. It is important that you set the values to match your UPS model and cable type, and the serial port that you have attached the UPS to. People have used both /dev/ttya and /dev/ttyb with no problems. You should be sure that logins are disabled on the port you are going to use, otherwise you will not be able to communicate with the UPS. If you are not sure that logins are disabled for the port, run the 'admintool' program as root, and disable the port. The 'admintool' program is a GUI administration program, and required that you are running CDE, OpenWindows, or another XWindows program such as KDE. Solaris probes the serial ports during boot, and during this process, it toggles some handshaking lines used by dumb UPSes. As a result, particularly for simple signalling "dumb" UPSes it seems to kick it into a mode that makes the UPS think it's either in a calibration run, or some self-test mode. Since at this point we are really not communicating with the UPS, it's pretty hard to tell what happened. But it's easy to prevent this, and you should. Disconnect the UPS, and boot the system. When you get to a login prompt, log in as root. Type the following command: :: eeprom com1-noprobe=true or :: eeprom com2-noprobe=true depending on which com port your UPS is attached to. Then sync and shutdown the system normally, reattach the UPS, and reboot. This should solve the problem. However, we have some reports that recent versions of Solaris (7 & 8) appear to have removed this eeprom option and there seems to be no way to suppress the serial port probing during boot. At this point, you should have a complete installation. The daemon will load automatically at the next boot. Watch for any error messages during boot, and check the event logs in /etc/apcupsd. If everything looks OK, you can try testing the package by removing power from the UPS. NOTE! if you have a voltage-signalling UPS, please run the first power tests with your computer plugged into the wall rather than into the UPS. This is because dumb serial-port UPSes have a tendency to power off if your configuration or cable are not correct. As a user, your input is very helpful in solving problems with the package, and providing suggestions and future directions for the development of the package. We are striving to provide a useful package that works across all platforms, and welcome your feedback. Unknown System ~~~~~~~~~~~~~~ During the '``./configure``', if apcupsd does not find one of the systems for which it has specific installation programs, it will set the Operating System to ``unknown`` and will use the incomplete installation scripts that are in ``platforms/unknown``. You will be on your own, or you can ask the developers list (apcupsd-users@lists.sourceforge.net) for installation instructions. This directory also contains a hint file for Linux From Scratch, which could be helpful for other systems as well. Windows Systems ~~~~~~~~~~~~~~~ Appropriate scripts (actually Windows batch files) are included with the Apcupsd Win32 installer package. After Installation ================== Checking Your Configuration File -------------------------------- Once you have installed apcupsd, either from a binary package or by building from source, your next step should be to inspect your ``/etc/apcupsd/apcupsd.conf`` file to make sure it is valid. You can read the complete reference on configuration directives (`Configuration Directive Reference`_), but if you are setting up a normal standalone configuration you should only need to check (and possibly fix) the first three items listed below. Your ``UPSTYPE`` should be the UPS's protocol type: dumb, apcsmart, usb, net, pcnet, or snmp. Your ``UPSCABLE`` should be the type of cable you are using. ``DEVICE`` should be set to the path of the device node (usually in /dev) to use to communicate with the UPS. This is used primarily for serial port connections. If you have a USB device, it is better not to specify a ``DEVICE`` directive by leaving it black or commenting it out. Apcupsd will automatically search for your device in the standard places. If you specify a ``DEVICE``, it should be the name of the device that apcupsd is to use to communicate with the UPS. If the first time you execute apcupsd, you get a message to the effect that the Apcupsd USB driver is missing, it means that you most likely forgot to put ``--enable-usb`` on your '``./configure``' command line. The `Configuration Examples`_ chapter of this manual provides the essential characteristics of each main type of configuration file. After those elements are correct, apcupsd should run, and then it is only a matter of customization of your setup. Arranging for Reboot on Power-Up -------------------------------- The final consideration for a automatic reboot after a full power down is to ensure that your computer will automatically reboot when the power is restored. This is not the normal behavior of most computers as shipped from the factory. Normally after the power is cut and restored, you must explicitly press a button for the power to actually be turned on. You can test your computer by powering it down; shutting off the power (pull the plug); then plugging the cord back in. If your computer immediately starts up, good. There is nothing more to do. If your computer does not start up, manually turn on the power (by pressing the power on button) and enter your computer's SETUP program (often by pressing DEL during the power up sequence; sometimes by pressing F10). You must then find and change the appropriate configuration parameter to permit instant power on. Normally, this is located under the ``BOOT`` menu item, and will be called something such as ``Restore on AC/Power Loss`` or ``Full-On``. The exact words will vary according to the ROM BIOS provider. Generally you will have three options: ``Last State``, ``Power On``, and ``Power Off``. Although ``Last State`` should normally work, we recommend setting your computers to ``Power On``. This means that whenever the power is applied they are on. The only way to shut them off is to pull the plug or to have a special program that powers them off (/sbin/poweroff on Linux systems). If after making all the changes suggested above, you cannot get your computer to automatically reboot, you might examine your halt script (/etc/rc.d/init.d/halt in the case of Red Hat Linux) and see if the final line that performs the halt or reboot contains the ``-p`` option for powering down the computer. It should not with the logic used by apcupsd, but if it does, the ``-p`` option could cause your computer to power off while the UPS is still suppling power (i.e. before the UPS kills the power). Depending on the setting of your BIOS, it may prevent your computer from restarting when the power returns. As already mentioned, this should not apply, but in case of problems it is worth a try. Making sure apcupsd Is Running ------------------------------ The simplest way to invoke apcupsd is from the command line by entering: :: /sbin/apcupsd To do so, you must be root. However, normally, you will want apcupsd started automatically when your system boots. On some systems with installation support (e.g. SUSE and Red Hat), the installation procedure will create a script file that you will be automatically invoked when your system reboots. On other systems, you will have to invoke apcupsd from your rc.local script. On Red Hat systems, this script file that automatically invokes apcupsd on system start and stops is ``/etc/rc.d/init.d/apcupsd`` To start apcupsd manually (as you will probably do immediately following the installation), enter the following: :: /etc/rc.d/init.d/apcupsd start To understand how this file is automatically invoked at system startup and shutdown, see the man pages for ``chkconfig(8)``. On SUSE systems, the script file that automatically invokes apcupsd on system start and stops is ``/etc/rc.d/apcupsd``. To start apcupsd manually (as you will probably do immediately following the installation), enter the following: :: /etc/rc.d/apcupsd start Normally, when properly installed, apcupsd will be started and stopped automatically by your system. Unfortunately, the details are different for each system. Below, we give the commands for selected systems. Alternatively, there are simple stopapcupsd and startapcupsd scripts in the examples directory, or you can modify one of the scripts in the distributions directory to meet your needs. To stop apcupsd you can do the following: On Red Hat systems: :: /etc/rc.d/init.d/apcupsd stop On SUSE systems: :: /etc/rc.d/apcupsd stop Please see the `Testing Apcupsd`_ chapter for more details on insuring that apcupsd is running properly. Configuration Examples ====================== A Simple USB Configuration -------------------------- If you have a USB UPS, the essential elements of your apcupsd.conf file should look like the following: :: ## apcupsd.conf v1.1 ## UPSCABLE usb UPSTYPE usb DEVICE LOCKFILE /var/lock UPSCLASS standalone UPSMODE disable Notice that we have not specified a device. In doing so, apcupsd will try all the well known USB ports. We strongly recommend you use this (empty device address) form unless you have a good reason to do otherwise. Please use the explicit specifications of a device only if you know exactly what you are doing. In general, it is much easier to let apcupsd find the device itself. Please see `USB Configuration`_ for detailed help on setting up your system to work with a USB UPS. A Simple Configuration for a Serial SmartUPS -------------------------------------------- If you have a Smart UPS using the serial cable supplied by APC, or you build a CUSTOM SMART cable outlined in the cables chapter, a very simple configuration file would look like the following: :: ## apcupsd.conf v1.1 ## UPSCABLE smart UPSTYPE apcsmart DEVICE /dev/ttyS0 LOCKFILE /var/lock UPSCLASS standalone UPSMODE disable Normally you would have many more configuration directives to completely customize your installation, but this example shows you the minimum required. A Simple Configuration for a Simple Signaling or Dumb ----------------------------------------------------- If you have a simple signaling or dumb UPS such as a BackUPS, you will need to know exactly what cable you have and specify it on the UPSCABLE directive. Please see the list of UPSes versus cables in the beginning of this document for more information. The cable number is normally stamped in the plastic at one end of the cable. If you specify the wrong cable, it is very likely that at the first power failure, your computer will be immediately shutdown. This is an unfortunate consequence of the dumb signaling mode. To avoid this, first replace /etc/apcupsd/apccontrol with safe.apccontrol found in the examples directory, then test until everything works correctly. Once you have the correct cable, be sure to remember to reinstall the correct apccontrol file and test that your computer is correctly shutdown during a power failure. :: ## apcupsd.conf v1.1 ## UPSCABLE (number of cable you have) UPSTYPE dumb DEVICE /dev/ttyS0 LOCKFILE /var/lock UPSCLASS standalone UPSMODE disable If your cable does not have low battery detection, as is the case with some older models, you will also need to define ``TIMEOUT nnn`` where you set ``nn`` to be the number of seconds on a power failure after which a shutdown is effected. Normally you would have many more configuration directives to completely customize your installation, but this example shows you the minimum required. NIS Server/Client Configuration Using the Net Driver ---------------------------------------------------- NIS (Network Information Server) mode allows for communication between instances of apcupsd running on different hosts. Only one of those hosts, the server, needs to talk to the UPS directly. The others, clients, obtain information about the state of the UPS by querying the server. NIS is *not* related to Sun's NIS/YP services. NIS clients and servers require that apcupsd be compiled with the Net Driver ``--enable-net``. This is typically enabled by default. The NIS server is connected to the UPS and should be configured exactly as a standalone configuration, but with ``NETSERVER on``. In all other respects, the server should be configured in standalone mode. You may also set the NIS server specific options ``NISIP`` to restrict which IP address of the server which apcupsd listens on. The default, 0.0.0.0, means to list on all of the server host's IP addresses; ``NISPORT`` (default 3551) to set which TCP port the server listens on; and ``EVENTSFILE`` and ``EVENTSFILEMAX`` to provide information about the last few events to clients. You may also need to modify your firewall rules on the server's host to allow traffic to the ``NISPORT``. For the NIS client computer, you will have a configuration that looks something like what follows. What is important is that you get the information from an ``UPSCABLE ether`` with ``UPSTYPE net`` over the network and you must specify the address of a NIS server using ``DEVICE``. The client apcupsd will then poll the NIS server specified in ``DEVICE`` every ``POLLTIME`` seconds (formerly ``NETTIME``). :: ## apcupsd.conf v1.1 ## UPSCABLE ether UPSTYPE net LOCKFILE /var/lock DEVICE server-network-address:3551 UPSCLASS standalone UPSMODE disable POLLTIME 10 The ``DEVICE`` is set to ``server-address:port``, where ``server-address`` is the fully qualified domain name or IP address of the apcupsd NIS server, and ``port`` is the ``NISPORT`` that the server is listening on. The default is 3551, but older versions of apcupsd used port 7000. If you set ``POLLTIME`` too large, your client may not see the change in state of the NIS server before the server has shutdown. Normally, you have at least 30 seconds of grace time between the time the NIS server decides to shutdown and the time it no longer responds. Your slave must poll during this interval. Any client run using the Net driver will shutdown when its own timers expire or when the NIS server shuts down, whichever occurs first. This means that if you want the slave to shutdown before the server, you need only set ``BATTERYLEVEL``, ``MINUTES`` or ``TIMEOUT`` on the client for a faster shutdown than the values defined on the NIS server. This can often be useful if the slave is less important than the master and you wish to reduce battery power consumption so that the master can remain up longer during a power outage. NIS clients work principally by reading the STATFLAG record that is sent by the NIS server (present in the output of apcaccess). The low 16 bits are the standard APC status flag, and the upper 16 bits represent the internal state of apcupsd, so the slave can see when the power fails and know when to shutdown. It would be possible to have a client also work as a server, but that would increase the delay of information getting from the UPS to the secondary client. Differences between NIS Client/Server and the old (now removed) Master/Slave modes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The difference between the NIS mode and the removed master/slave mode is that the NIS server has no explicit knowledge of the slaves. The NIS server makes its information available via the net (NIS), and the NIS slaves read it. When the NIS server is going to shutdown, it makes the information available to any NIS slave that polls it, but the NIS server does not explicitly call each NIS slave as is the case in the Master/Slave networking described several sections above. Think of the difference as push (Master/Slave) vs. pull (NIS-based). In the case of M/S, the master makes all the shutdown decisions and notifies the slaves when they are to shut down or when some other interesting event happens. The slaves just do whatever the master says, whenever the master says to. On the other hand, with the NIS-based network config you basically "publish" the UPS status from one server and then your clients view that status and make their own decisions. PowerChute Network Shutdown Driver (PCNET) ------------------------------------------ As of 3.14, Apcupsd supports the PowerChute Network Shutdown protocol. This is an alternative to SNMP for use with APC's AP9617 family of network smartslot modules. Note that the older AP9606 modules do **not** support PCNET. To enable PCNET support, configure with the ``--enable-pcnet`` flag. This is typically enabled by default. The required apcupsd.conf settings are straightforward: :: ## apcupsd.conf v1.1 ## UPSCABLE ether UPSTYPE pcnet LOCKFILE /var/lock DEVICE ipaddr:user:passphrase UPSCLASS standalone UPSMODE disable The ``DEVICE`` setting specifies the IP address of the UPS as well as the username and authentication passphrase to use. Note that the username and passphrase are **not** the Web/SNMP login credentials. They are separate settings. The default username on a new card is "``apc``" and the default passphrase is "``admin user phrase``". To change the passphrase, log in to the Web UI and go to the UPS tab, then to PowerChute -> Configuration. (This assumes firmware v3.3.1. Other versions may place the setting elsewhere.) *The password must be a minimum of 15 characters long.* The web UI will silently ignore shorter passwords and does not give an error message. There is no apparent way to change the username. Note that you may leave ``DEVICE`` blank and Apcupsd will accept information from any PCNET UPS on the network, **however it will be very insecure since an attacker could easily send packets crafted to cause your server to shut down**. Using the ``ipaddr``, ``user``, and ``passphrase`` will prevent this behavior. You may need to take steps to ensure networking stays active during your OS's shutdown sequence in order for the PCNET driver to power off the UPS (the so-called "killpower" operation). On a Linux distro, you can use commands such as... :: chkconfig --level 0 network on chkconfig --level 0 iptables on ...to make sure networking stays up. MODBUS Driver ------------- MODBUS is APC's replacement for the aging 'apcsmart' (aka UPS-Link) protocol. It is recommended for modern (ex: SMT series) Smart-UPS models. As of 3.14.11, apcupsd supports the MODBUS protocol over RS232 serial interfaces. As of 3.14.13, apcupsd supports the MODBUS protocol over USB. Not all APC UPSes support MODBUS. New 2013 year Smart-UPS models are likely to support it out-of-the-box and firmware updates are available for some older models. APC/Schneider tech support is your best point of contact for determining if a certain model will support MODBUS. That said, APC knowledge base article FA164737 indicates MODBUS support is available for the majority of the SMC, SMT, and SMX model lines. The required apcupsd.conf settings for MODBUS are straightforward. For MODBUS serial RS232: :: ## apcupsd.conf v1.1 ## UPSCABLE smart UPSTYPE modbus DEVICE /dev/ttyS0 LOCKFILE /var/lock UPSCLASS standalone UPSMODE disable The ``DEVICE`` setting identifies the serial port to which the UPS is connected. This can take the form of ``COM1``, etc. on Windows or ``/dev/XXX`` on UNIX systems. You should use the APC-supplied serial cable (P/N 940-0625A) that ships with the UPS. Other 'smart' type cables may work, but only 940-0625A has been formally tested at this time. For MODBUS USB: :: ## apcupsd.conf v1.1 ## UPSCABLE usb UPSTYPE modbus DEVICE LOCKFILE /var/lock UPSCLASS standalone UPSMODE disable The ``DEVICE`` setting can be left blank or, optionally, set to the serial number of the UPS. If ``DEVICE`` is blank, apcupsd will attach to the first APC UPS it finds, otherwise it will attach to the specific UPS identified by the serial number. Note that *most UPSes ship with MODBUS support disabled by default*. You must use the UPS's front panel menu to enable MODBUS protocol support before apcupsd will be able to communicate with the UPS. You may need to enable the "Advanced" menu option before the MODBUS protocol option will be visible. Testing Apcupsd =============== The following testing procedures apply for the most part to SmartUPSes, whether USB or serial. If you have a dumb voltage-signalling UPS, your testing procedures will be somewhat different, and you should see the section on Testing Serial UPSes (see `Testing Serial-Line UPSes`_). Process-Status Test ------------------- After you start apcupsd, execute the following command: :: ps fax or the equivalent for your system. You should see something similar to the following output. :: 632 ? S 0:00 /sbin/apcupsd -f /etc/apcupsd/apcupsd.conf 841 ? S 0:00 \_ /sbin/apcupsd -f /etc/apcupsd/apcupsd.conf 842 ? S 0:00 \_ /sbin/apcupsd -f /etc/apcupsd/apcupsd.conf This indicates that apcupsd is up and running and has started the two standard threads in addition to the main thread. If you see only one instance of apcupsd running, don't worry about it as this is normal on most non-Linux systems, and on Linux 2.6.x kernels. If you do not find that apcupsd is in the above list, the most likely problem is a configuration file glitch. If no messages were printed, you should check your system log (normally ``/var/log/messages``) where you will find one or messages indicating the nature of the problem. Logging Test ------------ Once you have established that the proper processes are running, do a tail of the system log file, normally ``/var/log/messages``: :: tail /var/log/messages You should see output that looks similar to the following: :: Dec 5 17:01:05 matou apcupsd[5917]: apcupsd 3.7.2 startup succeeded These messages should also appear in the temporary file (``/etc/apcupsd/apcupsd.events``) if you are using the default configuration file. If you have installed the RPM, they will probably be in ``/var/log/apcupsd.events``. apcaccess Test -------------- This test consists of running ``apcaccess`` to see if apcupsd is properly updating its internal variables. Please note that you must enable the apcupsd Network Information Server in your configuration file for ``apcaccess`` to work. This is done by setting: :: NETSERVER on NISPORT 3551 in your ``apcupsd.conf`` file. To run the apcaccess test, use the following command: :: apcaccess status Depending on the type of UPS you have, you will get slightly different output, but an example For a Smart-UPS is as follows: :: APC : 001,048,1088 DATE : Fri Dec 03 16:49:24 EST 1999 HOSTNAME : daughter RELEASE : 3.7.2 CABLE : APC Cable 940-0024C MODEL : APC Smart-UPS 600 UPSMODE : Stand Alone UPSNAME : SU600 LINEV : 122.1 Volts MAXLINEV : 123.3 Volts MINLINEV : 122.1 Volts LINEFREQ : 60.0 Hz OUTPUTV : 122.1 Volts LOADPCT : 32.7 Percent Load Capacity BATTV : 26.6 Volts BCHARGE : 095.0 Percent MBATTCHG : 15 Percent TIMELEFT : 19.0 Minutes MINTIMEL : 3 Minutes SENSE : Medium DWAKE : 000 Seconds DSHUTD : 020 Seconds LOTRANS : 106.0 Volts HITRANS : 129.0 Volts RETPCT : 010.0 Percent STATFLAG : 0x08 Status Flag STATUS : ONLINE ITEMP : 34.6 C Internal ALARMDEL : Low Battery LASTXFER : Unacceptable Utility Voltage Change SELFTEST : NO STESTI : 336 DLOWBATT : 05 Minutes DIPSW : 0x00 Dip Switch REG1 : N/A REG2 : N/A REG3 : 0x00 Register 3 MANDATE : 03/30/95 SERIALNO : 13035861 BATTDATE : 05/05/98 NOMOUTV : 115.0 NOMBATTV : 24.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : N/A BADBATTS : N/A FIRMWARE : N/A APCMODEL : 6TD END APC : Fri Dec 03 16:49:25 EST 1999 For a simple signaling or dumb UPS such as BackUPS, your output will be very minimal as follows: :: APC : 001,012,0319 DATE : Mon Feb 18 09:11:50 CST 2002 RELEASE : 3.8.5 UPSNAME : UPS_IDEN CABLE : APC Cable 940-0128A MODEL : BackUPS UPSMODE : Stand Alone STARTTIME: Mon Feb 18 09:11:45 CST 2002 LINEFAIL : OK BATTSTAT : OK STATFLAG : 0x008 Status Flag END APC : Mon Feb 18 09:15:01 CST 2002 If you see the above output, it is a good sign that apcupsd is working. Assuming that the output looks reasonable, check the following variables: ``LINEV`` This is the line voltage and it should be a value that is appropriate for your equipment. In the USA, it is typically about 120 Volts while in Europe, it is about 220 Volts. ``BATTV`` Unless you have additional battery packs, this should be near 24 Volts plus or minus 5 Volts. ``STATUS`` This is the status of the UPS and it should normally be ``ONLINE``. A very disturbing tendance is for some of the newer (Mar 2004) RS and ES UPSes to have no Voltage information. This is an annoying bug, but not serious. On the other hand, some of those UPSes now have no battery charge information ``BCHARGE``. If ``BCHARGE`` is zero in your listing and you are running a Smart or a USB UPS, then you will have to set the ``BATTERYLEVEL`` directive in your apcupsd.conf file to -1. If you see a message to the effect of: :: APCACCESS FATAL ERROR in apcaccess.c at line 336 tcp_open: cannot connect to server localhost on port 3551. It means that you have probably not enabled the Network Information Server in your configuration file for ``apcaccess`` to work. This is done by setting ``NETSERVER`` and ``NISPORT`` in your apcupsd.conf file as shown above. Communications Test ------------------- At this point, you should ensure that apcupsd is handling the connection to the UPS correctly. This test assumes you have a UPS that speaks apcsmart protocol, over either USB or a serial port. If you have an old-style voltage-signaling UPS, please skip to the next section (`Simulated Power Fail Test`_). When apcupsd detects a problem, it generates an EVENT, which consists of sending a message to the system log then invoking the ``apccontrol`` script (normally in /etc/acpupsd/apccontrol) to handle the event. In order to create an event, remove the serial port plug from the back of your computer or from the back of the UPS. Within 6 seconds, apcupsd should detect the lack of serial port communications and broadcast a ``wall`` message indicating that the serial port communications was lost: :: Warning communications lost with UPS lost. At the same time, it sends the same message to the system log and to the temporary EVENTS file (``/etc/apcupsd/apcupsd.events``). Plug the serial port plug back into your computer, and within about 12 seconds, apcupsd should reestablish communications and broadcast and log the following message: :: Communications with UPS restored. If these messages are logged but not broadcast, either you have your ``mesg`` permission set to ``no`` (see '``man wall``' or '``man mesg``'), or there is a problem with apccontrol. If you are running a window manager such as GNOME and don't have a console window open, you may not receive the ``wall`` messages. However, you should find them in your system log file (normally ``/var/log/messages``) and in the temporary EVENTS file, ``/etc/apcupsd/apcupsd.events``. For example, to observe these events in the temporary EVENTS file, you might do a :: tail -f /etc/apcupsd/apcupsd.events Note, if you have installed from the RPM, the proper events file may be ``/var/log/apcupsd.events``. You can find the actual filename by checking your apcupsd.conf file before running the test. If you do not observe these messages, you should correct this problem before proceeding with additional tests. Simulated Power Fail Test ------------------------- At this point, you should verify that in the event of a power fail apcupsd properly calls apccontrol. This test is appropriate for all models of UPSes (smart or dumb). To avoid the possibility that apcupsd might shut down your system, locate where apccontrol resides on your system (normally, /etc/apcupsd/apccontrol. Move this script to another location e.g. apccontrol.save and replace it with the script found in examples/safe.apccontrol. When that is done, ensure that your UPS battery is fully charged and that you have at least 5 minutes of remaining runtime on the batteries. This can be done by examining the values of the ``BATTCHG`` and ``TIMELEFT`` variables in the printout of '``apcaccess status``'. Athough this should not be necessary, as an extra precaution, you can shutdown your machine, remove the plug from the UPS you are testing, and plug your machine into another UPS or directly into the wall. Doing so, will ensure that the UPS doesn't cut the power to your machine at a bad time. Remember at the end of the testing to plug your machine back into the UPS. You can also minimize the risk from an unexpected shutdown by using a journaling filesystem such as Linux's EXT3. All modern disk drives park themselves safely when they power down, rather than ploughing up oxide on your disk's recording surface. Thus, unexpected power less has to hit very narrow timing windows in order to trash an EXT3 transaction. To begin the test, pull the power plug from the UPS. The first time that you do this, psychologically it won't be easy, but after you have pulled the plug a few times, you may even come to enjoy it. If all goes well, apcupsd should detect the power failure and print several warning messages. The first should appear after 5 to 6 seconds and read: :: Warning power loss detected. Then generally 6 seconds later, apcupsd is sure that it isn't a transient effect, so it sends: :: Power failure. Running on UPS batteries. After a few more seconds (total around 15 seconds), plug the power cord back in and ensure that apcupsd is aware that the power has returned. It should print: :: Power has returned... If you do not observe the above messages, please correct the situation before proceeding. The most likely cause of problems are: - apcupsd doesn't recognize the power failure because the configuration directives are not correct. E.g. wrong cable. - The file ``/etc/apcupsd/apccontrol`` doesn't exist or is not marked as executable. System Shutdown Test -------------------- This is an intermediate test that you can do, for all UPS models before doing the Full Power Down Test. First modify the ``/etc/apcupsd/apccontrol`` file so that in the ``killpower`` case, the line that re-executes apcupsd with the ``--killpower`` option is commented out. The original line probably looks something like: :: ${APCUPSD} --killpower when it is commented out, it looks like: :: #${APCUPSD} --killpower Now when you pull the power plug, and either the timer expires or the batteries are exhausted (see the next section for more details), the system should be fully shutdown. After performing this test, please be sure to restore ``/etc/apcupsd/apccontrol`` to its previous state. Full Power Down Test -------------------- To complete the testing, you should do a power fail shutdown of your system. This test is applicable to all UPS models. Please do a backup of your system or take other precautions before attempting this to avoid the possibility of lost data due to a problem (I have been through this at least 10 times and never once had problems, but we all know that someday something will go wrong). Before proceeding, please ensure that your halt script or the equivalent has been properly updated by the install process to contain the logic to call ``apcupsd --killpower`` or ``apccontrol killpower`` when it detects a power failure situation (the presence of a /etc/powerfail file). See the `Building and Installing apcupsd`_ section of this manual, or the README files for additional details about the halt modifications necessary. When you are ready to do the test, either simply pull the plug and wait for the batteries to become exhausted, or set the ``TIMEOUT`` configuration directive to something like 60 so that the system will shutdown before the batteries are exhausted. We recommend doing the full shutdown without using ``TIMEOUT`` to correctly simulate a real power failure, but the choice is yours (I did it once here, but now use ``TIMEOUT 30``). If all goes well, your system should be shutdown before the batteries are completely exhausted and the UPS should be powered off by apcupsd. Please be aware that if you do the full power down, you must ensure that your UPS is totally powered off. Otherwise, it may have been given the command to power off, but due to a long grace period it is still waiting. If you were to reboot your computer during the grace period, the UPS could then suddenly turn off the power (this happened to me). To avoid this problem, always wait for your UPS to power itself off, or power if off manually before restarting your computer. On my system, the UPS is configured as at the factory to have a 180 second grace period before shutting off the power. During this type of testing, 180 seconds *seems* like an eternity, so please take care to either wait or manually power off your UPS. To determine what grace period is programmed into your UPS EEPROM, run '``apcaccess eprom``' and look at the "Shutdown grace delay". If you experienced so problems with the above testing procedures, or if you are porting apcupsd to another system, or you are simply curious, you may want to know exactly what is going on during the shutdown process. If so, please see the `Shutdown Sequence`_ section of this manual. apctest ------- ``apctest`` is a program that allows you to talk directly to your UPS and run certain low-level tests, adjust various settings such as the battery installation date and alarm behavior, and perform a battery runtime calibration. Here we describe how to use it for a SmartUPS utilizing the apcsmart driver and RS232 serial connection. The menus and options for USB, MODBUS, and simple signaling UPSes are different but mostly self-explanatory. *Shutdown apcupsd if it is running.* This is important. Only one program can communicate with the UPS at a time and if apcupsd is running, apctest will fail to contact the UPS. Run apctest by invoking it with no arguments. It will read your installed apcupsd.conf configuration (so it knows where to find the UPS) and then it will present you with the following output: :: 2003-07-07 11:19:21 apctest 3.10.6 (07 July 2003) redhat Checking configuration ... Attached to driver: apcsmart sharenet.type = DISABLE cable.type = CUSTOM_SMART You are using a SMART cable type, so I'm entering SMART test mode mode.type = SMART Setting up serial port ... Creating serial port lock file ... Hello, this is the apcupsd Cable Test program. This part of apctest is for testing Smart UPSes. Please select the function you want to perform. 1) Query the UPS for all known values 2) Perform a Battery Runtime Calibration 3) Abort Battery Calibration 4) Monitor Battery Calibration progress 5) Program EEPROM 6) Enter TTY mode communicating with UPS 7) Quit Select function number: 1 Item 1 will probe the UPS for all values known to apcupsd and present them in rather raw format. This output can be useful for providing technical support if you are having problems with your UPS. Item 2 will perform a Battery Runtime Calibration. This test will only be performed if your battery is 100% charged. Running the test will cause the batteries to be discharged to approximately 30% of capacity. The exact number depends on the UPS model. In any case, apctest will abort the test if it detects that the battery charge is 20% or less. The advantage of doing this test is that the UPS will be able to recalibrate the remaining runtime counter that it maintains in its firmware. As your batteries age, they tend to hold less of a charge, so the runtime calibration may not be accurate after several years. We recommend that perform a Battery Calibration about once a year. You should not perform this calibration too often since discharging the batteries tends to shorten their lifespan. Item 3 can be used to abort a Battery Calibration in progress, if you some how became disconnected. Item 4 can be used to restart the monitoring of a Battery Calibration if you should some how become disconnected during the test. Item 5 is used to program the EEPROM. Please see the `Configuration Directives Used to Set the UPS EEPROM`_ chapter of this manual for the details. Item 6 will initiate a direct communication between your terminal and the UPS, at which point you can enter raw UPS commands. Please be aware that you should be careful what commands you enter because you can cause your UPS to suddenly shutdown, or you can modify the EEPROM in a way to disable your UPS. The details of the raw Smart mode UPS commands can be found in the `APC Smart Protocol`_ chapter of this manual. Item 7 will terminate apctest. Monitoring and Tuning your UPS ============================== After you have verified that your UPS is working correctly, you will probably want to query the state of its health occasionally. The tools apcupsd gives you to do this include one command-line utility (apcaccess) and a GUI you can use through a Web browser. You can also use apctest to tune some parameters of the UPS itself. apcaccess --------- ``apcaccess`` is a program (normally found in ``/sbin/apcaccess``) that permits you to print out the complete status of your UPS. apcaccess will use the Network Information Server to obtain the necessary information. You can specify a second optional argument to apcaccess in the form of ``host:port`` where the ``:port`` is optional. The default is ``localhost:3551``. Please note that in versions prior to 3.10.6, the default NIS port was 7000, so if you are mixing versions, you will need to take a lot of care to ensure that all components are using the same port. To enable the apcupsd Network Information Server, which is normally the default, you set: :: NETSERVER on NISPORT 3551 in your ``apcupsd.conf`` file. The full form of the apcaccess command is: :: apcaccess status localhost:3551 where only apcaccess status should normally be needed. localhost may be replaced by any machine name, fully qualified domain name, or IP address, which means that apcaccess can access any UPS on the network running the Network Information Server. The ``status`` command line option of apcaccess will produce a full printout of all the STATUS variables used by apcupsd. This can be very helpful for checking the condition of your UPS and to know whether or not apcupsd is properly connected to it. Please note that if you invoke apcaccess within the first 30 seconds of launching apcupsd, you will likely get an error message such as: :: APCACCESS FATAL ERROR in apcaccess.c at line 336 tcp_open: cannot connect to server localhost on port 3551. This is because apcupsd is still in the process of initializing the UPS. The solution is to wait at least 30 seconds after starting apcupsd before launching apcaccess. For a SmartUPS 1000 apcaccess will emit the following output: :: DATE : Fri Dec 03 12:34:26 CET 1999 HOSTNAME : matou RELEASE : 3.7.0-beta-1 CABLE : Custom Cable Smart MODEL : SMART-UPS 1000 UPSMODE : Stand Alone UPSNAME : UPS_IDEN LINEV : 232.7 Volts MAXLINEV : 236.6 Volts MINLINEV : 231.4 Volts LINEFREQ : 50.0 Hz OUTPUTV : 232.7 Volts LOADPCT : 11.4 Percent Load Capacity BATTV : 27.7 Volts BCHARGE : 100.0 Percent MBATTCHG : 5 Percent TIMELEFT : 112.0 Minutes MINTIMEL : 3 Minutes SENSE : Low DWAKE : 060 Seconds DSHUTD : 180 Seconds LOTRANS : 204.0 Volts HITRANS : 253.0 Volts RETPCT : 050.0 Percent STATFLAG : 0x08 Status Flag STATUS : ONLINE ITEMP : 29.2 C Internal ALARMDEL : Low Battery LASTXFER : U command or Self Test SELFTEST : NO STESTI : 336 DLOWBATT : 02 Minutes DIPSW : 0x00 Dip Switch REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 01/05/99 SERIALNO : GS9902009459 BATTDATE : 01/05/99 NOMOUTV : 230.0 NOMBATTV : 24.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : 0 BADBATTS : N/A FIRMWARE : 60.11.I APCMODEL : IWI END APC : Fri Dec 03 12:34:33 CET 1999 For the various smaller, cheaper APC USB UPSes, such as the CS, ES, ..., you will get much of the information that is presented above, but not all of it. For example, you will not get ``MAXLINEV``, ``MINLINEV``, ``LINEFREQ``, ... and in particular, the LOADPCT will be zero when you are running on mains. ``LOADPCT`` will display when the UPS is on batteries. You must remember that the non-SmartUPSes are much simpler (and less expensive) and therefore produce less information. Apcupsd Notification and Events ------------------------------- When a major event is generated within apcupsd, control is passed to the script apccontrol normally found in /etc/apcupsd/apccontrol. The event name, and a number of other important parameters are passed to the script. The major function of the apccontrol script is to perform a shutdown of the system (as well as the killpower operation). In addition, another major task for this script is to notify you by email when certain events such as powerfail occur. Since apccontrol is a script, you can customize it to your own needs using any text editor. To do so, you must have a minimal knowledge of Unix shell programming. In addition, another feature is that you can write your own scripts that will be automatically called by apccontrol before any of its own code is executed. Details of the events and how to program them are contained in the Advanced topics section entitled `Customizing Event Handling`_. apcupsd Network Monitoring (CGI) Programs ----------------------------------------- There are four CGI programs (multimon.cgi, upsstats.cgi, upsfstats.cgi, and upsimage.cgi). To have them properly installed, you must run the '``./configure``' command with ``--enable-cgi`` and you should specify an installation directory with ``--with-cgi-bin=`` or load them manually. The default directory for installation of the CGI programs is ``/etc/apcupsd``, which is not really where you want them if you are going to use them. Normally, they should go in the cgi-bin of your Web server. Once built and loaded, they will give you the status of your UPS or UPSes via a web browser. Normally only ``multimon.cgi`` is directly invoked by the user. However, it is possible to directly invoke ``upsstats.cgi`` and ``upsfstats.cgi``. ``upsimage.cgi`` should never be directly invoked as it is used by ``upsstats.cgi`` to produce the bar charts. Setting up and Testing the CGI Programs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Before using multimon and the other CGI programs, first ensure that apcupsd is configured to run the Network Information Server. This is done by setting ``NETSERVER on`` in /etc/apcupsd/apcupsd.conf. This switch is on by default. Next you must edit the hosts file /etc/apcupsd/hosts.conf and at the end, add the name of the hosts you want to monitor and a label string for them. For example: :: MONITOR matou "Server" MONITOR polymatou "Backup server" MONITOR deuter "Disk server" matou, polymatou, and deuter are the network names of the three machines currently running apcupsd. Please note that the network names may either be IP addresses or fully qualified domain names. The network name (or IP address) may optionally be followed by ``:port``, where the port is the NIS port address you wish to use. This is useful if you are running multiple copies of apcupsd on the same system or if you are running in a mixed vendor environment where the NIS port assignments differ. An example could be the following: :: MONITOR matou "Server" MONITOR polymatou "Backup server" MONITOR deuter "Disk server" MONITOR polymatou:7001 "APC USB UPS" where the USB copy of apcupsd has been configured to use port 7001 by modifying apcupsd.conf. Note, the default NIS port is 3551 on most platforms. To test multimon.cgi, you can execute it as non-root directly from the source cgi build directory. To do so, enter at a shell prompt: :: ./multimon.cgi If everything is set up correctly, it will print a bunch of HTML with the values of the machines that you have put in the hosts.conf file. It should look something like the following (note, only a small portion of the output is reproduced here): :: Content-type: text/html Multimon: UPS Status Page \n"; echo "\n"; } }; echo "
... If you do not get similar output, check the permissions of the /etc/apcupsd directory and of those of /etc/apcupsd/hosts.conf to ensure that your web server can access it. At many sites, the Apache server is not running as root, so you must be careful to ensure that that /etc/apcupsd/hosts.conf and /etc/apcupsd/multimon.conf are world readable. To invoke multimon in your Web browser, enter: ``http://your-site/cgi-bin/multimon.cgi`` You should get something similar to the screen shot shown below. If you wish additional control over the colors, type faces, and sizes of the multimon output, you may simply edit the apcupsd.css file to specify the styles you prefer. Using the CGI Programs on Windows ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The CGI programs compiled for Windows are included in the Windows package starting with apcupsd-3.14.7. The CGI programs included with the Windows package are intended to be run on Windows. If your web server is running on Linux or another operating system, you will need to obtain binary packages for that platform (or build them from source) instead. The windows build of the CGI programs has been tested with the Apache web server for Win32. They should also work with MS Internet Information Server (IIS). To use the programs, copy the contents of the ``cgi/`` directory from your apcupsd installation directory to the ``cgi-bin/`` directory of your web server. Consult your web server's documentation for how to enable CGI programs to be executed. Sometimes special security settings are required. Configure the hosts.conf file as described above. The programs expect to find the ``hosts.conf`` file and the ``apcupsd.css`` file in the directory ``\apcupsd\etc\apcupsd`` on the same drive letter as the web server's ``cgi-bin`` directory. If you installed apcupsd into ``C:\apcupsd`` (the default) and your web server's ``cgi-bin/`` directory is also located on the ``C:`` drive, no further changes are necessary. If you installed apcupsd into a different directory or your web server ``cgi-bin`` is on another drive, you will need to relocate ``hosts.conf`` and ``apcupsd.css`` from the apcupsd install location to ``\apcupsd\etc\apcupsd`` on the appropriate drive. multimon.cgi ~~~~~~~~~~~~ This program monitors multiple UPSes at the same time. A typical output of multimon.cgi as displayed in your Web browser might look like the following: .. image:: ./multimon.png :align: center The machines monitored as well as the values and their column headings are all configurable (see /etc/apcupsd/hosts.conf and /etc/apcupsd/multimon.conf) upsstats.cgi ~~~~~~~~~~~~ By clicking on the ``system`` name in the multimon.cgi display, you will invoke upsstats.cgi for the specified system, which will produce a bar graph display of three of the monitored values. For example, .. image:: ./status.png :align: center You can display different bar graphs by selecting different variables from the drop down menus at the top of each of the three bar graphs. As with multimon, if you have your local host configured in the /etc/apcupsd/hosts.conf file, you can execute it from a Unix shell from the source cgi directory as follows: :: ./upsstats.cgi As with multimon, quite a few lines of html should then be displayed. upsfstatus.cgi ~~~~~~~~~~~~~~ If you would like to see all of the STATUS variables available over the network, click on the ``Data`` field of the desired system, and your browser will display something like the following: :: APC : 001,048,1109 DATE : Thu Dec 02 17:27:21 CET 1999 HOSTNAME : matou.sibbald.com RELEASE : 3.7.0-beta-1 CABLE : Custom Cable Smart MODEL : SMART-UPS 1000 UPSMODE : Stand Alone UPSNAME : UPS_IDEN LINEV : 223.6 Volts MAXLINEV : 224.9 Volts MINLINEV : 222.3 Volts LINEFREQ : 50.0 Hz OUTPUTV : 223.6 Volts LOADPCT : 6.2 Percent Load Capacity BATTV : 27.9 Volts BCHARGE : 100.0 Percent MBATTCHG : 5 Percent TIMELEFT : 167.0 Minutes MINTIMEL : 3 Minutes SENSE : High DWAKE : 060 Seconds DSHUTD : 020 Seconds LOTRANS : 196.0 Volts HITRANS : 253.0 Volts RETPCT : 050.0 Percent STATFLAG : 0x08 Status Flag STATUS : ONLINE ITEMP : 35.1 C Internal ALARMDEL : Low Battery LASTXFER : U command or Self Test SELFTEST : NO STESTI : 336 DLOWBATT : 02 Minutes DIPSW : 0x00 Dip Switch REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 01/11/99 SERIALNO : GS9903001147 BATTDATE : 01/11/99 NOMOUTV : 230.0 NOMBATTV : 24.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : 0 BADBATTS : N/A FIRMWARE : 60.11.I APCMODEL : IWI END APC : Thu Dec 02 17:27:25 CET 1999 You should get pretty much the same output mixed in with html if you execute upsfstats.cgi directly from a Unix shell in the cgi subdirectory as explained above for upsstats.cgi and multimon.cgi. A Tip from Carl Erhorn for Sun Systems: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It is possible to run the CGI code to monitor your UPS using the answerbook HTTP server that runs on Solaris. As long as your server has the Answerbook2 web server installed and running, you can insert the cgi scripts into the cgi directory of the web server, and access the cgi using something like: ``http://hostname:8888/cgi/multimon.cgi`` CGI Credits ~~~~~~~~~~~ Many thanks go to Russell Kroll rkroll@exploits.org who wrote the CGI programs to work with his UPS Monitoring system named Network UPS Tools (NUT). Thanks also to Jonathan Benson jbenson@technologist.com for initially adapting the upsstatus.cgi program to work with apcupsd. We have enhanced the bar graph program and hope that our changes can be useful to the original author in his project. Security Issues: ---------------- - ``apcupsd`` runs as root. - If you have ``NETSERVER ON`` in your apcupsd.conf file (which is the default), be aware that anyone on the network can read the status of your UPS. This may or may not pose a problem. If you don't consider this information privileged, as is the case for many, there is little risk. In addition, if you have a perimeter firewall or NATting router with typical settings only users on your local network access to your UPS information. You may also restrict access using using firewall settings (see below) or TCP Wrappers (see below). Firewall Settings ~~~~~~~~~~~~~~~~~ If you are running apcupsd as an NIS server, you will need to ensure that the clients can reach it by opening up ``NISPORT`` (default: TCP 3551) on any firewall running on the server. You may wish to configure your firewall(s) to *only* allow connections from your local network or specifically from the masters, slaves, and servers as needed. TCP Wrappers ~~~~~~~~~~~~ If your operating system does not support a host based firewall (a firewall running on the local machine) then you may try to get some of the functionality of such a firewall with TCP Wrappers. As of apcupsd version 3.8.2, TCP Wrappers are implemented if you turn them on when configuring ``./configure --with-libwrap``. With this code enabled, you may control who may access your apcupsd via TCP connections (the Network Information Server). This control is done by modifying the file: /etc/hosts.allow. This code is implemented but untested. If you use it, please send us some feedback. Configuring Your EEPROM ----------------------- If you have a SmartUPS, there are depending on the UPS at least 12 different values stored in the EEPROM that determine how the UPS reacts to various conditions such as high line voltage, low line voltage, power down grace periods, etc. In general, for the moment, we do not recommend that you change your EEPROM values unless absolutely necessary. There have been several reported cases of problems setting the Low Transfer Voltage. Consequently, if at all possible, do not attempt to change this value. Using apctest to Configure Your EEPROM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ *To make the EEPROM changes with apctest you must first stop the apcupsd daemon.* After apcupsd is stopped you may invoke apctest (as root). We recommend that you change the EEPROM as little as is absolutely necessary since it is a somewhat delicate process that has occasionally produced problems (i.e. improper EEPROM values are displayed after the update). apctest will present a menu of options which are generally self-explanatory. Note that USB connections will show a difference set of options than smart serial connections. .. include:: maintaining_ups.rst Frequently-Asked Questions ========================== See the bugs section of this document for a list of known bugs and solutions. :Question: Why all the craziness with custom serial cables? :Answer: It was nothing more nor less than a form of customer control. For a long time APC wanted to keep other people from talking to its UPSes so it could lock out potential competition for its PowerChute software. Scrambling the leads on its serial cables was a cheap way to accomplish this -- in fact, they tended to be wired so that if you tried a straight-through cable, opening a serial link to the UPS would be interpreted as a shutdown command! (Hardware companies often think like this -- they lock up interfaces by instinct, cornering a small market rather than growing a bigger one. It's fundamentally stupid and self-defeating, but it's the kind of stupid that tends to sound good at an executive meeting.) :Question: What UPS brands does apcupsd support? :Answer: Currently apcupsd supports only APC UPSes. However, some companies such as Hewlett Packard put their own brand name on APC manufactured UPSes. Thus even if you do not have an APC branded UPS, it may work with apcupsd. You will need to know the corresponding APC model number. apcupsd supports all the popular APC models. See the installation and configurations sections of this document for more details. :Question: Does apcupsd support Windows? :Answer: Yes. :Question: I don't have a cable, which one should I build? :Answer: First you must know if you have an apcsmart UPS or a voltage-signalling UPS. If you have a apcsmart UPS, we recommend building a Custom Smart cable. (see `Smart-Custom Cable for SmartUPSes`_) If you have a voltage-signaling UPS, we recommend that you build a Custom Simple cable. (see `Simple-Custom Voltage-Signalling Cable for "dumb" UPSes`_) :Question: How much CPU resources does apcupsd use? :Answer: Depending on your CPU speed, you may see more or less of the CPU consumed by apcupsd. On a 400MHz Unix system, the CPU usage should fall well below 0.1%. On slower systems, the percentage will increase proportionally to the decrease in the CPU speed. On a 400Mhz Win98 machine, the CPU usage will be on the order of 0.5-1.0%. This is higher than for Unix systems. However, compared to the 30% CPU usage by APC's PowerChute (the version on the CDROM shipped with my UPS), apcupsd's 0.5-1.0% is very modest. :Question: What language is apcupsd written in? :Answer: It is written in C and C++. :Question: To test apcupsd, I unplugged the UPS to simulate a power outage. After the machine went into the shutdown process I plugged the UPS back into the commercial power source. This caused the shutdown process to hang after the daemon tried to shut-off the ups. Have you run into this problem, and if so do you have a remedy? :Answer: Normally, once the shutdown process has begun, we cannot stop it -- how do you stop a shutdown that has killed off half of the daemons running on your system? Most likely you will be left with an unusable system. In addition, when apcupsd is re-executed in the halt script after the disks are synced, it tries to shut off the UPS power, but the UPS will generally refuse to do so if the AC power is on. Since we cannot be 100% sure whether or not the UPS will shut off the power, we don't attempt to reboot the system if we detect that the power is back as it might then get caught by a delayed power off (at least for Smart UPSes). :Question: After running apcupsd for a while, I get the following error: "Serial communications with UPS lost." What is the problem? :Answer: We use standard Unix serial port read() and write() calls so once a connection is made, we generally have few problems. However, there have been reports that APC's SNMP Management Card can cause serial port problems. If you have such a card, we suggest that you remove it and see if the problem goes away. It is also possible that some other process such as a getty is reading the serial port. :Question: I get the following error: :: Starting apcupsd power management. Mar 20 21:19:40 box apcupsd[297]: apcupsd FATAL ERROR in apcserial.c at line 83. Cannot open UPS tty /dev/cua01: No such file or directory. What is the problem? :Answer: The two most likely causes of your problem are: 1. You have the wrong serial port device name in the apcupsd.conf file. 2. The device name is not defined on your system. Suggestions for proceeding:For the first item, check what your serial port device should be named. You might be able to find the name with an: :: ls /dev Normally there will be hundreds or even thousands of names that print. If that doesn't produce anything useful, you can try step 2. Perhaps your device is not defined. To get more information on your devices try '``man MAKEDEV``' or '``find / -name MAKEDEV``'. It is often located in ``/dev/MAKEDEV``. Looking at the documentation may tell you what the correct name is, or at least allow you to create the device. :Question: How do I ensure that the slaves shutdown before the master? :Answer: Slaves make their shutdown decision independently from the master. Therefore you can use the ``TIMEOUT``, ``MINUTES``, and ``BATTERYLEVEL`` settings in the slaves' apcupsd.conf to configure them to shut down before the master. :Question: How do I ensure that my database server is correctly shutdown? :Answer: You simply add whatever commands are necessary in the appropriate case statements in /etc/apcupsd/apccontrol, which is a standard script file that is called to actually do the shutdown. Alternatively, you can add your own script file that will be called before doing the commands in apccontrol. Your script file must have the same name as the appropriate case statement in apccontrol; it must be executable; and it must be in the same directory as apccontrol. Customizing Event Handling ========================== When apcupsd detects anomalies from your UPS device, it will make some decisions that usually result in one or more calls to the script located in ``/etc/apcupsd/apccontrol``. The ``apccontrol`` file is a shell script that acts on the first argument that apcupsd passes to it. These actions are set up by default to sane behavior for all situations apcupsd is likely to detect from the UPS. However, you can change the apccontrol behavior for every single action. To customize, so create a file with the same name as the action, which is passed as a command line argument. Put your script in the ``/etc/apcupsd`` directory. These events are sent to the system log, optionally sent to the temporary events file (``/etc/apcupsd/apcupsd.events``), and they also generate a call to ``/etc/apcupsd/apccontrol`` which in turn will call any scripts you have placed in the ``/etc/apcupsd`` directory. Normally, ``/etc/apcupsd/apccontrol`` is called only by apcupsd. Consequently, you should not invoke it directly. However, it is important to understand how it functions, and in some cases, you may want to change the messages that it prints using ``wall``. We recommend that you do so by writing your own script to be invoked by ``apccontrol`` rather than by modifying apccontrol directly. This makes it easier for you to upgrade to the next version of apcupsd In other case, you may want to write your own shell scripts that will be invoked by apccontrol. For example, when a power fail occurs, you may want to send an email message to root. To write your own routine for the ``powerout`` action, you create shell script named ``powerout`` and put it in the lib directory (normally /etc/apcupsd). When the ``powerout`` action is invoked by apcupsd, apccontrol will first give control to your script. If you want apccontrol to continue with the default action, simply exit your script with an exit status of zero. If you do not want apccontrol to continue with the default action, your script should exit with the special exit code of 99. However, in this case, please be aware that you must ensure proper shutdown of your machine if necessary. Some sample scripts (onbattery and mainsback) that email power failure messages can be found in /etc/apcupsd after an install or in the platforms/etc directory of the source code. apccontrol Command Line Options ------------------------------- When apcupsd detects an event, it calls the apccontrol script with four arguments as: ``apccontrol`` *event* *ups-name* *connected* *powered* where: *event* is the event that occurred and it may be any one of the values described in the next section. *ups-name* is the name of the UPS as specified in the configuration file (not the name in the EEPROM). *connected* is 1 if apcupsd is connected to the UPS via a serial port (or a USB port). In most configurations, this will be the case. In the case of a Slave machine where apcupsd is not directly connected to the UPS, this value will be 0. *powered* is 1 if the computer on which apcupsd is running is powered by the UPS and 0 if not. At the moment, this value is unimplemented and always 0. The following *event* names are supported: **annoyme** When a shutdown is scheduled, and the time specified on the ANNOYME directive in the apcupsd.conf file expires, this event is generated. *Default:* ``wall`` a message **changeme** When apcupsd detects that the mains are on, but the battery is not functioning correctly, this event is generated. It is repeated every x hours. *Default:* ``wall`` a message **commfailure** This event is generated each time the communications line with the computer is severed. This event is not detected on dumb signaling UPSes. *Default:* ``wall`` a message **commok** After a commfailure event is issued, when the communications to the computer is re-established, this event will be generated. *Default:* ``wall`` a message **doreboot** This event is depreciated and should not be used. *Default:* Shuts down the system using ``shutdown -h`` or similar **doshutdown** When the UPS is running on batteries and one of the limits expires (time, run, load), this event is generated to cause the machine to shutdown. *Default:* Shuts down the system using ``shutdown -h`` or similar **emergency** Called for an emergency system shutdown. (What triggers such a shutdown is unclear...) After completing this event, apcupsd will immediately initiate a ``doshutdown`` event. *Default:* ``wall`` a message **failing** This event is generated when the UPS is running on batteries and the battery power is exhausted. The event following this one will be a shutdown. *Default:* ``wall`` a message **loadlimit** This event is generated when the battery charge is below the low limit specified in the apcupsd.conf file. After completing this event, apcupsd will immediately initiate a ``doshutdown`` event. *Default:* ``wall`` a message **powerout** This event is generated immediately when apcupsd detects that the UPS has switched to batteries. It may be due to a short powerfailure, an automatic selftest of the UPS, or a longer powerfailure. *Default:* ``wall`` a message **onbattery** This event is generated 5 or 6 seconds after an initial powerfailure is detected. It means that apcupsd definitely considers the UPS to be on batteries. The onset of this event can be delayed by the ``ONBATTERYDELAY`` apcupsd.conf configuration directive. *Default:* ``wall`` a message **offbattery** This event is generated when the mains return only if the onbattery event has been generated. *Default:* ``wall`` a message **mainsback** This event is generated when the mains power returns after a powerout condition. The shutdown event may or may not have been generated depending on the parameters you have defined and the length of the power outage. *Default:* nothing **remotedown** This event is generated on a slave machine when it detects either that the master has shutdown, or that a onbattery situation exists and the communications line has been severed. *Default:* ``wall`` a message **runlimit** This event is generated when the ``MINUTES`` value defined in the apcupsd.conf file expires while in a power fail condition. The ``MINUTES`` is the remaining runtime as internally calculated by the UPS and monitored by apcupsd. After completing this event, apcupsd will immediately initiate a ``doshutdown`` event. *Default:* ``wall`` a message **timeout** This event is generated when the ``TIMEOUT`` value defined in the apcupsd.conf file expires while in a power fail condition. It indicates that the total time in a power failure has been exceeded and the machine should be shutdown. After completing this event, apcupsd will immediately initiate a ``doshutdown`` event. *Default:* ``wall`` a message **startselftest** This event is generated when apcupsd detects a self test by the UPS. Normally due to the 6 second onbattery delay default time, self test events are not detected. *Default:* nothing **endselftest** This event is generated when the end of a self test is detected. *Default:* nothing **battdetach** This event is generated when apcupsd detects that the UPS battery has been disconnected. *Default:* nothing **battattach** This event is generated when apcupsd detects that the UPS battery has been reconnected after a battdetach event. *Default:* nothing Controlling Multiple UPSes on one Machine ========================================= *The following discussion does not apply to Windows servers. Apcupsd on Windows is limited to a single instance and cannot support monitoring multiple UPSes.* If you have multiple UPSes in use, you may wish to consolidate the monitoring of all of these UPSes onto a single machine, which we shall call the "UPS server". Generally one of the UPSes is powering the "UPS server" itself (and possibly other machines as well). The remaining UPSes are powering additional machines. Apcupsd can work quite well in this environment by running one instance of apcupsd on the UPS server for each UPS to be controlled. That is, you install a single copy of apcupsd but launch it multiple times using different configuration files and scripts. (Older versions of apcupsd required you to actually compile the daemon multiple times with different ``configure`` options. This is no longer required, as all necessary adjustments can be made in ``apcupsd.conf``.) Additionally, you will run one instance of apcupsd on each of the machines you wish to be shut down. You will configure each of these apcupsd's to use the 'net' driver to read UPS status from the proper instance of apcupsd on the UPS server. See `NIS Server/Client Configuration Using the Net Driver`_ for more information on the 'net' driver and setting up net clients. Multiple UPS Example -------------------- There are many ways one could set up multiple apcupsd instances. Here I will present the way I have used with great success on Red Hat Linux. I have two apcupsd.conf files (this is for a 2 UPS setup, easily expandable to N): :: [adk0212@mail apcupsd]$ ls -l /etc/apcupsd/*.conf -rw-r--r-- 1 root root 11799 Aug 3 08:39 /etc/apcupsd/apcupsd.ups0.conf -rw-r--r-- 1 root root 11822 Aug 25 14:31 /etc/apcupsd/apcupsd.ups1.conf In my case, ups0 is the UPS powering the UPS server running the multiple apcupsd instances, so only ups0 should initiate a shutdown of the local machine. The differences between the confs are minor since both UPSes are USB (although that is not a requirement; mixing cable types works fine too): :: [adk0212@mail apcupsd]$ diff -u apcupsd.ups0.conf apcupsd.ups1.conf --- apcupsd.ups0.conf 2007-08-03 08:39:26.000000000 -0400 +++ apcupsd.ups1.conf 2007-08-25 14:31:17.000000000 -0400 -UPSNAME ups0 +UPSNAME ups1 -DEVICE /dev/ups0 +DEVICE /dev/ups1 -SCRIPTDIR /etc/apcupsd +SCRIPTDIR /etc/apcupsd/null -PWRFAILDIR /etc/apcupsd +PWRFAILDIR /etc/apcupsd/null -NOLOGINDIR /etc +NOLOGINDIR /etc/apcupsd/null -ANNOY 300 +ANNOY 0 -NISPORT 3551 +NISPORT 3552 -EVENTSFILE /var/log/apcupsd.events +EVENTSFILE /var/log/apcupsd.2.events The important difference to note is that ups1 has its ``SCRIPTDIR``, ``PWRFAILDIR``, and ``NOLOGINDIR`` set to a special "null" directory that I have created. This directory contains a copy of the event handling scripts modified to avoid shutting down the local machine. (Details below). Also the UPSes are given different ``EVENTSFILE`` and ``NISPORT`` settings. Plus I disable the "annoy" feature on ups1. Since the state of that UPS does not impact local users, there's no reason to annoy them. I have the following files in the special "null" directory: :: [adk0212@mail apcupsd]$ ls -l /etc/apcupsd/null total 32 -rwxr--r-- 1 root root 4176 Aug 3 08:24 apccontrol -rwxr-xr-x 1 root root 475 Aug 3 08:28 changeme -rwxr-xr-x 1 root root 502 Aug 3 08:28 commfailure -rwxr-xr-x 1 root root 503 Aug 3 08:28 commok -rwxr--r-- 1 root root 8 Aug 3 08:22 doshutdown -rwxr-xr-x 1 root root 470 Aug 3 08:27 offbattery -rwxr-xr-x 1 root root 435 Aug 3 08:27 onbattery The important change here is the addition of a 'doshutdown' script which overrides apccontrol's shutdown action: :: [adk0212@mail null]$ cat /etc/apcupsd/null/doshutdown exit 99 The "exit 99" tells apccontrol to skip its normal processing for that event. apccontrol itself is unchanged; it is a direct copy of the original. The other scripts are also direct copies and have simply been modified to generate status email from NISPORT 3552 instead of 3551. I also have a custom init.d start/stop script to manage multiple instances. The start, stop, and status handlers are modified to iterate over all /etc/apcupsd/apcupsd.*.conf files. This is derived from the standard apcupsd redhat rc script: :: #! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 60 99 # description: apcupsd monitors power and takes action if necessary # if test -f /etc/whitebox-release ; then f=/etc/whitebox-release else f=/etc/redhat-release fi if test `cat $f | grep release |\ cut -f 3 -d ' '`x = "Enterprise"x ; then DISTVER="Enterprise "`cat $f | grep release |\ cut -f 6 -d ' '` else DISTVER=`cat /etc/redhat-release | grep release |\ cut -f 5 -d ' '` fi # Source function library . /etc/rc.d/init.d/functions case "$1" in start) rm -f /etc/apcupsd/powerfail rm -f /etc/nologin for conf in /etc/apcupsd/apcupsd.*.conf ; do inst=`basename $conf` echo -n "Starting UPS monitoring ($inst):" daemon /sbin/apcupsd -f $conf -P /var/run/apcupsd-$inst.pid RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/apcupsd-$inst done ;; stop) for conf in /etc/apcupsd/apcupsd.*.conf ; do inst=`basename $conf` echo -n "Shutting down UPS monitoring ($inst):" killproc -p /var/run/apcupsd-$inst.pid apcupsd echo rm -f /var/run/apcupsd-$inst.pid rm -f /var/lock/subsys/apcupsd-$inst done ;; restart|force-reload) $0 stop sleep 15 $0 start ;; reload) echo "$0: reload not implemented" exit 3 ;; status) for conf in /etc/apcupsd/apcupsd.*.conf ; do inst=`basename $conf` status -p /var/run/apcupsd-$inst.pid apcupsd-$inst RETVAL=$? if [ $RETVAL -eq 0 ] then NISPORT=`grep ^NISPORT < $conf | sed -e "s/NISPORT *\([0-9]\)/\1/"` /sbin/apcaccess status localhost:$NISPORT | egrep "(STATUS)|(UPSNAME)" fi done ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0 That's about all there is to it. There are still some rough edges to clean up, but overall this is a *lot* easier with apcupsd 3.14.x than it used to be. Support for SNMP UPSes ====================== To run apcupsd with a SNMP UPS, you need the following things: - An SNMP UPS, for example a Web/SNMP (AP9716) or PowerNet SNMP (AP9605) card installed into the SmartSlot. Apcupsd also has support for some non-APC SNMP UPSes using RFC1628 or MGE MIBs, however the majority of the information in this section is for APC UPSes. Planning and Setup for SNMP Wiring ---------------------------------- SNMP packet requests are relayed to the UPS from monitoring APCUPSD servers over Ethernet via a switch, hub, or router. Protecting these Ethernet devices with UPS supplied power is necessary to ensure reliable SNMP communication during power failures. Servers may fail to shutdown quietly during power failures if SNMP communication is lost. Planning and Setup for SNMP Configuration ----------------------------------------- To establish communication to the UPS SNMP card installed in the UPS, the SNMP card will need the following: - Assign SNMP card IP Address - Set SNMP card General Parameters - Set SNMP card Shutdown Parameters - Set SNMP card Event Trap Receivers (apcupsd-3.12.0 and later) Assign SNMP Card IP Address ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following instructions come from the APC knowledge base: :: The Network Management Card (AP9617, AP9618, AP9619) must be configured with network settings before it can communicate on the network. Once the cards have been configured with an IP address, Subnet Mask, and Default Gateway the cards can be access, managed, and controlled from other computers on the network. There are two ways to configure the Network Management Card (NMC) with its initial settings: the (windows) Wizard and Address Resolution Protocol (ARP). 1. The wizard in included on the CD that comes with the card. The wizard must run on a Windows operating system. You can configure the card using the wizard over the network via FTP. If using the wizard please note, the un-configured NMC must be on the same subnet as the computer running the wizard. 2. Address resolution protocol (arp) can also be used to configure the NMC. The MAC Address of the NMC is needed for this method of configuration. The MAC address is located on the quality assurance slip that is shipped with the NMC, and is also located on the white sticker on the NMC itself. From a computer on the same subnet as the un-configured NMC, follow the instructions: Open up a command prompt and type the following (replacing and with the actual values): arp -s Next, use Ping with a size of 113 bytes to assign the IP address defined by the ARP command. - Linux command format: ping -s 113 - Windows command format: ping -l 113 Set SNMP card General Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ After the SNMP Network Management Card is configured with an IP address, the SNMP Card is ready for general configuration. This is accomplished by telneting to the SNMP Card. :: ~$ telnet Login using "apc" for both the username and password and the following menu will display: :: ******************************************************************************* American Power Conversion Network Management Card AOS v2.6.4 (c) Copyright 2004 All Rights Reserved Smart-UPS & Matrix-UPS APP v2.6.1 ------------------------------------------------------------------------------- Name : Date : 07/03/2006 Contact : Time : 04:43:33 Location : User : Administrator Up Time : 0 Days 01 Hours 57 Minutes Stat : P+ N+ A+ Smart-UPS 1000 named : On Line, No Alarms Present ------- Control Console ------------------------------------------------------- 1- Device Manager 2- Network 3- System 4- Logout - Main Menu, - Refresh, - Event Log > ******************************************************************************* Select **Option 2** for Network. Next select **Option 1** for TCP/IP settings. At this point the following settings will be to be specified: - Verify System IP: - Specify Subnet Mask: i.e. "225.225.225.0" - Specify Default Gateway - Specify Host Name - Specify Domain Name Specifying these parameters will complete the General Parameters setup. Additionally the SNMP Network Management Card can now be connected to from a web browser for monitoring and additional configuration. Set SNMP card Shutdown Parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There are two shutdown parameters that must be set in the SNMP card to ensure that connected servers shutdown quietly. These parameters can be set via the telnet terminal or the web browser interface. - Shutdown Delay (sec) - Return Battery Capacity (%) One of the draw-backs of SNMP communication to the UPS is that the Stand-alone or Primary server must issue the power down command to the UPS early in server halt procedure. This server must issue an early command to the SNMP UPS to power down before its ethernet service is halted. This creates a potential problem where the UPS may kill power to any connected servers before these affected servers' halt scripts complete a successful shutdown. The SNMP **Shutdown Delay** parameter is used to delay the UPS from killing power to its load by a prescribed period of seconds. The delay should be long enough to ensure that the Stand-alone or Primary server has enough time to successfully halt. The prescribed time should at least be 180 seconds. Any additional computers connected to the SNMP UPS must not be configured to issue the command to initiate UPS power down. These servers can be thought of as secondary stand-alone server. The APCUPSD daemons of secondary servers should be configured to initiate server halt a prescribed period of time before the Primary server issues the UPS power down command. The **Return on Battery Capacity** is useful during intermittent sequential power failures. This parameter insures that the UPS will not restore power to its loads until it has recharged it battery to a prescribed percentage. This parameter should be set to a value greater than value that the APCUPSD daemons configured "BATTERYLEVEL" shutdown of any connected servers. This will ensure that when the UPS restores power, any additional power failures will successfully re-trigger a server shutdown. Configure Event Trap Receivers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (Requires apcupsd-3.12.0 and later) By default, APCUPSD will poll the SNMP UPS card once per minute. In this case, server notification of UPS alarms could potentially be delayed one minute. Event trap catching mitigates this shortcoming. Any UPS alarms are instantly sent to prescribe servers connected SNMP UPS. These servers are referred to as Event Trap Receivers. The SNMP UPS card can be configure to send event traps to a maximum of four receivers that will "catch" these events. Event trap receivers IP address can be set using a telnet terminal or web browser interface. Also, be aware that servers configured to be Event Trap Receivers should have static IP set. Severs obtaining IPs from DHCP server will not catch instantaneous Events if the IP address changes from the address set in the SNMP UPS. Connecting APCUPSD to a SNMP UPS -------------------------------- The previous sections describe configuration of the actual SNMP card. The remaining sections describe configuration of the APCUPSD to communicate using SNMP Protocol. To enable the SNMP support it is enough to configure the correct device in your apcupsd.conf configuration file. The directive needed for this configuration is: :: DEVICE ::: ...where the directive is made by four parts. All but the first may be omitted completely or left empty to accept the default. - *host*: IP address or DNS hostname of the UPS (required) - *port*: Remote SNMP port (optional, default: 161) - *vendor*: The type of SNMP MIB available on the UPS (optional, default: autodetect). Allowable choices for vendor are: - APC : APC PowerNet MIB, used on most APC brand UPSes - RFC : RFC1628 MIB, used by some non-APC UPSes - MGE : MGE MIB, used by many MGE brand UPSes - blank : Autodetect Append "_NOTRAP" to the vendor name to disable SNMP trap catching (ex: "APC_NOTRAP"). See `SNMP Trap Catching`_. - *community*: The read-write community string, usually "private". You can specify a read-only community string, usually "public", if you do not require killpower support. If the community string is omitted, apcupsd will attempt to autotedect by trying "private" and "public". (optional, default: autodetect). A NIS Server/Client (Master/Slave) configuration with multiple servers is still applicable. However, an alternative configuration is possible with an SNMP enabled UPS. In this arrangement, all connected servers will be configured as a standalone server. Each will independently communicate to the UPS. One (primary) server will be chosen to manage the task of commanding the UPS to power down. All remaining (secondary) servers will be configured to quietly power down before the primary server issues the UPS power down command. Building with SNMP support -------------------------- Follow the instructions in `Building and Installing apcupsd`_, being sure to include the following options (in addition to any others you need) on the '``./configure``' line: :: ./configure --enable-snmp SNMP Trap Catching ------------------ apcupsd-3.11.14 introduces support for SNMP trap catching. Previous versions polled the UPS status once per minute, leading to significant delays before UPS state changes were recognized. With SNMP trap handling, apcupsd monitors the SNMP trap port and will re-poll the UPS whenever a trap is received. This happens, for example, when the UPS switches on or off battery. In order for this feature to work, you must configure your UPS to deliver traps to the server running apcupsd. This is generally done by connecting to your SNMP card via a web browser or telnet connection. You will need to enter your server's IP address as a trap receiver and make sure trap delivery is enabled. Trap catching can lead to problems if you are already running another SNMP trap daemon on your server. Only one daemon can listen to the trap port, so whichever one is started first will succeed and the others will fail. Apcupsd will fall back to polling behavior if it is unable to open the trap port. You can also forcibly disable trap catching by appending ``_NOTRAP`` to your vendor string in the apcupsd.conf ``DEVICE`` directive. Known Problems -------------- Currently (as of 3.10.0) the code to power off the UPS needs special configuration. The killpower command for SNMP UPSes can not be issued during shutdown as typically at some time during shutdown operations the network stack is stopped. To overcome this problem it is needed to modify the /etc/rc.d/apcupsd system control script to tell apcupsd to issue the power down command (killpower) to the UPS immediately before apcupsd initiates the system shutdown. For this reason it is paramount to set your UPS grace time to a value greater than 120 seconds to allow for clean shutdown operations before the UPS removes the power from its plugs. To enable correct shutdown operation during powerdown do the following: - Connect to your Web/SNMP card using your favorite web browser, go to the UPS configuration menu and change the "Shutdown Delay" parameter to 180 seconds or more, depending on how much time your system shutdown requires to umount all the filesystems. - **Option 1 (non-windows)** Edit the server halt script. Relocate the ups_kill_power() function higher in the shutdown sequence, primarily before the command to bring down the ethernet service. This is the preferred method for shutting down the UPS. The UPS will power down after the prescribed "Shut Down Delay" time (in seconds) has elapsed. - **Option 2** Change /etc/rc.d/apcupsd script adding the ``--kill-on-powerfail`` to the apcupsd invocation. This method is not preferred because the UPS is commanded to power down without delay. This creates the potential for UPS powering down before the server calling for UPS power down completes its shutdown. However, in the case of Microsoft Windows OS, this is the only method available for powering down the UPS. - Restart your apcupsd With this setup your UPS operations should be safe. apcupsd System Logging ====================== The apcupsd philosophy is that all logging should be done through the ``syslog`` facility (see: '``man syslog``') This is now implemented with the exceptions that STATUS logging, for compatibility with prior versions is still done to a file, and EVENTS logging can be directed to a temporary file so that it can be reported by the network information server. Logging Types ------------- apcupsd splits its logging into four separate types called: #. DEBUG #. DATA #. STATUS #. EVENTS Debug logging consists of debug messages. Normally these are turned on only by developers, and currently there exist very few of these debug messages. Data Logging ~~~~~~~~~~~~ This feature is somewhat outdated and not often used. Data logging consists of periodically logging important data concerning the operation of the UPS. For the definitive definition of the format, see log\_data() in apcreports.c. The format varies according to the UPS model and the information available from the UPS. For UPS models, NBKPRO, SMART, SHARESMART, and MATRIX, the output is written in a format very similar to what PowerChute writes. That is: MinLineVoltage, MaxLineVoltage, OutputVoltage, BatteryVoltage, LineFrequency, LoadPercent, UPSTemperature, AmbientTemperature, Humidity, LineVoltage, BatteryCharge, toggle Any value that is not supported by your UPS such as AmbientTemperature and Humidity will be blank or possibly as 0.0. In any case the commas before and after that field will still be output. The toggle value alternates from 0 to 1 on each line. This was added at user request so that no two adjacent samples are identical. An actual example from the log file is: :: Nov 2 12:43:05 matou apcupsd[23439]: 224.9,227.5,226.2,27.74,50.00,100.0,30.6,,,226.2,50.0,1 Status Logging ~~~~~~~~~~~~~~ Status logging consists of logging all available information known about your UPS as a series of ASCII records. This information is also made available by the apcupsd network information server. For more details on STATUS logging, see the `apcupsd Status Logging`_ section for details. EVENTS Logging ~~~~~~~~~~~~~~ Events logging consists of logging events as they happen. For example, successful startup, power fail, battery failure, system shutdown, ... See the `Customizing Event Handling`_ section for more details. Implementation Details ---------------------- In order to ensure that the data logged to syslog() can be directed to different files, I have assigned syslog() levels to each of our four types of data as follows: #. DEBUG logging has level LOG_DEBUG #. DATA logging has level LOG_INFO #. STATUS logging has level LOG_NOTICE #. EVENTS logging has levels LOG_WARNING, LOG_ERR, LOG_CRIT, and LOG_ALERT It should be noted that more work needs to be done on the precise definitions of each of the levels for EVENTS logging. Currently, it is roughly broken down as follows: LOG_WARNING general information such as startup, etc. LOG_ERR an error condition detected, e.g. communications problem with the UPS. LOG_CRIT a serious problem has occurred such as power failure, running on UPS batteries, ... LOG_ALERT a condition that needs immediate attention such as pending system shutdown, ... The default Facility for syslog() logging is DAEMON, although this can be changed with the FACILITY directive in apcupsd.conf. In the following example, we should the facility as local0. More work needs to be done to the code to ensure that it corresponds to the above levels. As a practical example of how to setup your syslog() to use the new logging feature, suppose you wish to direct all DATA logging to a file named /var/log/apcupsd.data, all EVENTS to the standard /var/log/messages file (to be mixed with other system messages), and at the same time send all EVENTS to /var/log/apcupsd.events, and finally, you want to send all STATUS logging to the named pipe /var/log/apcupsd.status First as root, you create the named pipe: :: mkfifo /var/log/apcupsd.status Change its permissions as necessary or use the -m option to set them when creating the pipe. Then you modify your /etc/syslog.conf file to direct the appropriate levels of messages where you want them. To accomplish the above, my syslog.conf file looks like: :: # exclude all apcupsd info by default *.info;local0.none /var/log/messages # Everything for apcupsd goes here local0.info;local0.!notice /var/log/apcupsd.data local0.notice;local0.!warn |/var/log/apcupsd.status local0.warn /var/log/apcupsd.events local0.warn /var/log/messages The Windows Version of apcupsd ============================== The Windows version of apcupsd has been tested on Win95, Win98, WinMe, WinNT, WinXP, and Win2000 systems. This version of apcupsd has been built to run natively on Windows (no Cygwin or other emulation layer needed). Even though the Win32 version of apcupsd is a port that relies on many Unix features, it is just the same a true Windows program. When running, it is perfectly integrated with Windows and displays its icon in the system icon tray, and provides a system tray menu to obtain additional information on how apcupsd is running (status and events dialog boxes). Once installed apcupsd normally runs as a system service. This means that it is immediately started by the operating system when the system is booted, and runs in the background even if there is no user logged into the system. Installing Apcupsd on Windows ----------------------------- Normally, you will install the Windows version of apcupsd from the binaries. Starting with version 3.11.15, the Windows binaries are distributed with a full GUI installer driven by NSIS, the Nullsoft Scriptable Install System (http://nsis.sourceforge.net). Installation is very simple and straight-forward: Simply double-click the installer executable and follow the instructions. Configuring Apcupsd on Windows ------------------------------ If you are installing Apcupsd for the first time, the installer will give you an opportunity to edit the apcupsd.conf configuration file to contain the values appropriate for your site. (Subsequent installations will maintain your existing apcupsd.conf, so you need not edit it again unless there are new features or syntax changes that must be accounted for.) The default configuration calls for a USB connected UPS. This is the most common connection for modern UPSes, especially those used with Windows computers. All other apcupsd drivers are available (apcsmart, dumb, net, snmp, pcnet) and can be used simply by editing the configuration file ``UPSCABLE``, ``UPSTYPE``, and ``DEVICE`` settings as described elsewhere in this manual. Note that on Windows, serial ports are specified using ``COM1``, ``COM2``, etc. notation instead of the UNIX-style /dev/tty\* notation. Note also if you are using WinNT or Win2000, the operating system may probe the serial port attempting to attach a serial mouse. This will cause apcupsd to be unable to communicate with the serial port. If this happens, or out of precaution, you can edit the ``c:\\boot.ini`` file. Find the line that looks something like the following: :: multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows NT Workstation Version 4.00" and add the following to the end of the line: ``/NoSerialMice:COM1`` (or COM2 depending on what you want to use). The new line should look similar to... :: multi(0)disk(0)rdisk(0)partition(1)\WINNT="Windows NT Workstation Version 4.00" /NoSerialMice:COM1 ...where the only thing you have changed is to append to the end of the line. This addition will prevent the operating system from interfering with apcupsd Starting Apcupsd on Windows --------------------------- The installer will give you an opportunity start the Apcupsd service immediately. If you choose to start it manually, you may do so by selecting the "Start Apcupsd" link from the Start->Programs->Apcupsd folder. On Windows NT/2000/XP, you may alternatively go to the Control Panel, open the Services folder, select Apcupsd UPS Server, and then click on the **Start** button as shown below: .. image:: ./wininstall6.png If the Services dialog reports a problem, it is normally because your ``DEVICE`` statement does not contain the correct serial port name. You probably should also click on the **Startup...** button to ensure that the correct defaults are set. The dialogue box that appears should have **Startup Type** set to **Automatic* and **Logon** should be set to **System Account**. If these values are not set correctly by default, please change them otherwise apcupsd will not work. For WinXP and Win2K systems, the dialogs are a bit different from those shown here for WinNT, but he concept is the same. You get to the Services dialog by clicking on: Control Panel -> Administrative Tools -> Component Services. The apcupsd service should appear in the right hand window when you click on **Services (Local)** in the left hand menu window. That should complete the installation process. When the system tray icon turns from a question mark |image4| into a plug |image5|, right click on it and a menu will appear. Select the **Events** item, and the Events dialogue box should appear. There should be no error messages. By right clicking again on the system tray plug and selecting the **Status** item, you can verify that all the values for your UPS are correct. When the UPS switches to the battery, the battery icon |image6| will appear in the system tray. While the UPS is online, if the battery is not at least 99% charged, the plug icon will become a plug with a lightning bolt in the middle |image7| to indicate that the battery is charging. Apctray ------- Starting with version 3.14.2, the tray icon is provided by a separate program called 'apctray'. This cleanly separates the user interface from the daemon (service) and is required for tray icon support on Windows Vista. Note that if you close or disable the tray icon this does **not** stop or disable the apcupsd service which will continue to monitor the UPS and shutdown the computer when appropriate. To stop or disable the service, use the service control panel. apctray has the capability of monitoring multiple apcupsd instances using apcupsd's Network Information Server (NIS). It will create a new icon for each instance being monitored. By default, apctray monitors the local apcupsd (localhost on port 3551). To add additional monitors, you can right-click an existing icon and choose "Add Monitor". To remove a monitor, right-click its icon and choose "Remove Monitor". To change thr settings for an existing monitor (ip address, port, refresh rate), right-click its icon and choose "Configure...". apctray can be installed standalone (without apcupsd) if you wish to use it only to monitor remote apcupsd instances. This can be convenient for keeping an eye on a room full of UPSes from your desktop. Download and run the normal apcupsd installer and simply uncheck all components except apctray. Then add as many monitors as you wish as described above. Testing Apcupsd on Windows -------------------------- It would be hard to overemphasize the need to do a full testing of your installation of apcupsd as there are a number of reasons why it may not behave properly in a real power failure situation. Please read the `Testing Apcupsd`_ section of this document for general instructions on testing the Win32 version. However, on Win32 systems, there is no Unix system log file, so if something goes wrong, look in the file ``c:\apcupsd\etc\apcupsd\apcupsd.events`` where apcupsd normally logs its events, and you will generally find more detailed information on why the program is not working. The most common cause of problems is either improper configuration of the cable type, or an incorrect address for the serial port. Additionally, check the application event log, if you're running a platform that supports it such as Windows 2000 or XP. Upgrading --------- An upgrade may be accomplished by uninstalling the old version (using the Add/Remove Programs Control Panel or clicking the "Uninstall Apcupsd" link from Start -> Programs -> Apcupsd. Near the end of the uninstall you will be prompted about removing configuration and event files. You should answer "No" in order to preserve your existing apcupsd.conf file. After the uninstall completes you may install the new version of Apcupsd as described above. If you preserved your existing apcupsd.conf file, the new apcupsd.conf will be installed as apcupsd.conf.new. Post-Installation ----------------- After installing apcupsd and before running it, you should check the contents of the config file ``c:\apcupsd\etc\apcupsd\apcupsd.conf``. You will probably need to change your UPSCABLE directive, your UPSTYPE and possibly your DEVICE directives. Please refer to the configuration section of this manual for more details. Problem Areas ------------- On some Windows systems, the domain resolution does not seem to work if you have not configured a DNS server in the Network section of the Control Panel. This problem should be apparent only when running a slave configuration. In this case, when you specify the name of the master in your apcupsd.conf file, apcupsd will be unable to resolve the name to a valid IP address. To circumvent this problem, simply enter the address as an IP address rather than a hostname, or alternatively, ensure that you have a valid DNS server configured on your system. On WinNT, WinXP, and Win2K systems, you can examine the System Applications log to which apcupsd writes Windows error messages during startup. Regardless of which Windows system you are running, apcupsd logs most error messages to ``c:\apcupsd\etc\apcupsd\apcupsd.events``. This type error messages such as configuration file not found, etc are written to this file. Note that on some systems (WinXP, possibly others) Apcupsd is unable to write to this file when running as a service. Email Notification of Events ---------------------------- It is possible to receive email notification of apcupsd events using some simple Visual Basic scripts contributed by Ed Dondlinger . The scripts are automatically installed in the ``etc/apcupsd`` directory of your apcupsd installation but are disabled by default. To enable them, first open them in a text editor such as Notepad and edit the ``USER VARIABLES`` section to set your email preferences including address, server information, etc. Then rename the script files without the ``*.example`` suffix. Scripts are supplied for onbattery, offbattery, and commfailure events. You can copy the scripts to other filenames and modify the email body text to respond to other events as described in `Customizing Event Handling`_. Killpower under Windows ----------------------- If your batteries become exhausted during a power failure and you want your machine to automatically reboot when the power comes back, it is useful to implement the killpower feature of the UPS where apcupsd sends the UPS the command to shut off the power. In doing so, the power will be cut to your PC and if your BIOS is properly setup, the machine will automatically reboot when the power comes back. This is important for servers. This feature is implemented on Unix systems by first requesting a system shutdown. As a part of the shutdown, apcupsd is terminated by the system, but the shutdown process executes a script where apcupsd is recalled after the disks are synced and the machine is idle. Apcupsd then requests the UPS to shut off the power (killpower). Unfortunately on Windows, there is no such shutdown script that we are aware of and no way for apcupsd to get control after the machine is idled. If this feature is important to you, it is possible to do it by telling apcupsd to immediately issue the killpower command after issuing the shutdown request. The danger in doing so is that if the machine is not sufficiently idled when the killpower takes place, the disks will need to be rescanned (and there is a possibility of lost data however small). Generally, UPSes have a shutdown grace period which gives sufficient time for the OS to shutdown before the power is cut. To implement this feature, you need to add the ``-p`` option to the apcupsd command line that is executed by the system. Currently the procedure is manual. You do so by editing the registry and changing the line: :: c:\apcupsd\apcupsd.exe /service found under the key: :: HKEY_LOCAL_MACHINE Software\Microsoft\Windows\CurrentVersion\RunServices to :: c:\apcupsd\apcupsd.exe /service -p If you have a Smart UPS, you can configure the kill power grace period, and you might want to set it to 3 minutes. If you have a dumb UPS, there is no grace period and you should not use this procedure. If you have a Back-UPS CS or ES, these UPSes generally have a fixed grace period of 2 minutes, which is probably sufficient. Power Down During Shutdown -------------------------- Our philosophy is to shutdown a computer but not to power it down itself (as opposed to having the UPS cut the power as described above). That is we prefer to idle a computer but leave it running. This has the advantage that in a power fail situation, if the killpower function described above does not work, the computer will continue to draw down the batteries and the UPS will hopefully shutoff before the power is restore thus permitting an automatic reboot. Nevertheless some people prefer to do a full power down. To do so, you might want to get a copy of PsShutdown, which does have a power down option. You can find it and a lot more useful software at: http://technet.microsoft.com/en-us/sysinternals/bb897541.aspx. To use their shutdown program rather than the apcupsd supplied version, you simply edit: :: c:\apcupsd\etc\apcupsd\apccontrol with any text editor and change our calls to shutdown to psshutdown. Command Line Options Specific to the Windows Version ---------------------------------------------------- These options are not normally seen or used by the user, and are documented here only for information purposes. At the current time, to change the default options, you must either manually run apcupsd or you must manually edit the system registry and modify the appropriate entries. In order to avoid option clashes between the options necessary for apcupsd to run on Windows and the standard apcupsd options, all Windows specific options are signaled with a forward slash character (``/``), while as usual, the standard apcupsd options are signaled with a minus (``-``), or a minus minus (``--``). All the standard apcupsd options can be used on the Windows version. In addition, the following Windows only options are implemented: /service Start apcupsd as a service /run Run the apcupsd application /install Install apcupsd as a service in the system registry /remove Uninstall apcupsd from the system registry /about Show the apcupsd about dialogue box /kill Stop any running apcupsd /help Show the apcupsd help dialogue box It is important to note that under normal circumstances the user should never need to use these options as they are normally handled by the system automatically once apcupsd is installed. However, you may note these options in some of the .pif files that have been created for your use. Installation: Serial-Line UPSes =============================== Overview of Serial-Interface UPSes ---------------------------------- If you have a UPS that communicates via serial port, you need to do two things before you can even think about configuring the software. First, you need to figure out whether it's a dumb (voltage-signalling) UPS or speaks the apcsmart protocol. Second, if you have an interface cable from APC, you need to figure out what kind it is. If you don't have such a cable, you need to build one. A straight-through serial cable won't work. According to Bill Marr the Belkin F5U109, also sold as F5U409 also works with apcupsd for kernel versions 2.4.25 or higher and kernels 2.6.1 and higher. These newer kernels are needed to have the patch that makes the mct\_u232 (Magic Control Technology) module and other adapters work with RS-232 devices that do not assert the CTS signal. Connecting a Serial-Line UPS to a USB Port ------------------------------------------ By using a special adaptor, you can connect your serial-line UPS to a USB port. If you would like to free up your serial port and connect your existing serial port UPS to a USB port, it is possible if you have one of the later kernels. You simply get a serial to USB adapter that is supported by the kernel, plug it in and make one minor change to your apcupsd.conf file and away you go. (Kern adds: Thanks to Joe Acosta for pointing this out to me.) The device that Joe Acosta and Kern are using is IOgear GUC232A USB 2 serial adapter. Bill Marr informs us that it also works with a Back-UPS Pro 650 and the 940-0095B cable. At Kern's site, running Red Hat 7.1 with kernel 2.4.9-12, he simply changed his /etc/apcupsd/apcupsd.conf configuration line to be: :: DEVICE /dev/ttyUSB0 Depending on whether or not you have hotplug working, you may need to explicitly load the kernel modules ``usbserial`` and ``pl2303``. In Kern's case, this was not necessary. Testing Serial-Line UPSes ------------------------- If you have a serial-line UPS, there are some tests you should run before the general ones described in the `Testing Apcupsd`_ section. To test your computer's connection with a serial-line UPS, you first need to establish that the serial line is functioning, and then that the UPS is responding to commands. This can be a bit tricky, especially with a dumb voltage-signalling interface, because it is completely quiescent when there are no commands being passed, and the command repertoire doesn't include any self-tests. Because it is easy to configure a serial cable incorrectly in such a way as to cause premature shutdowns of the UPS power, we *strongly* recommend, especially for voltage- signaling (dumb) UPSes, that you do most of the initial testing with your computer plugged into the wall rather than your UPS. Thus if the UPS power is suddenly shut off, your computer will continue to run. We also recommend using safe-apccontrol as described below, until you are sure that the signaling is correct. Also note that if you launch the execution of apcupsd while your voltage-signaling UPS is on battery power, it is very likely that your UPS will immediately shut off the power. This is due to the initialization of the serial port line signals, which often looks to the UPS like a shutdown command. Finally, double-check the state of your cabling and UPS indicator lights frequently during testing. For voltage-signaling UPSes, apcupsd is not currently able to detect whether or not the serial cable is connected. In addition, some simple signaling UPSes with certain cable combinations are not able to detect the low battery condition. For more details please see `Voltage Signalling Features Supported by Apcupsd for Various Cables`_. Establishing Serial Port Connection ----------------------------------- Once you have compiled, installed, and invoked apcupsd, you should wait to allow apcupsd to configure itself and establish contact with the UPS. If you see a message similar to the following about 30 seconds after starting apcupsd... :: apcupsd FATAL ERROR in apcserial.c at line 156 PANIC! Cannot communicate with UPS via serial port. it means that apcupsd tried for about 30 seconds to establish contact with the UPS via the serial port, but was unable to do so. Before continuing, you must correct this problem. Some of the possible sources of the problem are: - You have not configured the correct serial port name on the ``DEVICE`` directive in your apcupsd configuration file. - The serial port that you have chosen has logins enabled. You must disable logins on that port, otherwise, the system prevents apcupsd from using it. Normally, the file /etc/inittab specifies the ports for which a getty process is started (on Sun machines, the serial port program equivalent to getty is called ttymon). You must disable this for the port that you wish to use. - Make sure you are doing your testing as root otherwise, you may have permissions problems accessing the serial port. - You may have cabling problems, either with an incorrect cable, or the incorrect cable specification directive in the configuration file. - You may have a problem with the /etc/apcupsd/acpupsd.conf file. For example, check that you have specified the correct type of UPS and the correct networking directives. For more details, see the `After Installation`_ section. - If you have a SmartUPS 5000 RM 15U or similar model, that comes with a "Web/SNMP management card" in one of the "Smart Slots", this card may interfere with the serial port operation. If you are having problems, please remove this card and try again. Supposedly V3.0 of the card firmware has been corrected to properly release the serial port. - Ensure that you have no other programs that are using the serial port. One user reported that he had problems because the serial port mouse (gpm) was using the same port as apcupsd. This causes intermittent seemingly random problems. - Try connecting your UPS to another machine. If it works, then you probably have a bad serial port card. As unlikely as this may sound, at least two of our users have had to replace bad serial port cards. - Try doing an '``lsof /dev/ttyS0``' where you replace the ``/dev/ttyS0`` with your serial port name. If you get no output, the port is free (or there is no physical port). If you get output, then another program is using the port, and you should see which one. - Try doing a '``dmesg | grep tty``'. This may show you if a program has grabbed the port. (Thanks to Joe Acosta for the suggestion.) - If all else fails, make sure your system is configured for serial port support. The first thing to do is to look at your log file, usually /var/log/messages because apcupsd writes more detailed information to the log file whenever there is an error. If you have a UPS that uses apcsmart protocol, you can manually test the serial communications with the UPS by starting a serial port communications program (such as minicom, tip, or cu) with the settings 2400 8N1 (2400 baud, 8 data bits, no parity, 1 stop bit). Be extremely careful what you send to your UPS as certain characters may cause it to power down or may even cause damage to the UPS. Try sending an upper case ``Y`` to the UPS (without a return at the end). It should respond with ``SM``. If this is not the case, review the possible problems listed above. If you fat finger the Y and enter y instead, no cause for alarm, you will simply get the APC copyright notice. Once you are sure that serial port communications is working, proceed to the next test. Once you have established serial communications ----------------------------------------------- Once you have established that apcupsd can talk to the UPS over the serial part, go do the series of functional tests described in the main Testing section (see `Testing Apcupsd`_). Troubleshooting Serial Line communications ------------------------------------------ *The most frequently encountered problem with voltage-signalling UPSes (e.g. BackUPS 650) is that you have incorrectly specified which cable is being used.* All cables furnished by APC have the cable number stamped on the side of the computer connector end of the cable. Using this number with apcupsd will normally work fine. If you do not know what cable you have, you can use the apctest program to determine the type of the cable. For simple signaling UPSes, you should **not** use ``simple`` in the cable specification (i.e. ``UPSCABLE simple``) unless you have made the cable yourself according to the wiring diagram given in the cables chapter of this manual. Bizarre Intermittent Behavior: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In one case, a user reported that he received random incorrect values from the UPS in the status output. It turned out that gpm, the mouse control program for command windows, was using the serial port without using the standard Unix locking mechanism. As a consequence, both apcupsd and gpm were reading the serial port. Please ensure that if you are running gpm that it is not configured with a serial port mouse on the same serial port. .. include:: cables.rst Recalibrating the UPS Runtime ============================= Note: In a future release of apcupsd this procedure will be replaced by a daemon operation that can be performed on all types of UPS. This section does not apply to voltage-signalling or dumb UPSes such as the older BackUPS models. Smart UPSes internally compute the remaining runtime, and apcupsd uses the value supplied by the UPS. As the batteries age (after say two or three years), the runtime computation may no longer be accurate since the batteries no longer hold the same charge. As a consequence, in the event of a power failure, the UPS and thus apcupsd can report a runtime of 5 minutes remaining when in fact only one minute remains. This can lead to a shutdown before you might expect it, because regardless of the runtime remaining that is reported, the UPS will always correctly detect low batteries and report it, thus causing apcupsd to correctly shutdown your computer. If you wish to have the UPS recalibrate the remaining runtime calculations, you can do so manually as the current version of apcupsd does not support this feature. To do so, - Shutdown apcupsd - contact your UPS directly using some terminal program such as minicom, tip, or cu with the settings 2400 8N1 (2400 baud, 8 bits, no parity, 1 stop bit). Be extremely careful what you send to your UPS as certain characters may cause it to power down or may even cause damage to the UPS. Try sending an upper case ``Y`` to the UPS (without a return at the end). It should respond with ``SM``. If this is not the case, read the chapter on testing. If you fat finger the ``Y`` and enter ``y`` instead, no cause for alarm, you will simply get the APC copyright notice. - when you are sure you are properly connected send an upper case D (no cr). This will put the UPS into calibration mode, and it will drain the battery down to 25% capacity (35% for a Matrix) at which point it will go back on the mains. In doing so, it will recompute the runtime calibration. - If you wish to abort the calibration, enter a second D command. - When you are done, restart apcupsd. In principle, you should be able to do this with the computer powered by the UPS, but if you wish to be completely safe, you should plug your computer into the wall prior to performing the runtime calibration. In that case, you will need to artificially load the UPS with light bulbs or other means. You should supply a load of about 30 to 35% but not more than 50%. You can determine the load by looking at the output of the ``apcaccess status`` command while apcupsd is running. You should not run the recalibration command more than once or twice per year as discharging these kinds of batteries tends to shorten their life span. Configuration Directive Reference ================================= Configuration directives in /etc/apcupsd/apcupsd.conf control the behavior of the apcupsd daemon. For most installations it is only necessary to set a handful of general directives. The rest can be left at their defaults unless you have an exotic configuration. Note that the apcupsd daemon must be restarted in order for changes to the configuration file to become active. General Configuration Directives -------------------------------- In general, each of these directives is required (except that the ``DEVICE`` directive is ignored for ``UPSCABLE ether`` and not required for ``UPSCABLE usb``). **UPSTYPE** *driver* The name of a driver. Should be one of ``dumb``, ``apcsmart``, ``net``, ``usb``, ``pcnet``, ``snmp``, or ``test``. This describes your interface type. The UPSTYPE directive can be defined during installation by using the ``--with-upstype=`` option of the ``configure`` program. **UPSCABLE** *cable* Defines the type of cable connecting the UPS to your computer. Possible generic choices for are: ``simple``, ``smart``, ``ether``, ``usb`` Or a specific cable model number may be used: ``940-0119A``, ``940-0127A``, ``940-0128A``, ``940-0020B``, ``940-0020C``, ``940-0023A``, ``940-0024B``, ``940-0024C``, ``940-1524C``, ``940-0024G``, ``940-0095A``, ``940-0095B``, ``940-0095C``, ``M-04-02-2000`` The ``--with-upscable=`` option of ``configure`` can be used to set a default for this directive during the your build. **DEVICE** *device* Specify which device is used for UPS communications. For serial ports, it is usually something like /dev/ttyS0. For USB ports, you may leave the name of the device blank (no specification) and apcupsd will automatically search the standard locations for the UPS. Normally, the ``configure`` program will set an appropriate default value. You may also specify the ``--with-serial-dev=`` option of the ``configure`` program to set this directive at build time. If you have specified ``UPSTYPE net``, then the device name to be specified consists of *hostname:port* where the *hostname* is the fully qualified name or IP address of the host (NIS server) and the *port* (optional) is the port to use to contact the server. If you specified ``UPSTYPE snmp``, then the device name becomes *hostname:vendor:community*. Please see the `Support for SNMP UPSes`_ chapter in this manual for more details. **POLLTIME** *time in seconds* The interval, in seconds, at which apcupsd polls the UPS for status. This rate is automatically set to 1 second if the UPS goes on batteries and reset to your specified value when the mains power returns. This setting applies both to directly-attached UPSes (``UPSTYPE`` ``apcsmart``, ``usb``, ``dumb``) and networked UPSes (``UPSTYPE`` ``net``, ``snmp``). Lowering this setting will improve apcupsd's responsiveness to certain events at the cost of higher CPU utilization. The default of 60 is appropriate for most situations. This directive was formerly known as ``NETTIME``. **LOCKFILE** *path to lockfile* This option tells apcupsd where to create a lockfile for the USB or serial port in the specified directory. This is important to keep two programs from reading or writing the port at the same time. Please note that although the directive name is LOCKFILE, you are actually specifying the lock file path. apcupsd automatically appends the name of the device when creating the file. On most systems, this directive is automatically set by the ``./configure`` program. You may also explicitly set it during the build process by using the ``--with-lock-dir=`` option of the ``configure`` program. Configuration Directives Used by the Network Information Server --------------------------------------------------------------- None of these directives are required for proper operation of apcupsd. **NETSERVER** *[on \| off]* This configuration directive turns the network information server on or off. If it is on, apcupsd will spawn a child process that serves STATUS and EVENTS information over the network. This information is currently used by the Web-based CGI programs. The default is on. *This option is required to be turned on for net clients and apcaccess to function.* **NISIP** *IP-address* This directive specifies the IP address of the network interface on which the NIS server will listen for incoming connections. Default value is 0.0.0.0 which means the NIS will listen for connections on all network interfaces. If your machine has more than one interface, you can specify the IP of a single interface to limit connections to only that interface. Furthermore, you can specify the loopback address (127.0.0.1) to accept connections only from the local machine. You may also use the ``--with-nisip=`` option of the ``configure`` program to set this directive during the build. **NISPORT** *port* This configuration directive specifies the port to be used by the apcupsd Network Information Server. The default is platform dependent, but typically 3551, which we have received from IANA as the official apcupsd networking port. This value should only be changed if it conflicts with an existing service in use on your network or if you are running multiple instances of apcupsd on the same machine. **EVENTSFILE** *filename* If you want the apcupsd network information server to provide the last 10 events via the network, you must specify a file where apcupsd will save these events. The default is: /etc/apcupsd/apcupsd.events. Currently, apcupsd will save at most the last 50 events. Periodically (once an hour by default), apcupsd will check the size of this file. When more than 50 events are recorded, apcupsd will truncate the file to the most recent 10 events. Consequently this file will not grow indefinitely. Although we do not recommend it, you may change these values by editing apcevents.c and changing the appropriate defines. Be aware that if you set these values to very large numbers, apcupsd may make excessive memory demands on the system during the data access and file truncation operations. This filename may also be specified at build time by using the ``--with-log-dir=`` option of the ``configure`` program. Configuration Directives used during Power Failures --------------------------------------------------- In general, none of these directives are required. However, if you have a voltage-signalling (dumb) UPS with a cable that does not support the Low Battery signal, you must set the ``TIMEOUT`` directive to force a shutdown. **BATTERYLEVEL** *percent of battery* If ``BATTERYLEVEL`` is specified, during a power failure, apcupsd will halt the system when the remaining battery charge falls below the specified percentage. The default is 5 percent. This directive is ignored for dumb (voltage-signalling) UPSes. To totally disable this counter, set ``BATTERYLEVEL -1`` in your apcupsd.conf file. **MINUTES** *battery runtime in minutes* If ``MINUTES`` is specified, during a power failure, apcupsd will shutdown the system when the remaining runtime on batteries as internally calculated by the UPS falls below the time specified. The default is 3. This directive is ignored for dumb (voltage-signalling) UPSes. It should be noted that some UPSes report an incorrect value for remaining runtime when the battery is fully charged. This can be checked by examining the ``TIMELEFT`` value as printed in the output of an '``apcaccess status``' command. If the value is zero or otherwise unreasonable, your UPS is probably broken. In this case, we recommend that you disable this timer by setting ``MINUTES -1`` in your apcupsd.conf file. **TIMEOUT** *time in seconds* After a power failure, apcupsd will halt the system when ``TIMEOUT`` seconds have expired. A value of zero disables this timer. Normally for all Smart UPS models and dumb UPSes with cables that support low battery detection, this should be zero so that the shutdown time will be determined by the battery level and/or remaining runtime (see above) or in the case of a voltage-signalling UPS, when the battery is exhausted. This command is required for dumb UPSes that do not provide a battery exhausted signal (only testing can determine this point). For more information, see the `Testing Apcupsd`_ section of this manual. This timer can also be useful if you want some slave machines to shutdown before other machines to conserve battery power. It is also useful for testing apcupsd because you can force a rapid shutdown by setting a small value (e.g. 60) and pulling the plug to the UPS. ``TIMEOUT``, ``BATTERYLEVEL``, and ``MINUTES`` can be set together without problems. apcupsd will react to the first case or test that is valid. Normally SmartUPS users will set ``TIMEOUT`` to zero so that the system is shutdown depending on the percentage battery charge remaining (``BATTERYLEVEL``) or the remaining battery runtime (``MINUTES``). **ANNOY** *time in seconds* Specify the time in seconds between messages requesting logged in users to get off the system during a power failure. This timer starts only when the UPS is running on batteries. The default is 300 seconds (5 minutes). apcupsd sends the annoy messages by invoking the apccontrol script with the ``annoyme`` argument. The default is to send a wall message on Unix systems and a popup message in Windows. The value of ``ANNOYDELAY`` must be greater than the value of ``ANNOY`` in order to receive annoy messages (this doesn't make sense, and means that the default values do not generate annoy messages: KES). Note that if ``NOLOGON disable`` is set, the annoy messages will also be disabled. **ANNOYDELAY** *time in seconds* Specify delay time in seconds before apcupsd begins requesting logged in users to get off the system during a power failure. This timer starts only after the UPS is running on batteries. This timer is reset when the power returns. The default is 60 seconds. Thus, the first warning to log off the system occurs after 60 seconds on batteries, assuming that ``NOLOGON`` is not set to ``disable``. **NOLOGON** *disable* | *timeout* | *percent* | *minutes* | *always* Specifies when apcupsd should prevent user logins The type specified allows you define the point when apcupsd will create the 'nologin' file and thus when user logins are prohibited. Once the 'nologin' file is created, normal users are prevented from logging in. Control of when this file is created is important for allowing systems with big UPSes to run as normally until the system administrator determines the need for preventing user logins. The feature also allows the system administrator to hold the "ANNOY" factor until the 'nologin' file is created. The default is always disable if no ``NOLOGON`` directive is specified. The 'nologin' file will be created in the directory specified by the ``NOLOGINDIR`` directive described below. As far as I can tell, the only useful types are disable and always since the difference in the time when the logout warning is given and shutdown occurs for the other types is very short (KES). *disable* prevents apcupsd from creating the nologin file. Consequently, any user can login during a power failure condition. Also, the ANNOY feature is disabled so users will not be warned to logoff the system. *timeout* specifies that apcupsd should prohibit logins after the UPS is on batteries for 90% of the time specified on the ``TIMEOUT`` configuration directive. Note! Normally you don't want to specify a TIMEOUT value, so this option is probably not too useful (KES). *percent* specifies that apcupsd should prohibit logins when the remaining battery charge percentage reaches 110% or less than the value specified on the ``BATTERYLEVEL`` configuration directive. Thus if the ``BATTERYLEVEL`` is specified as 15, apcupsd will prohibit logins when the battery charge drops below 16% (15% X 110% = 16%). *minutes* specifies that apcupsd should prohibit logins when the remaining runtime in minutes reaches 110% or less than the value specified on the ``MINUTES`` configuration directive. Thus if ``MINUTES`` is set to 3, apcupsd will prohibit logins when the remaining runtime is less than 3 minutes (3 X 110% = 3). *always* causes apcupsd to immediately prohibit logins when a power failure occurs. This will also enable the ANNOY feature. **NOLOGINDIR** *path to nologin dir* This directive configures the directory into which apcupsd will write the nologin file, as described above for the ``NOLOGON`` directive. Normally, the ``configure`` program will set an appropriate default value for your platform, often /etc. You may also specify the ``--with-nologdir=`` option of the ``configure`` program to change the default at compile time. **KILLDELAY** *time in seconds* If ``KILLDELAY`` is set, apcupsd will continue running after a shutdown has been requested, and after the specified time in seconds, apcupsd will attempt to shut off the UPS the power. This directive should normally be disabled by setting the value to zero, but on some systems such as Win32 systems apcupsd cannot regain control after a shutdown to force the UPS to shut off the power. In this case, with proper consideration for the timing, the ``KILLDELAY`` directive can be useful. Please be aware, if you cause apcupsd to kill the power to your computer too early, the system and the disks may not have been properly prepared. In addition, apcupsd must continue running after the shutdown is requested, and on Unix systems, this is not normally the case as the system will terminate all processes during the shutdown. **SCRIPTDIR** *path to apccontrol dir* This option configures the directory in which apccontrol and other event scripts are located. Normally, the ``configure`` program will set an appropriate default value for your platform, often /etc/apcupsd. **PWRFAILDIR** *path to powerfail dir* When apcupsd shuts down your system, it creates a temporary "flag file" which is used by the operating system halt scripts to know if this shutdown is due to a power failure. This directive configures which directory the flag file will be written into. The chosen directory must be writable by the user apcupsd is running as (normally root) and must not be cleared or unmounted early in the shutdown sequence. Normally, the ``configure`` program will set an appropriate default value for your platform, often /etc/apcupsd. You may also specify the ``--with-pwrfaildir=`` option of the ``configure`` program to change the default at compile time. Configuration Directives used to Control System Logging ------------------------------------------------------- **STATTIME** *time in seconds* This directive supplies the time interval in seconds between writes to the STATUS file. If set to zero, the STATUS file will not be written. Please note that in a future version of apcupsd the STATUS file code will disappear since its functionality has been replaced by the Network Information Server and by ``apcaccess status``, as a consequence, it is normally disabled by setting it to zero. **STATFILE** *file* This directive specifies the file to be used when writing the STATUS information. The default is /etc/apcupsd/apcupsd.status. **DATATIME** *time in seconds* This directives supplies the time interval in seconds between writes of PowerChute-like data information to the log file. See the `DATA Logging`_ section of this manual for additional details. **FACILITY** *log-facility* The ``FACILITY`` directive can be used to change the system logging class or facility. The default is ``DAEMON``. This parameter can be useful if you wish to direct the apcupsd system logging information to other than your system default files. See the `apcupsd System Logging`_ section of this manual for additional details. Configuration Directives for Sharing a UPS ------------------------------------------ The following directives apply to sharing an UPS using a ShareUPS hardware module. Most users will not use this mode. **UPSCLASS** *standalone* | *shareslave* | *sharemaster* The default is ``standalone`` and should be used for all machines powered by the UPS and having a serial port or other direct connection to the UPS. This is the normal case. Use ``shareslave`` if and only if you are using a ShareUPS and connected to a BASIC Port with Simple Signal. This code is not fully tested. Use ``sharemaster``, if and only if you are using a ShareUPS and connected to the ADVANCED Port Smart Signal control. This code is not fully tested. **UPSMODE** *disable* | *share* For normal standalone operations, you will set ``UPSMODE disable`` to indicate that you are disabling the ShareUPS support. Use ``share`` for two or seven additional simple signal ports on a SmartAccessories(tm) (internal/external box) for SmartUPSes. The share and sharenet code is not fully tested. Configuration Directives Used to Set the UPS EEPROM --------------------------------------------------- *These directives have no effect on the operation of apcupsd but are reserved for use by apctest when bulk programming the values of the UPS EEPROM configuration variables in a Smart-UPS model.* **UPSNAME** ** Name of UPS. Maximum of 8 characters. **BATTDATE** [ *mm/dd/yy* | *dd/mm/yy* ] Last battery replacement date. Maximum of 8 characters. **SENSITIVITY** [ *H* | *M* | *L* ] H : High (most sensitive setting) M : Medium L : Low (least sensitive setting) **WAKEUP** [ *000* | *060* | *180* | *300* ] The time delay in seconds that the UPS waits after the return of utility power before "waking up" and restoring power to the connected equipment. **SLEEP** [ *020* | *180* | *300* | *600* ] The time delay in seconds for which the UPS waits or "sleeps" after it receives a request to power off the connected system. **LOTRANSFER** ** Low line voltage causing transfer to battery power or activation of SmartBoost. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are:: D 106 103 100 097 M 177 172 168 182 A 092 090 088 086 I 208 204 200 196 where D = domestic (USA), M = Canada, A = Asia and I = International. **HITRANSFER** ** High line voltage causing transfer to battery power or activation of SmartTrim. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are:: D 127 130 133 136 M 229 234 239 224 A 108 110 112 114 I 253 257 261 265 where D = domestic (USA), M = Canada, A = Asia and I = International. **RETURNCHARGE** [ *00* | *15* | *50* | *90* ] Percentage of battery charge needed for the UPS to restore power to the connected equipment. **BEEPSTATE** [ *0* | *T* | *L* | *N* ] Alarm delay. :: 0 : Zero delay after power fails. T : When power fails plus 30 seconds. L : When low battery occurs. N : Never. **LOWBATT** ** Low battery warning occurs when the specified number of minutes remains before the UPS estimates battery power will be exhausted. There are four user-changeable settings: 2, 5, 7, or 10 minutes **OUTPUTVOLTS** ** UPS nominal output voltage when running on battery. Allowable values depend on the last letter of the firmware or APCMODEL. Typical values are:: D 115 M 208 A 100 I 230 240 220 225 where D = domestic (USA), M = Canada, A = Asia and I = International. **SELFTEST** [ *336* | *168* | *ON* | *OFF* ] Self test interval in hours (336 = 2 weeks, 168 = 1 week, ON = at power on, OFF = never). apcupsd Status Logging ====================== There is a good deal of information available about the UPS and apcupsd's status. This document describes the format of that information. Normally you will get at it via ``apcaccess``, but there are other ways as well. Status report format -------------------- STATUS output is in ASCII format with a single data value or piece of information on each line output. Because not all UPSes supply the same information, the output varies based on the type of UPS that you are using. In general, if the information is not available for your UPS, the line will be missing entirely or the data portion of the output record will contain an ``N/A`` indicating that the information is not available. Status logging consists of periodically logging ALL available information concerning the UPS. Since the volume of data is rather large (over 1000 bytes per status), the STATUS data is not automatically sent to the system log file. Instead, it is written as a series of data records in a specific file (normally /etc/apcupsd/apcupsd.status). After each write, the file is rewound so that the size of the file remains constant. The STATUS file is kept for backward compatibility and will be eliminated in a future version of apcupsd. The preferred method for obtaining this information is from apcaccess or by using the CGI interface (see `apcupsd Network Monitoring (CGI) Programs`_). To make reading the status data reliable via a named pipe, the first record written contains a version number, the number of records that follow the first record, and the total number of bytes in those subsequent records. An actual example of such a status file (/etc/apcupsd/apcupsd.status) is shown below. Consequently, the first record always consists of 24 bytes (23 characters followed by a newline). This record starts with APC and as indicated in the example is followed by 37 records consisting of 906 bytes. The last record begins with END APC and contains the date and time matching the DATE record. When this data is written to a file, it is written as two records, the first record, and all the other records together. In reading the file, it can be either be read a record at a time, or in one big read. When this data is written to syslog(), it is written a record at a time. The first record is the first 24 bytes. By having the number of records and the size in the first record, the complete status can be reliably reassembled. Status Report Example --------------------- An example of output from a BackUPS RS 1500 follows: :: APC : 001,037,0906 DATE : Sun Apr 26 17:22:22 EDT 2009 HOSTNAME : mail.kroptech.com VERSION : 3.14.2 (10 September 2007) redhat UPSNAME : ups0 CABLE : USB Cable MODEL : Back-UPS RS 1500 UPSMODE : Stand Alone STARTTIME: Sun Apr 26 10:22:46 EDT 2009 STATUS : ONLINE LINEV : 123.0 Volts LOADPCT : 24.0 Percent Load Capacity BCHARGE : 100.0 Percent TIMELEFT : 144.5 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds SENSE : Medium LOTRANS : 097.0 Volts HITRANS : 138.0 Volts ALARMDEL : Always BATTV : 26.8 Volts LASTXFER : Low line voltage NUMXFERS : 0 TONBATT : 0 seconds CUMONBATT: 0 seconds XOFFBATT : N/A SELFTEST : NO STATFLAG : 0x07000008 Status Flag MANDATE : 2003-05-08 SERIALNO : JB0319033692 BATTDATE : 2001-09-25 NOMINV : 120 NOMBATTV : 24.0 FIRMWARE : 8.g6 .D USB FW:g6 APCMODEL : Back-UPS RS 1500 END APC : Sun Apr 26 17:22:32 EDT 2009 Status Report Fields -------------------- The meaning of the above variables are: **APC** Header record indicating the STATUS format revision level, the number of records that follow the APC statement, and the number of bytes that follow the record. **DATE** The date and time that the information was last obtained from the UPS. **HOSTNAME** The name of the machine that collected the UPS data. **UPSNAME** The name of the UPS as stored in the EEPROM or in the ``UPSNAME`` directive in the configuration file. **VERSION** The apcupsd release number, build date, and platform. **CABLE** The cable as specified in the configuration file (``UPSCABLE``). **MODEL** The UPS model as derived from information from the UPS. **UPSMODE** The mode in which apcupsd is operating as specified in the configuration file (``UPSMODE``) **STARTTIME** The time/date that apcupsd was started. **STATUS** The current status of the UPS (ONLINE, ONBATT, etc.) **LINEV** The current line voltage as returned by the UPS. **LOADPCT** The percentage of load capacity as estimated by the UPS. **BCHARGE** The percentage charge on the batteries. **TIMELEFT** The remaining runtime left on batteries as estimated by the UPS. **MBATTCHG** If the battery charge percentage (BCHARGE) drops below this value, apcupsd will shutdown your system. Value is set in the configuration file (``BATTERYLEVEL``) **MINTIMEL** apcupsd will shutdown your system if the remaining runtime equals or is below this point. Value is set in the configuration file (``MINUTES``) **MAXTIME** apcupsd will shutdown your system if the time on batteries exceeds this value. A value of zero disables the feature. Value is set in the configuration file (``TIMEOUT``) **MAXLINEV** The maximum line voltage since the UPS was started, as reported by the UPS **MINLINEV** The minimum line voltage since the UPS was started, as returned by the UPS **OUTPUTV** The voltage the UPS is supplying to your equipment **SENSE** The sensitivity level of the UPS to line voltage fluctuations. **DWAKE** The amount of time the UPS will wait before restoring power to your equipment after a power off condition when the power is restored. **DSHUTD** The grace delay that the UPS gives after receiving a power down command from apcupsd before it powers off your equipment. **DLOWBATT** The remaining runtime below which the UPS sends the low battery signal. At this point apcupsd will force an immediate emergency shutdown. **LOTRANS** The line voltage below which the UPS will switch to batteries. **HITRANS** The line voltage above which the UPS will switch to batteries. **RETPCT** The percentage charge that the batteries must have after a power off condition before the UPS will restore power to your equipment. **ITEMP** Internal UPS temperature as supplied by the UPS. **ALARMDEL** The delay period for the UPS alarm. **BATTV** Battery voltage as supplied by the UPS. **LINEFREQ** Line frequency in hertz as given by the UPS. **LASTXFER** The reason for the last transfer to batteries. **NUMXFERS** The number of transfers to batteries since apcupsd startup. **XONBATT** Time and date of last transfer to batteries, or N/A. **TONBATT** Time in seconds currently on batteries, or 0. **CUMONBATT** Total (cumulative) time on batteries in seconds since apcupsd startup. **XOFFBATT** Time and date of last transfer from batteries, or N/A. **SELFTEST** The results of the last self test, and may have the following values: - OK: self test indicates good battery - BT: self test failed due to insufficient battery capacity - NG: self test failed due to overload - NO: No results (i.e. no self test performed in the last 5 minutes) **STESTI** The interval in hours between automatic self tests. **STATFLAG** Status flag. English version is given by STATUS. **DIPSW** The current dip switch settings on UPSes that have them. **REG1** The value from the UPS fault register 1. **REG2** The value from the UPS fault register 2. **REG3** The value from the UPS fault register 3. **MANDATE** The date the UPS was manufactured. **SERIALNO** The UPS serial number. **BATTDATE** The date that batteries were last replaced. **NOMOUTV** The output voltage that the UPS will attempt to supply when on battery power. **NOMINV** The input voltage that the UPS is configured to expect. **NOMBATTV** The nominal battery voltage. **NOMPOWER** The maximum power in Watts that the UPS is designed to supply. **HUMIDITY** The humidity as measured by the UPS. **AMBTEMP** The ambient temperature as measured by the UPS. **EXTBATTS** The number of external batteries as defined by the user. A correct number here helps the UPS compute the remaining runtime more accurately. **BADBATTS** The number of bad battery packs. **FIRMWARE** The firmware revision number as reported by the UPS. **APCMODEL** The old APC model identification code. **END APC** The time and date that the STATUS record was written. Logging the STATUS Information ------------------------------ If specified in the configuration file, the STATUS data will also be written to the system log file. Please note, that it would not normally be wise to write this data to a normal system log file as there is no mechanism in syslog() to rewind the file and hence the log file would quickly become enormous. However, in two cases, it can be very useful to use syslog() to write this information. The first case is to set up your syslog.conf file so that the data is written to a named pipe. In this case, normally not more than about 8192 bytes of data will be kept before it is discarded by the system. The second case is to setup your syslog.conf file so that the status data is sent to another machine, which presumably then writes it to a named pipe. Consequently, with this mechanism, provides a simple means of networking apcupsd STATUS information. Although we mention system logging of STATUS information, we strongly recommend that you use apcaccess or the CGI interface to get this information. The Shutdown Sequence and its Discontents ========================================= Shutdown Sequence ----------------- If you experienced so problems with the testing procedures, or if you are porting apcupsd to another system, or you are simply curious, you may want to know exactly what is going on during the shutdown process. The shutdown sequence is as follows: - apcupsd detects that there is a power problem and it calls ``/etc/apcupsd/apccontrol powerout``. By default this event does nothing, but it can be overridden to notify users, etc. - After the configured ``ONBATTERYDELAY``, apcupsd calls ``/etc/apcupsd/apccontrol onbattery``, which normally sends a message to all users informing them that the UPS is on batteries. - When one of the conditions listed below occurs, apcupsd issues a shutdown command by calling ``/etc/apcupsd/apccontrol doshutdown``, which should perform a shutdown of your system using the system shutdown(8) command. You can modify the behavior as described in `Customizing Event Handling`_. The conditions that trigger the shutdown can be any of the following: - Running time on batteries have expired (``TIMEOUT``) - The battery runtime remaining is below the configured value (``BATTERYLEVEL``) - The estimated remaining runtime is below the configured value (``MINUTES``) - The UPS signals that the batteries are exhausted. A shutdown could also be initiated if apcupsd detects that the batteries are no longer functioning correctly. This case, though very unusual, can happen at any time even if there is proper mains voltage, and ``/etc/apcupsd/apccontrol emergency`` is called. Just before initiating any shutdown through the apccontrol script, apcupsd will create the file /etc/apcupsd/powerfail. This file will be used later in the shutdown sequence to recall apcupsd after syncing of the disks to initiate a power off of the UPS. If the /etc/nologin file has not already been created, it will normally be created during the shutdown sequence to prevent additional users from logging in (see the ``NOLOGIN`` configuration directive). Even though apcupsd has requested the system to perform a shutdown, it continues running. - When the system signals apcupsd to do exit, it does so. This is part of the normal system shutdown (at least on Unix and Linux systems) and the exact time that apcupsd receives the termination signal depends on how the shutdown links (usually in /etc/rc.d) are set. Note that on Windows NT systems, apcupsd apparently continues to run as a Service even though the machine is "shutdown". - During the shutdown of the system after apcupsd has been forced to exit, one of the last things done by the system shutdown is to call the halt script, which is usually in /etc/rc.d/halt or /etc/rc.d/init.d/halt, or possibly in /sbin/init.d/rc.0 depending on your system. If apcupsd was properly installed, this standard halt script was modified to include a bit of new logic just before the final halt of the system. It first tests if the file /etc/apcupsd/powerfail exists, and if it does, it executes ``/etc/apcupsd/apccontrol killpower``. It is this last step that will cause apcupsd to be re-executed with the ``--killpower`` option on the command line. This option tells apcupsd to inform the UPS to kill the power. This final step is important if you want to ensure that your system will automatically reboot when the power comes back on. The actual code used on the Red Hat version is: :: # See if this is a powerfail situation. # ***apcupsd*** if [ -f /etc/apcupsd/powerfail ]; then # ***apcupsd*** echo # ***apcupsd*** echo "APCUPSD will now power off the UPS" # ***apcupsd*** echo # ***apcupsd*** /etc/apcupsd/apccontrol killpower # ***apcupsd*** echo # ***apcupsd*** echo "Please ensure that the UPS has powered off before rebooting" # ***apcupsd*** echo "Otherwise, the UPS may cut the power during the reboot!!!" # ***apcupsd*** echo # ***apcupsd*** fi # ***apcupsd*** The above code must be inserted as late as possible in the halt script. On many systems, such as Red Hat, all the disk drives were unmounted, then remounted read-only, thus permitting access to the /etc files and the apcupsd executable. If your system does not explicitly remount the disks, you must remount them in read-only mode in the code that you add. Examples of code fragments that do this can be found in the distributions/suse subdirectory of the source. If you are not able to insert the above code in your halt script because there is no halt script, or because your halt script calls the init program as some Unix systems do, you can either just forget about powering off the UPS, which means that your machine will not automatically reboot after a power failure, or there is yet another alternative, though not at all as satisfying as inserting code in the halt script. Only if you cannot insert the appropriate code in the halt script, when you start apcupsd, normally from the /etc/rc.d/init.d/apcupsd script, use the ``--kill-on-powerfail`` option. This will cause apcupsd to program the UPS to shutoff the power just before it (apcupsd) does the system shutdown. Please note that this is not the most ideal solution. Read on to understand why. A very important consideration is that you must set the EEPROM in your UPS so that it waits a sufficient time for the system to halt before it shuts off the UPS power. When using a USB connection, apcupsd automatically sets this value to 60 seconds. When using a serial connection to a SmartUPS, you must configure the value in the UPS EEPROM by hand using ``apctest``. Shutdown Problems ----------------- Obviously if your halt script is not properly modified, apcupsd will not be able to shut off the power to the UPS, and if the power returns before the batteries are exhausted your system will not automatically reboot. In any case, your machine should have been cleanly shut down. Master/Slave Shutdown --------------------- In master/slave configurations, however, the master cannot be 100 percent sure that the slaves have all shutdown before it performs the power off. To avoid this situation, be sure to configure any slaves (clients) to shut down before the master by setting different ``TIMEOUT``, ``BATTERYLEVEL``, or ``MINUTES`` parameters in the config file. Also, on a slave machine, you do not want to use the modified halt script since it will recall apcupsd, which will detect that it is a slave (i.e. no connection to the UPS) and will complain that it cannot do the killpower. This situation is not harmful just annoying and possibly confusing. One possible problem during shutdown can be caused by remnants of old versions. Please be sure to delete or rename all prior versions (/usr/local/sbin/apcupsd or /sbin/powersc). Startup ------- Normally, apcupsd is automatically started when your system is rebooted. This normally occurs because the startup script apcupsd is linked into the appropriate places in /etc/rc.d. On most Linux systems, there is a program called chkconfig(8) that will automatically link the startup script. This program is invoked by the ``make install`` scripts, or it is explicitly done for those systems that do not have chkconfig(8). If this is not the case, you can either link it in appropriately yourself or explicitly call it from your rc.local file. The appropriate manual way to startup apcupsd is by executing: :: /apcupsd start where *path* is normally /etc/rc.d or /etc/rc.d/init.d depending on your system. Using this script is important so that any files remaining around after a power failure are removed. Likewise, shutting down apcupsd should be done with the same script: :: /apcupsd stop Windows Considerations ---------------------- Please see the `Killpower under Windows`_ chapter of this manual for considerations pertaining to shutdown and killpower on Windows. .. include:: smartprotocol.rst NIS Network Server Protocol =========================== The NIS network server in apcupsd is capable of sending status and events data to clients that request it. The communication between the client and the server is performed over a TCP connection to the NISPORT (normally port 3551). The client opens a connection to the server and sends a message, to which the server will reply with one or more messages. Each message consists of a 2-byte length (in network byte order) followed by that many bytes of data. Both the client->server and server->client messages follow this format. apcupsd supports two commands, sent as the body of a message: #. "status" - The status command requests that the server send a copy of all status values, in the form displayed by apcaccess. After the client sends the "status" command, the server will reply with a series of messges, each one containing one line of apcaccess status data. The end of the command series is indicated by an empty message (length of 0). #. "events" - The events command operates the same as "status" except the server replies with lines from the log of recent events. As an example, the following bytes would be sent by a client to solicit the status: :: 0x00 0x06 0x73 0x74 0x61 0x74 0x75 0x73 The first two bytes are the data length (6) in network byte order. The 6 bytes of data that follow are the ASCII characters for "status". The server will respond to this command with a series of its own messages containing the status data. Apcupsd RPM Packaging FAQ ========================= **How do I build Apcupsd for platform xxx?** The apcupsd spec file contains defines to build for several platforms: RedHat 7.x (rh7), RedHat 8.0 (rh8), RedHat 9 (rh9), Fedora Core (fedora_core), RedHat Enterprise Linux and clones (rhel3 and rhel4), SuSE 9 & 10 (suse), and Mandrake (mdk). The package build is controlled by a define set at the beginning of the file. These defines basically just control the dependency information that gets coded into the finished rpm package. So while you could technically build a package without defining a platform, or with an incorrect platform, and have it install and run it would not contain correct dependency information for the rpm database. The platform define may be edited in the spec file directly (by default all defines are set to 0 or "not set"). For example, to build the RedHat 7.x package find the line in the spec file which reads :: %define rh7 0 and edit it to read :: %define rh7 1 Alternately you may pass the define on the command line when calling rpmbuild: :: rpmbuild -ba --define "build_rh7 1" apcupsd.spec rpmbuild --rebuild --define build_rh7 1" apcupsd-x.x.x-x.src.rpm **How do I control whether usb support gets built?** Up through version 3.12, by default standard serial port support was built and the apcupsd-std package was produced. The usb package pre-configured the configuration files for usb devices and installed a couple additional tools in /etc/apcupsd but the usb driver was built regardless. To get the usb package and support in those versions either set the :: %define usb 0 to :: %define usb 1 in the spec file directly or pass it to rpmbuild on the command line: :: rpmbuild -ba --define "build_rh7 1" --define "build_usb 1" apcupsd.spec With the release of 3.14 USB support is now considered standard and the apcupsd-std and apcupsd-usb packages are obsoleted in favor of a single apcupsd package configured for usb connected UPS's. The serial port driver is still built and can be configured accordingly after installation. If you are performing an upgrade it will of course not replace your current config file. The build directive: :: --define "build_usb 1" is no longer recognized. **What other defines are used?** There is a define for the initdir for the daemon control script. On RedHat or Mandrake systems this is set to /etc/rc.d/init.d/. On SuSE systems this is set to /etc/rc.d. You would only need to edit this if packaging for a platform that uses a different directory. A second define controls whether the Gnome monitoring application, new in the 3.14 release, is built. This application requires the Gtk2 version to be >= 2.4. If you want to build the apcupsd-gapcmon package add: :: --define "build_gapcmon 1" A third define controls whether the SNMP driver is built. If you want to build the net-snmp driver add: :: --define "build_snmp 1" **Can I supply packages for other platforms you do not publish?** Yes, there are tools provided for contributors to supply rpm packages for platforms for which support is provided in the spec file but for which the development team chooses not to release binary packages, usually due to lack of interest or lack of an available platform. Please see platforms/contrib/README in the source package. **I'm getting errors about not having permission when I try to build the packages. Do I need to be root?** No, you do not need to be root and, in fact, it is better practice to build rpm packages as a non-root user. Apcupsd's packages are designed to be built by a regular user but you must make a few changes on your system to do this. If you are building on your own system then the simplest method is to add write permissions for all to the build directory (/usr/src/redhat/). To accomplish this execute one of the following commands as root depending on your distribution, RedHat, SuSE or Mandriva, respectively: :: chmod -R 777 /usr/src/redhat chmod -R 777 /usr/src/packages chmod -R 777 /usr/src/RPM If you are working on a shared system where you can not use the method above then you need to recreate the /usr/src/redhat (or other) directory tree with all of it's subdirectories inside your home directory. Then create a file named :: .rpmmacros in your home directory (or edit the file if it already exists) and add the following line: :: %_topdir /home/myuser/redhat Credits ======= .. image:: ./thanks.png The success of apcupsd is due to the many people that helped in development, testing and in many other ways. Thank all the developers that worked hard to make APCUPSD one of the best piece of software for UPS management. Contributors ------------ **Current Code Maintainer and Project Manager** Adam Kropelin (adam@kroptech.com) **RPM Packager** D\. Scott Barninger **CGI and HTML fixer** William King (wrking@dadaboom.com) **Former Project Manager** Kern Sibbald (kern@sibbald.com) **Project Starter and Former Code Maintainer** Andre Hedrick (andre@linux-ide.org) **Former Code Maintainer and Project Manager** Riccardo Facchetti (riccardo@master.oasi.gpa.it) **Serial Communications** Andre Hedrick (andre@linux-ide.org) **2.0 User's Manual** Eric S. Raymond (esr@thyrsus.com) **Alpha Port** Kern Sibbald (kern@sibbald.com) J. Rochate (jrochate@ualg.pt) testing and machine loan **Caldera** John Pinner (john@clocksoft.com) **HP-UX Port** Carl Erhorn (Carl_Erhorn@hyperion.com) Robert K Nelson (rnelson@airflowsciences.com) **SOLARIS Port** Carl Erhorn (Carl_Erhorn@hyperion.com) **OpenBSD Port** Devin Reade (gdr@gno.org) **NetBSD Port** Neil Darlow (neil@darlow.co.uk) **Win32 Port** Kern Sibbald (kern@sibbald.com) Paul Z. Stagner **WEB Interfaces** Kern Sibbald (kern@sibbald.com) Joseph Acosta (joeja@mindspring.com) Apcupsd License --------------- Apcupsd is licensed under the terms of the GNU General Public License, version 2 (GPLv2). The full text of this license may be found in the COPYING file at the top of the source tree and online at http://www.gnu.org/licenses/gpl-2.0.html. Source files are copyright of their specific author(s), as noted in the files. :: This program is free software; you can redistribute it and/or modify it under the terms of version 2 of the GNU General Public License as published by the Free Software Foundation. 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, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA. Other Open Source Licenses -------------------------- Apcupsd incorporates the libusbhid library which is subject to the following copyright and license: :: Copyright (c) 1999 Lennart Augustsson All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .. |image4| image:: ./commlost.png .. |image5| image:: ./online.png .. |image6| image:: ./onbatt.png .. |image7| image:: ./charging.png .. |date| date:: %B %e, %Y .. |time| date:: %T .. |(C)| unicode:: 0xA9 .. copyright sign .. |TM| unicode:: U+2122 .. trademark sign apcupsd-3.14.14/doc/manual/multimon.png000066400000000000000000000167031274230402600177260ustar00rootroot00000000000000PNG  IHDR^l PLTERcyiIDATx]mr렒EfLߘ Vla>A#!8r b;4 {z~==:^:^:^:^:^ sO{NJJJJ-9.mrOLxvrz;^)ίJRz;^)d_B)ɻ4uwq>0}V9MT$mIˉb=t'$`7~ͯc>,ǔO9N!o>[sP_PsLI B &D?+k 6w $`FSRs<߷s f&,KA6Tުa틟6C1*N.4 :}"\ Xj` 씅-ӘsZW;-yQ^3Ăq2kz}3 @zz P eZ9^3)ץy]-PG&_wU,g9͂'H$q)}L90(k°F<Q[t.hCF:4Q;(.z,W2ePE rDYBxX jsV4LDi53)3!Edũ{lСwůxq=A@H11< )/I^ND R 1js%~e824Ȅm((ǬǨz{5+dTP`L5`Lчtan`L <bgqM6I2&2CLL{.T'_Թ~d{k5 ALtFY$JtOXX ~xyʱ\~I%XʼZZA&jo$V^i"Pxż1 qO_0 >ȅ0Z~>~r2c?d/$8L/cω$̯$+/#:.1 =ўIQXJ)7~H8z]ْ#in;GQbs7oH4_&să8KgF _`sc(Wpvʆny%K"{BXk09i&&e`x 2ʊZF,Zc/0ţ06L`2;ϪfƱ|ʑq+%c wuQDw`K"1 Ř9$?=_yW¤% _1?ȗIN)k^ |բǒ5M~ywůȲU;ὃCϲ);c&t ͺLz_B|=-2 cu~~9crS&`RU ^"Q1^ &)V9,)ƗCeSWNb9~eǯ V9 P^ u5VoBA{ٳ~)++p~t gZW2H N6is>eD5`)(YH _j QV. ϥ>eJH G#O4y*V吣M~EeLbIQuJMYGI.UŝYK;`9iGVŪ  <81ʄZu7ðdb%JpKFDܻa_+YU&p(R+l"၅i”4&f@3Jplt`0zi7',RX TU g~9zy~g(442Xi.q|L.!7B#!sdFNyz~i?/O/?~ɔ nqEN\@ ENt+l @SzIge$>ÜMy</߄[T*8d(K!T̅׊^?ͯtM~E;sj _5(k^Yn+rUi1_!ҦjڦWucpqKrU4i{_S{:G 0k~ڟI8Wq(UM N.hMoTES伃l3\\ ]DNAv)5WW%{Z^zv6ep A옘;{zqgᘖqFKJ$ljL8 {zE̿.D rpFuM۫.\6~F)rkS=i2~`c|[#$@!`Eq \IOe S; /V>Kϑ]S8[:qA9lh y.:kʎ^hh{_?eaKrZҋ6Ni a2^{pRM~i Q5-\QA%.(S_\&dVX +DtVM 뷎_AM̉ä$V!Z B/@:_\ #>ԍ.V z/U؅s-6-|GF!ij/d꤁ ΂_8q^1a'm^2 7`g2#fJ:KV B gU@/Ru_'-Q'*uSW_#Z+Ջ؂_xwA׳ܞ;OYSү_n0Q4&J S*Í'"8$H_9C9\]¡,LId ]+?X)hRz;O$h඄ <b⟺'*!xUk .OzVxx ('ՇI:2;K#b`D'0̯l ' K1A:'&dprIU ݏ{_ĂD 'z;~9ҁ_9LBKW1VٰE\@a:bʧS(n̩R:@(_ڤKΘC_ TA$aN_c{vs*7sM~NjUf[.e_$lKǜhSZSR'Tjy"BYn)m@KE_vd l]*oe*Q+P..zNJi07T|"}~|z{y2^|A?jsA?.;M9?Y% lI+Hx} H-1x#/ aů*huXS {z+x)^˚_+|hѪx\^78x 85^[xIϯ{6m5lvD9-P:݁ s!sGXx<^|nU x-;WDbs[? i2F#=Ƌ#.z$ZGuK & B7ϮK{DCVh.՛xmt.kPX"I3^#I.33(g&YeXG̈ /F xï7}sW_[xIY"F`e5y¯udoK=1mnx&ׇAx`r=/]kp m'5IoI1>`ċCv[Ï{zkxSo5V/bCp'^7G G3_c/UCѐTޜjͿ<ޜsm/9RۇGm PX֖}8yh9>\և/024 Zx5^ҐW֌DZ ZӠo0%/]d|c|/J [%2rA-m|/m`=C)5[FB]H}pC_b_x݋g#ug;u~Wǫxu:^?ǫk_^v:^Wǫxu:^Wix[xʙmY'$2Žވ'2ל'|7Ou.]D^Ot);>W9«x3ފ'*[Sׯ'Z5,K4X{≊W7E EDE)ȉvXx%^8=쇍Oq^x"7 2k0[sx"ևb밊-MDVezaP .y XOd`sͽ܉p'^],ERZE)h1,  5z/1De"_ulo'ZUYpoջw} F >d-MDp1ZܲӇT78HixZ,OtUL^{'2yڌ'z3íUꉶ'*?Lt^;'re;;u [x [x])QNבC-JTLBDlu4B ^;' CDG㢤lLu/D/poyvO>I|>DfQm DG+Z_)y<u<6J,{{>o|^8%*x9T.C느:^=DW'z-ȯWǫxu:^oëkkkk^=DxVxVxVxVxVxVxVxVxVxVxVxVxV/6pCh=IENDB`apcupsd-3.14.14/doc/manual/onbatt.png000066400000000000000000000002401274230402600173360ustar00rootroot00000000000000PNG  IHDRRPLTEbKGDoѓIENDB`apcupsd-3.14.14/doc/manual/publishdoc000077500000000000000000000003461274230402600174320ustar00rootroot00000000000000#!/bin/sh sftp -b - web.sourceforge.net <<-END cd /home/groups/a/ap/apcupsd/htdocs -mkdir manual cd manual -rm * progress put manual.pdf put manual.html put *.png ln manual.pdf apcupsd.pdf ln manual.html index.html END apcupsd-3.14.14/doc/manual/smartprotocol.rst000066400000000000000000001246461274230402600210240ustar00rootroot00000000000000APC smart protocol ================== The APC UPS protocol was originally analyzed by Pavel Korensky with additions from Andre H. Hendrick beginning in 1995, and we want to give credit for good, hard work, where credit is due. After having said that, you will see that Steven Freed built much of the original apcupsd information file. The start of this chapter of the apcupsd manual in HTML format was pulled from the Network UPS Tools (NUT) site (http://www.networkupstools.org/ups-protocols/apcsmart.html). It has been an invaluable tool in improving apcupsd, and I consider it the Bible of APC UPS programming. In the course of using it, I have added information gleaned from apcupsd and information graciously supplied by APC. Description ----------- Here's the information on the elusive APC smart signaling protocol used by their higher end units (Back-UPS Pro, Smart-UPS, Matrix-UPS, etc). What you see here has been collected from a variety of sources. Some people analyzed the chatter between PowerChute and their hardware. Others sent various characters to the UPS and figured out what the results meant. RS-232 differences ------------------ Normal 9 pin serial connections have TxD on 3 and RxD on 2. APC's smart serial ports put TxD on pin 1 and RxD on pin 2. This means you go nowhere if you use a normal straight through serial cable. In fact, you might even power down the load if you plug one of those cables in. This is due to the odd routing of pins - DTR and RTS from the PC usually wind up driving the on/off line. So, when you open the port, they go high and \*poof\* your computer dies. The Smart Protocol ------------------ Despite the lack of official information from APC, this table has been constructed. It's standard RS-232 serial communications at 2400 bps/8N1. Don't rush the UPS while transmitting or it may stop talking to you. This isn't a problem with the normal single character queries, but it really does matter for multi-char things like "@000". Sprinkle a few calls to usleep() in your code and everything will work a lot better. The following table describes the single character "Code" or command that you can send to the UPS, its meaning, and what sort of response the UPS will provide. Typically, the response shown below is followed by a newline (\\n in C) and a carriage return (\\r in C). If you send the UPS a command that it does not recognize or that is not available on your UPS, it will normally respond with "NA" for "not available", otherwise the response is given in the "Typical results" column. +---------+------------+----------------+--------------------------------------+ |Character|Meaning |Typical results |Other info | +=========+============+================+======================================+ |^A |Model string|SMART-UPS 700 |Spotty support for this query on older| | | | |models | +---------+------------+----------------+--------------------------------------+ |^N |Turn on UPS |n/a |Send twice, with 1.5s delay between | | | | |chars. Only on 3rd gen SmartUPS and | | | | |Black Back-UPS Pros | +---------+------------+----------------+--------------------------------------+ |^Z |Permitted |*long string* |Gives the EEPROM permitted values for | | |EEPROM | |your model. See `EEPROM Values`_ for | | |Values | |details. | +---------+------------+----------------+--------------------------------------+ |A |Front panel |Light show + |Also sounds the beeper for 2 seconds | | |test |"OK" | | +---------+------------+----------------+--------------------------------------+ |B |Battery |27.87 |Varies based on current level of | | |voltage | |charge. See also Nominal Battery | | | | |Voltage. | +---------+------------+----------------+--------------------------------------+ |C |Internal |036.0 |Units are degrees C | | |Temperature | | | +---------+------------+----------------+--------------------------------------+ |D |Runtime |!, then $ |Runs until battery is below 25% (35% | | |calibration | |for Matrix) Updates the 'j' values. | | | | |Only works at 100% battery charge. Can| | | | |be aborted with a second "D" | +---------+------------+----------------+--------------------------------------+ |E |Automatic |336 |Writable variable. Possible values: | | |self test | | | | |interval | |- "336" (14 days) | | | | |- "168" (7 days) | | | | |- "ON " (at power on) note extra space| | | | |- "OFF" (never) | +---------+------------+----------------+--------------------------------------+ |F |Line |60.00 |Units are Hz. Value varies based on | | |frequency | |locality, usually 50/60. | +---------+------------+----------------+--------------------------------------+ |G |Cause of |O |Possible values: | | |last | | | | |transfer | |- R (unacceptable utility voltage rate| | |to battery | | of change) | | | | |- H (high utility voltage) | | | | |- L (low utility voltage) | | | | |- T (line voltage notch or spike) | | | | |- O (no transfers since turnon) | | | | |- S (transfer due to U command or | | | | | activation of UPS test from front | | | | | panel) | | | | |- NA (transfer reason still not | | | | | available; read again) | +---------+------------+----------------+--------------------------------------+ |I |Measure-UPS |FF |*not decoded yet* | | |Alarm enable| | | +---------+------------+----------------+--------------------------------------+ |J |Measure-UPS |0F,00 |*not decoded yet* | | |Alarm status| | | +---------+------------+----------------+--------------------------------------+ |K |Shutdown |OK or * |Send twice with > 1.5s delay between | | |with grace | |chars. Older units send "*" instead of| | |period (no | |"OK". Length of grace period is set | | |return) | |with Grace Period command. UPS will | | | | |remain off and NOT power on if utility| | | | |power is restored. | +---------+------------+----------------+--------------------------------------+ |L |Input line |118.3 |Value varies based on locality. Does | | |voltage | |not always read 000.0 on line failure.| +---------+------------+----------------+--------------------------------------+ |M |Maximum line|118.9 |This is the max voltage since the last| | |voltage | |time this query was run. | +---------+------------+----------------+--------------------------------------+ |N |Minimum line|118.1 |This is the min voltage since the last| | |voltage | |time this query was run. | +---------+------------+----------------+--------------------------------------+ |O |Output |118.3 |Also see on battery output voltage. | | |voltage | | | +---------+------------+----------------+--------------------------------------+ |P |Power load |023.5 |Relative to capacity of the UPS. | | |% | | | +---------+------------+----------------+--------------------------------------+ |Q |Status flags|08 |Bitmapped, see `status bits`_ below | +---------+------------+----------------+--------------------------------------+ |R |Turn dumb |BYE |Only on 3rd gen SmartUPS, SmartUPS | | | | |v/s, BackUPS Pro. Must send enter | | | | |smart mode command to resume comms. | +---------+------------+----------------+--------------------------------------+ |S |Soft |OK |Command executes after grace period. | | |shutdown | |UPS goes online when power returns. | | | | |Only works when on battery. | +---------+------------+----------------+--------------------------------------+ |U |Simulate |!, then $ |See `Alert messages`_ section for info| | |power | |on ! and $. | | |failure | | | +---------+------------+----------------+--------------------------------------+ |V |Old firmware|"GWD" or "IWI" |See `Interpretation of the Old | | |revision | |Firmware Revision`_ | +---------+------------+----------------+--------------------------------------+ |W |Self test |OK |Tests battery, like pushing button on | | | | |the front panel. Results stored in "X"| +---------+------------+----------------+--------------------------------------+ |X |Self test |OK |Possible values: | | |results | | | | | | |- OK = good battery | | | | |- BT = failed due to insufficient | | | | | capacity | | | | |- NG = failed due to overload | | | | |- NO = no results available (no test | | | | | performed in last 5 minutes) | +---------+------------+----------------+--------------------------------------+ |Y |Enter smart |SM |This must be sent before any other | | |mode | |commands will work. See also turn dumb| | | | |command to exit smart mode. | +---------+------------+----------------+--------------------------------------+ |Z |Shutdown |n/a |Send twice with > 1.5s delay between | | |immediately | |chars. UPS switches load off | | | | |immediately (no grace period) | +---------+------------+----------------+--------------------------------------+ |a |Protocol |*long string* |Returns three main sections delimited | | |info | |by periods: | | | | | | | | | |- Protocol version | | | | |- Alert messages (aka async notifiers)| | | | |- Valid commands | +---------+------------+----------------+--------------------------------------+ |b |Firmware |50.9.D |See `Interpretation of the New | | |revision | |Firmware Revision`_. | | | | | | | | | |Decoding the example: | | | | | | | | | |- 50 = SKU (variable length) | | | | |- 9 = firmware revision | | | | |- D = country code (D=USA, | | | | | I=International, A=Asia, J=Japan, | | | | | M=Canada) | +---------+------------+----------------+--------------------------------------+ |c |UPS local |UPS_IDEN |Writable variable. Up to 8 letter | | |id | |identifier for keeping track of your | | | | |hardware. | +---------+------------+----------------+--------------------------------------+ |e |Return |00 |Writable variable. Minimum battery | | |threshold | |charge % before UPS will return online| | | | |after a soft shutdown. Possible | | | | |values: | | | | | | | | | |- 00 = 00% (UPS turns on immediately) | | | | |- 01 = 15% | | | | |- 02 = 25% | | | | |- 03 = 90% | +---------+------------+----------------+--------------------------------------+ |f |Battery |099.0 |Percentage of battery charge remaining| | |level % | | | +---------+------------+----------------+--------------------------------------+ |g |Nominal |024 |The battery voltage that's expected to| | |battery | |be present in the UPS normally. This | | |voltage | |is a constant based on the type, | | | | |number, and wiring of batteries in the| | | | |UPS. Typically "012", "024" or "048". | +---------+------------+----------------+--------------------------------------+ |h |Measure-UPS |042.4 |Percentage. Only works on models with | | |ambient | |Measure-UPS SmartSlot card. | | |humidity (%)| | | +---------+------------+----------------+--------------------------------------+ |i |Measure-UPS |00 |Bitmapped hex variable. Mapping: | | |dry contacts| | | | | | |- 10 = contact 1 | | | | |- 20 = contact 2 | | | | |- 40 = contact 3 | | | | |- 80 = contact 4 | +---------+------------+----------------+--------------------------------------+ |j |Estimated |0327: |Value is in minutes. Terminated with | | |runtime | |a colon. | +---------+------------+----------------+--------------------------------------+ |k |Alarm delay |0 |Writable variable. Controls behavior | | | | |of UPS beeper. Possible values: | | | | | | | | | |- 0 = 5 second delay after power fail | | | | |- T = 30 second delay | | | | |- L = alarm at low battery only | | | | |- N = no alarm | +---------+------------+----------------+--------------------------------------+ |l |Low transfer|103 |Writable variable. UPS goes on battery| | |voltage | |when voltage drops below this point. | +---------+------------+----------------+--------------------------------------+ |m |Manufacture |11/29/96 |Format may vary by country (MM/DD/YY | | |date | |vs DD/MM/YY). Unique within groups of | | | | |UPSes (production runs) | +---------+------------+----------------+--------------------------------------+ |n |Serial |WS9643050926 |Unique for each UPS | | |number | | | +---------+------------+----------------+--------------------------------------+ |o |Nominal |115 |Expected output voltage when running | | |Output | |on batteries. May be a writable | | |Voltage | |variable on 220/230/240 VAC units. | +---------+------------+----------------+--------------------------------------+ |p |Shutdown |020 |Seconds. Writable variable. Sets the | | |grace delay | |delay before soft shutdown completes. | | | | |(020/180/300/600) | +---------+------------+----------------+--------------------------------------+ |q |Low battery |02 |Minutes. Writable variable. The UPS | | |warning | |will report a low battery condition | | | | |this many minutes before it runs out | | | | |of power | +---------+------------+----------------+--------------------------------------+ |r |Wakeup delay|000 |Seconds. Writable variable. The UPS | | | | |will wait this many seconds after | | | | |reaching the minimum charge before | | | | |returning online. (000/060/180/300) | +---------+------------+----------------+--------------------------------------+ |s |Sensitivity |H |Writable variable. Possible values: | | | | | | | | | |- H = highest | | | | |- M = medium | | | | |- L = lowest | | | | |- A = autoadjust (Matrix only) | +---------+------------+----------------+--------------------------------------+ |t |Measure-UPS |80.5 |Degrees C. Only works on models with | | |ambient | |the Measure-UPS SmartSlot card. | | |temperature | | | +---------+------------+----------------+--------------------------------------+ |u |Upper |132 |Writable variable. UPS goes on battery| | |transfer | |when voltage rises above this point. | | |voltage | | | +---------+------------+----------------+--------------------------------------+ |v |Measure-UPS |4Kx |Firmware information for Measure-UPS | | |firmware | |board | +---------+------------+----------------+--------------------------------------+ |x |Last battery|11/29/96 |Writable variable. Holds whatever the | | |change date | |user set in it. Eight characters. | +---------+------------+----------------+--------------------------------------+ |y |Copyright |\(C) APCC |Only works if firmware letter is | | |notice | |later than O | +---------+------------+----------------+--------------------------------------+ |z |Reset to |CLEAR |Resets most variables to initial | | |factory | |factory values except identity or | | |settings | |battery change date. Not available on | | | | |SmartUPS v/s or BackUPS Pro. | +---------+------------+----------------+--------------------------------------+ |\+ |Capability |*various* |Cycle forward through possible | | |cycle | |capability values. UPS sends | | |(forward) | |afterward to confirm change to EEPROM.| +---------+------------+----------------+--------------------------------------+ |\- |Capability |*various* |Cycle backward through possible | | |cycle | |capability values. UPS sends | | |(backward) | |afterward to confirm change to EEPROM.| +---------+------------+----------------+--------------------------------------+ |@nnn |Shutdown and|OK or * |UPS shuts down after grace period with| | |return | |delayed wakeup after nnn tenths of an | | | | |hour plus any wakeup delay time. Older| | | | |models send "*" instead of "OK". | +---------+------------+----------------+--------------------------------------+ |0x7f |Abort |OK |Use to abort @, S, K | | |shutdown | | | +---------+------------+----------------+--------------------------------------+ |~ |Register #1 |*see below* |See `Register 1`_ table | +---------+------------+----------------+--------------------------------------+ |' |Register #2 |*see below* |See `Register 2`_ table | +---------+------------+----------------+--------------------------------------+ |0 |Battery | |See `Resetting the UPS Battery | | |constant | |Constant`_ | +---------+------------+----------------+--------------------------------------+ |4 |*???* | |Prints 35 on SmartUPS 1000 | +---------+------------+----------------+--------------------------------------+ |5 |*???* | |Prints EF on SmartUPS 1000 | +---------+------------+----------------+--------------------------------------+ |6 |*???* | |Prints F9 on SmartUPS 1000 | +---------+------------+----------------+--------------------------------------+ |7 |DIP switch | |See `Dip switch info`_ | | |positions | | | +---------+------------+----------------+--------------------------------------+ |8 |Register #3 |*see below* |See `Register 3`_ table | +---------+------------+----------------+--------------------------------------+ |9 |Line quality|FF |Possible values: | | | | | | | | | |- 00 = unacceptable | | | | |- FF = acceptable | +---------+------------+----------------+--------------------------------------+ |> |Number of | |SmartCell models return number of | | |external | |connected packs. Other models return | | |battery | |value set by the user (use +/-). | | |packs | | | +---------+------------+----------------+--------------------------------------+ |[ |Measure-UPS |NO,NO |Degrees C. Writable Variable. Possible| | |Upper temp | |values: 55, 50, 45, ..., 05. | | |limit | |Use +/- to change values. | +---------+------------+----------------+--------------------------------------+ |] |Measure-UPS |NO,NO |Degrees C. Writable Variable. Possible| | |lower temp | |values: 55, 50, 45, ..., 05. | | |limit | |Use +/- to change values. | +---------+------------+----------------+--------------------------------------+ |{ |Measure-UPS |NO,NO |Percentage. Writable Variable. | | |Upper | |Possible values: 90, 80, 70, ..., 10. | | |humidity | |Use +/- to change values. | | |limit | | | +---------+------------+----------------+--------------------------------------+ |} |Measure-UPS |NO,NO |Percentage. Writable Variable. | | |lower | |Possible values: 90, 80, 70, ..., 10. | | |humidity | |Use +/- to change values. | | |limit | | | +---------+------------+----------------+--------------------------------------+ |**Matrix-UPS and Symmetra Commands** | +---------+------------+----------------+--------------------------------------+ |^ |Run in |BYP, INV, ERR |If online, "BYP" response is received | | |bypass mode | |as bypass mode starts. If already in | | | | |bypass, "INV" is received and UPS goes| | | | |online. If UPS can't transfer, "ERR" | | | | |received | +---------+------------+----------------+--------------------------------------+ |< |Number of |000 |Count of bad packs connected to the | | |bad battery | |UPS | | |packs | | | +---------+------------+----------------+--------------------------------------+ |/ |Load current|*nn.nn* |True RMS load current drawn by UPS | +---------+------------+----------------+--------------------------------------+ |\\ |Apparent |*nnn.nn* |Output load as percentage of full | | |load power | |rated load in VA. | +---------+------------+----------------+--------------------------------------+ |^V |Output | |Writable variable. Possible values: | | |voltage | | | | |selection | |- A = automatic (based on input tap) | | | | |- M = 208 VAC | | | | |- I = 240 VAC | +---------+------------+----------------+--------------------------------------+ |^L |Front panel | |Writable variable. Possible values: | | |language | | | | | | |- E = English | | | | |- F = French | | | | |- G = German | | | | |- S = Spanish | | | | |- 1 = *unknown* | | | | |- 2 = *unknown* | | | | |- 3 = *unknown* | | | | |- 4 = *unknown* | +---------+------------+----------------+--------------------------------------+ |w |Run time | |Writable variable. Minutes of runtime | | |conservation| |to leave in battery (UPS shuts down | | | | |"early"). Possible values: | | | | | | | | | |- NO = disabled | | | | |- 02 = leave 2 minutes of runtime | | | | |- 05 = leave 5 minutes | | | | |- 08 = leave 8 minutes | +---------+------------+----------------+--------------------------------------+ Dip switch info --------------- === ====== ===================================================================== Bit Switch Option when bit=1 === ====== ===================================================================== 0 4 Low battery alarm changed from 2 to 5 mins. Autostartup disabled on SU370ci and 400 1 3 Audible alarm delayed 30 seconds 2 2 Output transfer set to 115 VAC (from 120 VAC) or to 240 VAC (from 230 VAC) 3 1 UPS desensitized - input voltage range expanded 4-7 Unused at this time === ====== ===================================================================== Status bits ----------- This is probably the most important register of the UPS, which indicates the overall UPS status. Some common things you'll see: - 08 = On line, battery OK - 10 = On battery, battery OK - 50 = On battery, battery low - SM = Status bit is still not available (retry reading) === ============================================================================ Bit Meaning when bit=1 === ============================================================================ 0 Runtime calibration occurring (Not reported by Smart UPS v/s and BackUPS Pro) 1 SmartTrim (Not reported by 1st and 2nd generation SmartUPS models) 2 SmartBoost 3 On line (this is the normal condition) 4 On battery 5 Overloaded output 6 Battery low 7 Replace battery === ============================================================================ Alert messages -------------- These single character messages are sent by the UPS any time there is an Alert condition. All other responses indicated above are sent by the UPS only in response to a query or action command. ========= ============= ======================================================== Character Meaning Description ========= ============= ======================================================== ! Line Fail Sent when the UPS goes on-battery, repeated every 30 seconds until low battery condition reached. Sometimes occurs more than once in the first 30 seconds. $ Return from UPS back on line power. Only sent if a ! has been sent line fail previously. % Low battery Sent to indicate low battery. Not implemented on SmartUPS v/s or BackUPS Pro models \+ Return from Sent when the battery has been recharged to some level low batt Only sent if a % has been sent previously. ? Abnormal Sent for conditions such as "shutdown due to overload" condition or "shutdown due to low battery capacity". Also occurs within 10 minutes of turnon. = Return from Sent when the UPS returns from an abnormal condition abnormal where ? was sent, but not a turn-on. Not implemented on condition SmartUPS v/s or BackUPS Pro models. \* About to Sent when the UPS is about to switch off the load. No turn off commands are processed after this character is sent. Not implemented on SmartUPS v/s, BackUPS Pro, or 3rd generation SmartUPS models. # Replace Sent when the UPS detects that the battery needs to be battery replaced. Sent every 5 hours until a new battery test is run or the UPS is shut off. Not implemented on SmartUPS v/s or BackUPS Pro models. & Check alarm Sent to signal that temp or humidity out of set limits. register Also sent when one of the contact closures changes for fault state. Sent every 2 minutes until the alarm conditions (Measure-UPS) are reset. Only sent for alarms enabled with I. Cause of alarm may be determined with J. Not implemented on SmartUPS v/s or BackUPS Pro. \| Variable Sent whenever any EEPROM variable is changed. Only change in supported on Matrix UPS and 3rd generation SmartUPS EEPROM models. ========= ============= ======================================================== Register 1 ---------- All bits are valid on the Matrix UPS. SmartUPS models only support bits 6 and 7. Other models do not respond. === ============================================================================ Bit Meaning when bit=1 === ============================================================================ 0 In wakeup mode (typically lasts < 2s) 1 In bypass mode due to internal fault (see `Register 2`_ or `Register 3`_) 2 Going to bypass mode due to command 3 In bypass mode due to command 4 Returning from bypass mode 5 In bypass mode due to manual bypass control 6 Ready to power load on user command 7 Ready to power load on user command or return of line power === ============================================================================ Register 2 ---------- Matrix UPS models report bits 0-5. SmartUPS models only support bits 4-6. SmartUPS v/s and BackUPS Pro report bits 4, 6, 7. Unused bits are set to 0. Other models do not respond. === ============================================================================ Bit Meaning when bit=1 === ============================================================================ 0 Fan failure in electronics, UPS in bypass 1 Fan failure in isolation unit 2 Bypass supply failure 3 Output voltage select failure, UPS in bypass 4 DC imbalance, UPS in bypass 5 Battery is disconnected 6 Relay fault in SmartTrim or SmartBoost 7 Bad output voltage === ============================================================================ Register 3 ---------- All bits are valid on the Matrix UPS and 3rd generation SmartUPS models. SmartUPS v/s and BackUPS Pro models report bits 0-5. All others report 0-4. State change of bits 1,2,5,6,7 are reported asynchronously with ? and = messages. === ============================================================================ Bit Meaning when bit=1 === ============================================================================ 0 Output unpowered due to shutdown by low battery 1 Unable to transfer to battery due to overload 2 Main relay malfunction - UPS turned off 3 In sleep mode from @ command (maybe others) 4 In shutdown mode from S command 5 Battery charger failure 6 Bypass relay malfunction 7 Normal operating temperature exceeded === ============================================================================ Interpretation of the Old Firmware Revision ------------------------------------------- The Old Firmware Revision is obtained with the "V" command, which gives a typical response such as "GWD" or "IWI", and can be interpreted as follows: :: Old Firmware revision and model ID String for SmartUPS & MatrixUPS This is a three character string XYZ where X == Smart-UPS or Matrix-UPS ID Code. range 0-9 and A-P 1 == unknown 0 == Matrix 3000 5 == Matrix 5000 the rest are Smart-UPS and Smart-UPS-XL 2 == 250 3 == 400 4 == 400 6 == 600 7 == 900 8 == 1250 9 == 2000 A == 1400 B == 1000 C == 650 D == 420 E == 280 F == 450 G == 700 H == 700XL I == 1000 J == 1000XL K == 1400 L == 1400XL M == 2200 N == 2200XL O == 3000 P == 5000 where Y == Possible Level of Smart Features, unknown??? G == Stand Alone T == Stand Alone V == ??? W == Rack Mount where Z == National Model Use Only Codes D == Domestic 115 Volts I == International 230 Volts A == Asia ?? 100 Volts J == Japan ?? 100 Volts Interpretation of the New Firmware Revision ------------------------------------------- :: New Firmware revision and model ID String in NN.M.L is the format where NN == UPS ID Code. 12 == Back-UPS Pro 650 13 == Back-UPS Pro 1000 52 == Smart-UPS 700 60 == SmartUPS 1000 72 == Smart-UPS 1400 where NN now Nn has possible meanings. N == Class of UPS 1n == Back-UPS Pro 5n == Smart-UPS 7n == Smart-UPS NET n == Level of intelligence N1 == Simple Signal, if detectable WAG(*) N2 == Full Set of Smart Signals N3 == Micro Subset of Smart Signals where M == Possible Level of Smart Features, unknown??? 1 == Stand Alone 8 == Rack Mount 9 == Rack Mount where L == National Model Use Only Codes D == Domestic 115 Volts I == International 230 Volts A == Asia ?? 100 Volts J == Japan ?? 100 Volts M == North America 208 Volts (Servers) EEPROM Values ------------- Upon sending a ^Z, your UPS will probably spit back approximately 254 characters something like the following (truncated here for the example): :: #uD43132135138129uM43229234239224uA43110112114108 .... It looks bizarre and ugly, but is easily parsed. The # is some kind of marker/ident character. Skip it. The rest fits this form: - Command character - use this to select the value - Locale - use 'b' to find out what yours is (the last character), '4' applies to all - Number of choices - '4' means there are 4 possibilities coming up - Choice length - '3' means they are all 3 chars long Then it's followed by the choices, and it starts over. Matrix-UPS models have ## between each grouping for some reason. Here is an example broken out to be more readable: :: CMD DFO RSP FSZ FVL u D 4 3 127 130 133 136 u M 4 3 229 234 239 224 u A 4 3 108 110 112 114 u I 4 3 253 257 261 265 l D 4 3 106 103 100 097 l M 4 3 177 172 168 182 l A 4 3 092 090 088 086 l I 4 3 208 204 200 196 e 4 4 2 00 15 50 90 o D 1 3 115 o J 1 3 100 o I 1 3 230 240 220 225 o M 1 3 208 s 4 4 1 H M L L q 4 4 2 02 05 07 10 p 4 4 3 020 180 300 600 k 4 4 1 0 T L N r 4 4 3 000 060 180 300 E 4 4 3 336 168 ON OFF CMD == UPSlink Command. u = upper transfer voltage l = lower transfer voltage e = return threshold o = output voltage s = sensitivity p = shutdown grace delay q = low battery warning k = alarm delay r = wakeup delay E = self test interval DFO == (4)-all-countries (D)omestic (I)nternational (A)sia (J)apan (M) North America - servers. RSP == Total number possible answers returned by a given CMD. FSZ == Max. number of field positions to be filled. FVL == Values that are returned and legal. Programming the UPS EEPROM -------------------------- There are at this time a maximum of 12 different values that can be programmed into the UPS EEPROM. They are: ======= ======================================================================== Command Meaning ======= ======================================================================== c The UPS Id or name x The last date the batteries were replaced u The Upper Transfer Voltage l The Lower Transfer Voltage e The Return Battery Charge Percentage o The Output Voltage when on Batteries s The Sensitivity to Line Quality p The Shutdown Grace Delay q The Low Battery Warning Delay k The Alarm Delay r The Wakeup Delay E The Automatic Self Test Interval ======= ======================================================================== The first two cases (Ident and Batt date) are somewhat special in that you tell the UPS you want to change the value, then you supply 8 characters that are saved in the EEPROM. The last ten item are programmed by telling the UPS that you want it to cycle to the next permitted value. In each case, you indicate to the UPS that you want to change the EEPROM by first sending the appropriate query command (e.g. "c" for the UPS ID or "u" for the Upper Transfer voltage. This command is then immediately followed by the cycle EEPROM command or "-". In the case of the UPS Id or the battery date, you follow the cycle command by the eight characters that you want to put in the EEPROM. In the case of the other ten items, there is nothing more to enter. The UPS will respond by "OK" and approximately 5 seconds later by a vertical bar (\|) to indicate that the EEPROM was changed. apcupsd-3.14.14/doc/manual/status.png000066400000000000000000000177571274230402600174170ustar00rootroot00000000000000PNG  IHDRN|;KPLTE111ŦIDATxMq`ګloro m36~Z,?$R{LIQ,XWm8!pCԇS~ǘӫ/PQ]pjZ]pjZ]pjZ]pjZ]ЅMσ)V/9=l ^Uxԇԇԇԇ sهJbmH[rn0}Nt"979'y6/yu7{sLs*+#٘ћc8=7?do-fNCilfga^zrr} E-r")R1-rbߍ4EsZd>ז<_,X- 6GLYۑ2'6C7j=q_4|6W8=i'cD©`nB2&wZ8L}/!;[~N_vӏ6qby}/}d^R3p'r:ēr?.N u(9ۏOgקY8i~}*qv}:iPn޹5c$맜MfW '䞑)5iccm/^*%'PM;{d!S6d1gDGE# kfa}(r*(] -s ,]tR88RҭdIe1q)4PγoJv툓bfɹ<ӡyfT Ɂ{bnW): xh|i M9g9i=]-s/2,pr[yd+QΉܹg8eRO!^_7-p=sklgeN9S_݉}R|\pYsqWIY9㡂AsqkFO^laJT>[Ͻs8y d׊E+AX'+!?f8mx|\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p\p܌ӫ܁V܋Rs˜pjZ]pjZ]pjZ]pjZ]pjZ]8U~BL]B%^7xgSSS~h6˿%צCnm2_{gȦ q 4z;a\Bֳ$4INIྷa+sb6'b39D!oCuNqZQ1++pDCQN ڌcVD< NG9I8:5-ؤk~[g?t9i+8M&q߷.&99/0pb^H y=ބȔ.Ir=W2f8i\ 8M'"V)a5q9=<'7IQÍt%>O}*3%>T8i8шK9>5ӄ֟SDŽsF$i}N>L|d| {N^i}a:[ft'rJ=I"dv)oB)NTRO\U^*c?Arm }.mdt; 6gO!ۛ8r(ڼ~S-N %N .4}mGT|VHRpo32d ?p:_d(溎>)^Of|FIJƁ&e'H|R3Ya4eXpShC}F)' ,Ɓ%:SNVR姙'9?*/O x~9Ym=t5ܧT..4đSFST;IUT!'d;^Q~?krz  ˒?{Si?:N}N"tSeg5$-t,نJ/m8pS?b|ίi)ԧBp>etL6g > pđSe~ЏXNg9Gf |*~98> 圆Ns$p'pąX,58iYNdc:X{3q271o:&eNF58[0i. xxgJp+kS&CzU礏`4R?EI̽OHNy/g`OdivgroB̽}eBϭt>={zN/:DTUn&}{Nzx'=n%;rJ )8k}[N4V Nk8SByqYp3Jg_9 qtfN6vNiܜa(No#VNs֨hөf#('SLa28SZlrJ8Qt8>eϯHa<3|fep=O7闋yB~N/888888^N| $.¨sYf&='&o|{''sUb p:ɇ7$4s_Ed_Kp)Uk4_}koT3UOLc}4oS=l ~a~ kӥ5׆#ߑSj`ENv qb.8888888˩4!M̭+}y~^Ӻ\kB\}(\(֏~,Ӈ82W$VImAd!i/X|qbM~ 19 P8]I5RFY5NLSIڑ ~)}3s <Nvi4ZӞO N1WCz88888%3NQS_Ϥ w'188]Sh\5O:D>?jkUne}אqm84G}Mw)'tO} &O)35NSTהק ֈ0?jkr8d>1yNkN8?*5YEF?KO\u N7'p'p'p'pNNNNN‰59 CњslI򖜮]e'9 #'kYǜN Ӝ.ʯA6ُ׸> 4`>ʜ 8D#N81eix.#sp:MkؘB\nCxGWO?pp [SX?t d59!3*,'sl|' %NrIś8(֥8=R(8l_ȍiTQgksc67s*b0KBr C;OfK`N楜pI|LqsqS0/q5^^T#`˸Vls5s4"v}~ 3Ii<:fuiCŠ's ܟOZ3}]G91uwtE4T'J¼ ȉ.D k9lX8Oa])TʜE\_ܷ{FK$'V>[v$/ɯ!קXwsz_Ή_t}z1srOOV}GNƘkpxD'gm0X'9388888}y*,("18b.T? BP|󟮬O4?q]?esF\p_?epq){Nt'ނP6'sYb'=Oԧ ^/p:iប͌Iuo|s N'9Sٺ>FcNn{s>';q'b_cYINaԌFQo= #N#Z):hOb/ٍ lKӦN2 ilӺ pr|qY?X|8^ 8n8|>O 2N[Foџ888\NNNNNz9Dvz}q4̜1M9vx;U /+m8~CsߔO}q%e' _N'l?)9I_9̜18'wJ쟝8-ϛ9cp^wOq}}SRqrks4oMq}Z>11mCT?"nܤDӏ(+mЯGpp N} N} N} N} N} N} N} N} N} N} N} N} N} N} N} N} N} N}qф܁V܋Rs˜pjZ]pjZ]pjZ]pjZ]pjZ]8 5?.pznR pCԇS>N} 'f- tS zvq*v kZD[N/FN.d[B Ԍ!ws5lV9T^\Hk'k 6p"<>R^^_ kՇvg`ӿh}r-dXS'38EWY뜴*ku]⅋p}ҽ#ʈ۸UYCԇS>N}8!pCԇS>N}8!pCԇS>N}8N zrfkӫG_i}˷/pjZ_Z8= J}Q27,en N{8y4Ӳ|??S>|M쿓Ԑgn/wqonŌx~?$sm :Z[2c]dل{Β_urqbN=Hrsj"'aٵ]Nڦ9Nf;'W&q-mbTRr_1{8ٜp}<6'9IZOR?o,޷j4zod ?bʦk+W__OK~:IMp9LIP#?qx}v'>Qv~)SzƜ> vwm"#8iyS Lx}vq/VFpdYOaԇԧ3't)2zgv-jO}:J}BW׬C<6]ק'ER2XޯljMlG1(WѮ SX6P38~-jw}:J} WdLF̵Pdj]f9Na,t>?>O6i8d2|hQۢvէ'tIG1ߤ9Yb{l3665#>z3#9[}TV>UO}>!ԧ>n'3~{?kOHmL2%vhSIo8zT;tSֹN%Ѹ)7&eu*K^.t}m9龱koSM?>mK~ciN ƩO8!pCԇS+^?AO7q7˵OS}swiw|S'2"֓wISXgX8l9l}P⅝?uɏgCUnpuY?8*Y?Q9QGp:ۜ?QIʵox{8U?Q/?yL&wwS:"ךmWoӧ Y!ijCȧև^z{WFԽ?xP5FJw~]wϽ?1lۋWSiSloEV܁N}8!pCԇS>N}8!pCԇS>N}h-pZCi=tCi=tCi=tCi=tCi=tsgE9A 8!pCԇS>N}8!pCԇS`-)QrIENDB`apcupsd-3.14.14/doc/manual/thanks.png000066400000000000000000000371761274230402600173610ustar00rootroot00000000000000PNG  IHDRqVVPLTE~fffJJJeEBBBL9:::i666#2I0!"*:I.fᚚ&&& )^^_epVFbvvv""%NKN>nc 2]ZH`v5Jmu>;l@>AZ!!&D5*r0-N R1Lh>Z~":FFFf`1?>D1>V~&f\v,*z VB0B nJR0&GXP1?R2fhUN.TR'5=nUv e/{pv7Nr.D\PTx#1v VRrhV^ &S*:T" {04XXXl"":  =Lv"E (/Ba2?4o>*pIf<=FrR[>UP$1n ZNZD,X;2[X]:) &<)E~z.zt6,^2Ff2 t~.zi \3"FV fNn&j(*H'G&6P:Rx: r^ b2=]w*>Zr Y)2W3"*FjvR e> o9z* yT=2 v.>\V\Jd 82,!*J jVbT:=lR=>Z b(#&t#+G(0/2>&_=YCBFO"">Nf bYjv{v84F l& z*:%CCN|b5v"04Kj6%"&fF&Vh`rjBBC^. t*,L&*PPPN i>> ~ ~C;mFFvCJ{Bvvvj&:O>" !3FkD;^rb `6 r bKGDK ;2IDATx}}\T癶4B!|4'! 6EFe!n邱C'tP,]݂ӼkAe 0qN(1d7"ɀK`$k1/cg>pΙ3gs\9I!£: "M>mUz7| ӂ(Oc Q\$%%`KIuEͯ5cHr&gx S|G<\9!uŭ6.x>.ƉE^^q< R)2^(>~G~p#B[R2\ԡ}_W|L .bbQXOI.8ʕ["beW{)q²l5)7$K [ЬH$~+W0$ǃ!͛[P:pBTEC(~L$nI 9޿u'4[$i0n6UP'=@~_u@rM! }>&z?sD(͏ y6CE4k<V}^IHFq!|9l4_IJpj4 vzP*뒒BpS -Ȭ lP hL~z@[ЂMg.^<лW.YH-GGS^Q]-Rvu*i2lgQG!!L&ZKSR|g7|ŅnBCM*R&ܸH`L>AVKG4}7#!ؐLBqVp'1rurBsv.z/LQG>z't;FG[z1ᨆֵKn:5xZ|a^`:C& b L7K;@i\XY@|lh(PdYeb*>:NϦ̦1K{+yy/+1#SO WG \L~)cIKѬ~ :!=T)!-,u4a2n*,&q¿+WBTS{w39g_)kc؊'/@ܯRlq=}}) : AmY>D{Q/r!V=2۲ʯZm9NDtlWi0^=|q7L*8skB[ 9fS|<@q78KY,ŝ0*4nIqn. үH$(>VְqBL9v#v W1I).U|!p' hZ:gLN&[_-o$[u$Ge6 .:Ù"4")NE?ξ`='>XpU N!*~E1\,FE$ҨB&6Ȭ{u|h2iq8q8>8 YY}`??0iQ 6?U$Iwu~oKZWT0T.$,)-E^R_"K^zTqF]Fe|GnD jw()W #^^nQQtI 97|C}qsiϣ [DRJϋ}ˇ8!@ܢ&O?n)ɸ@aחv\v9Nmef(E_^rO/8ѻ=@6/^u0\8/G yssvn6pKXFdbEVk.?x96g3+vp\E y@\jJ|S.Jhao#U(B~^av2ν}Oq"~_%F-ϱIŻIdz})#2PR{JLdk}MJK !]oUI .t 6>.2}RqP8^i1O6qudLK{c!,7D(9Nqpj g`ae+CtxuZFOōܔUWV<ɉ(ϱ~JcJHCV&*g(??ņ\g?Z~*.h7DOڀR([ e_R3r'^.T3HAglFǁfhN}Mv,.lC$- |(`p~Q\qǁ8ULkg[$ccchf[/%3Sa>sRݒNB"9n";i%aIeXm{@WF_5NC~e;grmޖN> U}&,oa/6ɂP&*q iL9;ƈc2q}r gLxLNÌ^#l Q[_1qp_o)bWY YYVxFPF<,9Q!~O(KoM ]-J[wot^S9ui^7 QFXmm.~z x ٤o:}ի^u3d{5CY0t/5/ }3*5LgLV"ȱdpֈz'sPR18tW/8Q(Y_!H1ӳ|#Nr7bI̮Dq\qEbΌBoO_ĸ%#&ͳ2.8NAݑoBƣ(MITo"ďgC~ eFM)/כ&0Ѫ2Vj-C)d2.[^pCZm~~~ywYselʪyao/jXWܛjk}.:&7ׅBOk{-<;, cx̟} A7oF  1S1btD(=Y&&6r,zn X%Dž pirtMY r|:kJH[RR cx*ZSZԷ9T7p 9xSOKQPV[ tڴi跓y 4jW!ȇjv M78ӆ!P8>@׾=͕DdK!) t7 $+9558[à'~q?U')Br ~?Ĵ^L_ ^8%q?L`m >E'4/WxDo#S䀮 w(jOZMG\rW;H>,}YOjY!ON&ubP$(>gHTPcv] 5)ۺZ*Tv8~]u^:JKهv i|D/ cc٪lEqFX><Ù b6CQlk[Fd'&6d &`LB WLC}qp> 9Yr1a9騝d j琠?tCCT:P} 8TJ1tlܵr8BJ4oFl<wJu2(aVVPCݻwwڲc߾\@x(EqTkX/$x$*:9|&*-«O-[VwTRmkZrzδؕP涒~]UV괁7jȊrtg:"d= |N8gגAòS̀lJEMRA6=-S{?s4q $8kNx_EV/.vŭ2ZG_8KQQG 87SOc8sݩO>ڔ/Oygjj;*\ڇYm/N 6iĔ{͝ӄ_qyz10q %U)ٔ52򍦆7NqPxY9.(ӯ) ,]g#odB`S]0$* xB%KXU5|bEcaБK}'Q<2ˏ-y_#:j8jgp዗ &WJQ t<3|qPl&# .$S<݆WZ_׫{5"rzVrGx! T%DbzO-ZNj5G&):q5UXx rg2L&?]&S|?"gcj!nsr1KRvݻs9o'Igq7y:NpL۽"j)x*O0]q;v 7sEQvV[oA$ i1)D@U}Y%ݕ Vzs N"IZ^0Ƀ[Uψ?$gI,,y%%8XM".A\je'_m%\1(ֱSL|$S\r>CUd!*u<#Ei9i_E-Ĕ=6s604 ߓTs"-g,f)Ըm}sx y $D?'uG hI@-1&3D%Hq1 UѓARG?|)ye9oҥI *~E^O ̏su,!ap˂v@i$D*"w)w9 6hsBGp|JURo'fEqEpn9 077\Zqs0q_Grj +o r*1|(w'ݓ\"1mG+-qD|W&/$4ϏsvY3ꢀg\8 %l < TbD/f!r~B&z-9pPumD9> U,wqu[NC9rEqqb8IW(*G#1A9NQ*r>yi'mǥ8.{z?37qp\Upz xcHیtf)z>yyÏU^E$''hߐVހ[F[L*D H_qI ^rSSլ*gIUxDWa K @ȧ@b"Ў,TY,/LE" {we{[ =ɯ򕲘Wq-gkNXh8?Bt<9N Pj]&nb GONܛaHe"8y5QpXtvA%6g[#ӲKb ҡ+|Q0 G˹~Px\jR\p|^l1"P|Ga0^ZȁynE.Ø_c)Q?!:.nW*d'M!>^ck^>EzT㼯S«TWym~U‹¡)=N{84E>,^AǎUꢜB $O~W|jVsuYQV:*qvbx͛7-3;~[c+_eῠ}"{n_gBܠ!ċms݄ɯ\%~+Lγ\%kYyeVq!_ akJ0O_r/=GeqMڒK,:E4[CIsƕ t/ϻ|{<#Snq݁6hʹ:mf߽u/x:AF<}'Lf7_?_T4e{x79m%(eɐs~ΚUIxu꩕x]ɓiQXg~vdUqH8Q; pu~%_g4_M̯W`5Vt-T%o.+1=qײGbcȎ{姄8-Y$qūpB1Y9I^/e(5r0k''C6kN]8ľzyR "XS0lfɊNt+ӓMbO<_߷mKVt|>O@<Iưb9lVyIF f_*<Qp]ik_KTc%j_B!ߎAVà 9]@Q}Dt|W,j˔yUL%6fhhcvTLʾ24^-~2b 9tDvAhzq#;ǂF8!V`QK vuj }˟-a2.HQyHO׉ojqL';؏8Sq+++ѫY?KX'!9^~70 SkO`(\XR_FF܆6Κged*"#s`QY侠n T1nIDM9 L@'rC{1g&r FM 2fijG@\̓Q85j@Y.溡q=Tr=Og^'Z/B8ໜ? h(PRVɒUF7U7&"#Η晗1ɢR>M"fÄxW U_G'r?=vB}']9 |Ǒx kR[~uhn[߻p<,z`K1Sƫ *mj(tE+{bFo< Q< &_oK#HBѝ x奛, d'U]  o'Wisz\]zmyZF'O >ԶE۵mrxQmP1EAJΎ__6F?-8.[0%NBt3ǛyI hW==fYy>~=O;OD?;^eI@v q|eJ7quÕAw oQ|Ar\h_{fZ>eLV_ZRʸq0##Å7MTgJ^/Tg}ee:Az55oYr& } ;x{CFfsoʃШQy'~*6F.͛z팃oMwdA6y[Ÿ-:6L)W&^ody%' e_kbx2]/n#bIK?{ߐs^mlQmHMsKK\ų2R4ESjϭ{zNO`/kG<j(D!w`EEF#5 YO9}S(j{\!S6\h4hƛ7#s#{bRlږgjXȓU,Ka~p10^,_mB\:(U2/wcclȧ'"[@_gNawIOgeiS$Fڃ>_ j$bF|'V^-ٴ 0)wѫZ;֫}ua >j(os۶M}ZLaB+hϾT= ک0b76<|ïP7W&( {NU1&9C5[U8XL/U8e>w4}KG$WDuq ʏQ㙙ˆ[,%^rTW/[z ;^^}oaNJ*U)4q=!N|Q.~c!]L ʴ۷ک C bwa.nY~0\ȍ`Q'ćSr3`f>C> Tt䗛E@^;HL4|jsjjC| yd-gsP]~`dDTJF܃_ڸqyE`8JV6pn d쁩WIkc侥UrоȊb?SSn?g>/c Հ'AÇPoEgQ|+}?g>w]OJĈ?FOyÏChٱs£8xnSOfn{➻y}qߗMB}m ";O(q}';s|ǭ{˯q_p=8C~P8J^<Cٻ}>җ>x|K_}xm-xC`CzzލO~6M;ΐ.5nqX_ٻ?[%L}S|mG;8߹t|w>&8Nn;h]=XH? [< n%c_6N.C;;օ{8/xG ZH ޹7k!V@B(? 1g-rmIENDB`apcupsd-3.14.14/doc/manual/wininstall6.png000066400000000000000000000113561274230402600203330ustar00rootroot00000000000000PNG  IHDRSPLTE{AJIDATxђ*9_صJO> DbcuF60ճ !v7]@w o+AP[읿STÍ:}'KBy@u exMKtTHWޕGqm~Tʦ:TҼP@*PdEOEE@U"_y UwgDzT+oJJuNu~?]j)Jڪ D@""\ """""""""""""nFv kk*О1nc'\@(zR”.0*K~樚TFX׫{?{rNەr*ԯ+aJڿ{tAT: )o|SJiYQ =d{ S ZҦ &&YPmh0yڳH@{V*(㝵fԅ@֡{_M@[C;([C(^u FfN졶P0kuTۭ-)nZy~oE]y@WʶhE&׊cyW6 ,4F lsE@Wh鴉tb'Q30^O_>P*{Oг ? I@7'$Lȿ(d#(~&8w< m:K>KTv6o[N@6ƹBoQ6x}}DyP>Ah7EPX(\6S q>Ƭ?^3%uDGn3 T=Z@t">`}/Sm:к@ovPA=u:|^RE(^˧T(*RuflP ,C+PzTvW*/Gx&S^Z-PTL6!AdM&-0?6T@*t<ֵP"F/WJ {'ֵ0j23лXj>=uo[*p:2bZyn un{!V~oЃVBV//c]y= o[%PB1PU f{(fжTz:PLg!W" 4O$ ywyz:g(7F7)P'g8~V{>qJV^:<0AM d&&Z=N)t; A8SKzGR׍F*<pqJ˭yZ4[4~‰mP"01JR8XQ&J=6lCݭ(qJbKpzɽ{̉=7h8%@4݃@ VDB BYm VlKW|" %Y(hdt*[R~>:ncrOXU m88Ħ.@Z(lE@21B.;1 .(yM)ZS&6OFzې. xb`} ^NŸɷwNPa.rmX*P)2|u p"p0}>%(,"Ӥb eEξ4@cPs@ \VeŅB]BI({KF@>4}J@Z]@j*\Lۇo]5M+"Ѕ:Kak],Ԟ;O ͹n yzԤZSifkߧ ==L@ ,"ęB/-UjIRꑷjZ&qd @@AzRCNznGr<*PL*U%Yաj:"/?E@s*C 㕊ɧt-{}w%l@EzNȫVD3h7&Sng@Shw*\`Mw^2.6Bmjzą[k^w%p)6}Jyn МO)j|ϽNtE@)Ej|I{I4F5S1Є{"ߘOI̴vuȽ4 >%9w`&oM@i3h=BqE-P\MPKsDRH|G44.א}J@G"gdr 1D_IԍP,B b\625$L?xt=(@''5iTO-2 zMtF5$L/_u8ہމCOC$$/&P8)pynf OU*P=Q\jNև_DYc?98/MP-͙zJ5G0/DiTWETe=#Ћye:9΃Te=2@3+:&-T Λh}OֵP[Lc2";| 4[j؅)UBtT34ܙxZsr}zJ@cqW% E`,Wd" Y(BqU7M7>$}yYcqXco nb#"7?cjG (,bڗ9LRw l74}_N&z\?}2XC=5}PoC IARO|Pqʝc飀:͘A=ОM@&EcաSON͉Լq@+Ϸ~ ,t`]Ϻczм AQLz 肞j:%v@'*lPFu=P}bZN7Lk4]f;_.aPARs+qQ>U<)9eИ]d}q DZb7\sii&}_k\+V}{%jv^5GP~m<3nEMkjT Ig-Tx@%3󫀪O As+<4]0Z>Cj@~I6'nЄ tQBӘ}h 4'-aO"mî:*zED[J ?SmocW@IEEEEǢW#ԝM㘻pi^'D@SZj0Ub1^"FQ0Mc.H}]*O5L >J@S-wh!*_@5_**hJ1P{fE >J@SZ:tj;')ѥ'"f IG hJd"""""g ~0G0gfP)h<Q41]76+n$:45]Im ߺnChK~+D7JѼ%3M5tyzTB?"`T\nChKщ}<] 5u) MZG*OP%"zE@E@}m-`#" 5s;t;s#֢#1uʅ5J@ h PaHC@e- n: 'VJ@v Ju(&Pjzro@uJZhV ^aF6L4oqF@I8""""""""""""]]gﰁ_VS8ҌIENDB`apcupsd-3.14.14/examples/000077500000000000000000000000001274230402600151415ustar00rootroot00000000000000apcupsd-3.14.14/examples/Makefile000066400000000000000000000005641274230402600166060ustar00rootroot00000000000000topdir:=.. SUBDIRS = include $(topdir)/autoconf/targets.mak TARGETS = hid-ups hid-set client megaclient newslave upsapm \ smartsim snoopdecode SRCS = $(foreach target,$(TARGETS),$(target).c) all-targets: client megaclient newslave upsapm smartsim snoopdecode $(TARGETS): %: $(call SRC2OBJ,%.c) $(APCLIBS) $(LINK) # Include dependencies -include $(DEPS) apcupsd-3.14.14/examples/SmartUPS1400.snmp000066400000000000000000000420001274230402600200170ustar00rootroot00000000000000enterprises.apc.products.hardware.ups.upsIdent.upsBasicIdent.upsBasicIdentModel.0 = "SMART-UPS 1400" enterprises.apc.products.hardware.ups.upsIdent.upsBasicIdent.upsBasicIdentName.0 = "UPS_IDEN" enterprises.apc.products.hardware.ups.upsIdent.upsAdvIdent.upsAdvIdentFirmwareRevision.0 = "70.11.I" enterprises.apc.products.hardware.ups.upsIdent.upsAdvIdent.upsAdvIdentDateOfManufacture.0 = "11/11/99" enterprises.apc.products.hardware.ups.upsIdent.upsAdvIdent.upsAdvIdentSerialNumber.0 = "QS9946315184" enterprises.apc.products.hardware.ups.upsBattery.upsBasicBattery.upsBasicBatteryStatus.0 = batteryNormal(2) enterprises.apc.products.hardware.ups.upsBattery.upsBasicBattery.upsBasicBatteryTimeOnBattery.0 = Timeticks: (0) 0:0 enterprises.apc.products.hardware.ups.upsBattery.upsBasicBattery.upsBasicBatteryLastReplaceDate.0 = "11/11/99" enterprises.apc.products.hardware.ups.upsBattery.upsAdvBattery.upsAdvBatteryCapacity.0 = Gauge32: 100 enterprises.apc.products.hardware.ups.upsBattery.upsAdvBattery.upsAdvBatteryTemperature.0 = Gauge32: 39 enterprises.apc.products.hardware.ups.upsBattery.upsAdvBattery.upsAdvBatteryRunTimeRemaining.0 = Timeticks: (468000) 1:1 enterprises.apc.products.hardware.ups.upsBattery.upsAdvBattery.upsAdvBatteryReplaceIndicator.0 = noBatteryNeedsReplacing(1) enterprises.apc.products.hardware.ups.upsBattery.upsAdvBattery.upsAdvBatteryNumOfBattPacks.0 = 0 enterprises.apc.products.hardware.ups.upsBattery.upsAdvBattery.upsAdvBatteryNumOfBadBattPacks.0 = 0 enterprises.apc.products.hardware.ups.upsInput.upsBasicInput.upsBasicInputPhase.0 = 1 enterprises.apc.products.hardware.ups.upsInput.upsAdvInput.upsAdvInputLineVoltage.0 = Gauge32: 231 enterprises.apc.products.hardware.ups.upsInput.upsAdvInput.upsAdvInputMaxLineVoltage.0 = Gauge32: 231 enterprises.apc.products.hardware.ups.upsInput.upsAdvInput.upsAdvInputMinLineVoltage.0 = Gauge32: 228 enterprises.apc.products.hardware.ups.upsInput.upsAdvInput.upsAdvInputFrequency.0 = Gauge32: 50 enterprises.apc.products.hardware.ups.upsInput.upsAdvInput.upsAdvInputLineFailCause.0 = selfTest(9) enterprises.apc.products.hardware.ups.upsOutput.upsBasicOutput.upsBasicOutputStatus.0 = onLine(2) enterprises.apc.products.hardware.ups.upsOutput.upsBasicOutput.upsBasicOutputPhase.0 = 1 enterprises.apc.products.hardware.ups.upsOutput.upsAdvOutput.upsAdvOutputVoltage.0 = Gauge32: 231 enterprises.apc.products.hardware.ups.upsOutput.upsAdvOutput.upsAdvOutputFrequency.0 = Gauge32: 50 enterprises.apc.products.hardware.ups.upsOutput.upsAdvOutput.upsAdvOutputLoad.0 = Gauge32: 21 enterprises.apc.products.hardware.ups.upsOutput.upsAdvOutput.upsAdvOutputCurrent.0 = Gauge32: 0 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigNumDevices.0 = 4 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.deviceIndex.1 = 1 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.deviceIndex.2 = 2 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.deviceIndex.3 = 3 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.deviceIndex.4 = 4 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.deviceName.1 = Hex: 44 65 76 69 63 65 20 31 00 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.deviceName.2 = Hex: 44 65 76 69 63 65 20 32 00 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.deviceName.3 = Hex: 44 65 76 69 63 65 20 33 00 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.deviceName.4 = Hex: 44 65 76 69 63 65 20 34 00 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.vaRating.1 = 0 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.vaRating.2 = 0 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.vaRating.3 = 0 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.vaRating.4 = 0 enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.acceptThisDevice.1 = yes(1) enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.acceptThisDevice.2 = yes(1) enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.acceptThisDevice.3 = yes(1) enterprises.apc.products.hardware.ups.upsConfig.upsBasicConfig.upsBasicConfigDeviceTable.upsBasicConfigDeviceEntry.acceptThisDevice.4 = yes(1) enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigRatedOutputVoltage.0 = 230 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigHighTransferVolt.0 = 253 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigLowTransferVolt.0 = 196 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAlarm.0 = timed(1) enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAlarmTimer.0 = Timeticks: (0) 0:0 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigMinReturnCapacity.0 = 0 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigSensitivity.0 = high(4) enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigLowBatteryRunTime.0 = Timeticks: (12000) 0:0 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigReturnDelay.0 = Timeticks: (0) 0:0 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigShutoffDelay.0 = Timeticks: (2000) 0:0 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigUpsSleepTime.0 = Timeticks: (0) 0:0 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigSetEEPROMDefaults.0 = noSetEEPROMDefaults(1) enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigBattExhaustThresh.0 = Timeticks: (0) 0:0 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigPassword.0 = " " enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.1 = 1 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.2 = 2 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.3 = 3 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.4 = 4 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.5 = 5 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.6 = 6 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.7 = 7 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.8 = 8 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldIndex.9 = 9 enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.1 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigRatedOutputVoltage enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.2 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigHighTransferVolt enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.3 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigLowTransferVolt enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.4 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAlarmTimer enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.5 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigMinReturnCapacity enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.6 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigLowBatteryRunTime enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.7 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigReturnDelay enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.8 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigShutoffDelay enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldOID.9 = OID: enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigBattExhaustThresh enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.1 = "Not Configurable" enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.2 = "253, 264, 271, 280 Vac" enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.3 = "188, 196, 204, 208 Vac" enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.4 = "0 , 30 seconds" enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.5 = "00, 15, 50, 90 percent" enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.6 = "02, 05, 07, 10 minutes" enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.7 = "000, 060, 180, 300 seconds" enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.8 = "020, 180, 300, 600 seconds" enterprises.apc.products.hardware.ups.upsConfig.upsAdvConfig.upsAdvConfigAllowedSetTable.apcUpsConfigEntry.apcUpsConfigFieldValueRange.9 = "Not Configurable" enterprises.apc.products.hardware.ups.upsControl.upsBasicControl.upsBasicControlConserveBattery.0 = noTurnOffUps(1) enterprises.apc.products.hardware.ups.upsControl.upsAdvControl.upsAdvControlUpsOff.0 = noTurnUpsOff(1) enterprises.apc.products.hardware.ups.upsControl.upsAdvControl.upsAdvControlRebootUps.0 = noRebootUps(1) enterprises.apc.products.hardware.ups.upsControl.upsAdvControl.upsAdvControlUpsSleep.0 = noPutUpsToSleep(1) enterprises.apc.products.hardware.ups.upsControl.upsAdvControl.upsAdvControlSimulatePowerFail.0 = noSimulatePowerFailure(1) enterprises.apc.products.hardware.ups.upsControl.upsAdvControl.upsAdvControlFlashAndBeep.0 = noFlashAndBeep(1) enterprises.apc.products.hardware.ups.upsControl.upsAdvControl.upsAdvControlTurnOnUPS.0 = noTurnOnUPS(1) enterprises.apc.products.hardware.ups.upsControl.upsAdvControl.upsAdvControlBypassSwitch.0 = noBypassSwitch(1) enterprises.apc.products.hardware.ups.upsTest.upsAdvTest.upsAdvTestDiagnosticSchedule.0 = biweekly(2) enterprises.apc.products.hardware.ups.upsTest.upsAdvTest.upsAdvTestDiagnostics.0 = noTestDiagnostics(1) enterprises.apc.products.hardware.ups.upsTest.upsAdvTest.upsAdvTestDiagnosticsResults.0 = ok(1) enterprises.apc.products.hardware.ups.upsTest.upsAdvTest.upsAdvTestLastDiagnosticsDate.0 = "05/04/1998" enterprises.apc.products.hardware.ups.upsTest.upsAdvTest.upsAdvTestRuntimeCalibration.0 = noPerformCalibration(1) enterprises.apc.products.hardware.ups.upsTest.upsAdvTest.upsAdvTestCalibrationResults.0 = ok(1) enterprises.apc.products.hardware.ups.upsTest.upsAdvTest.upsAdvTestCalibrationDate.0 = "Unknown" enterprises.apc.products.hardware.ups.upsComm.upsCommStatus.0 = ok(1) enterprises.apc.products.hardware.miniSNMPadapter.serialPort.serialPort2.serialPort2Config.serialPort2Mode.0 = passthrough(2) enterprises.apc.products.hardware.miniSNMPadapter.serialPort.serialPort2.serialPort2Control.setPulseOnTXD.0 = noSetPulseOnTXD(1) enterprises.apc.apcmgmt.mconfig.mconfigNumTrapReceivers.0 = 4 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.trapIndex.1 = 1 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.trapIndex.2 = 2 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.trapIndex.3 = 3 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.trapIndex.4 = 4 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.receiverAddr.1 = IpAddress: 0.0.0.0 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.receiverAddr.2 = IpAddress: 0.0.0.0 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.receiverAddr.3 = IpAddress: 0.0.0.0 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.receiverAddr.4 = IpAddress: 0.0.0.0 enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.communityString.1 = "public" enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.communityString.2 = "public" enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.communityString.3 = "public" enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.communityString.4 = "public" enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.severity.1 = information(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.severity.2 = information(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.severity.3 = information(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.severity.4 = information(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.acceptThisReceiver.1 = yes(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.acceptThisReceiver.2 = yes(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.acceptThisReceiver.3 = yes(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.acceptThisReceiver.4 = yes(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.receiveTrapType.1 = powernet(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.receiveTrapType.2 = powernet(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.receiveTrapType.3 = powernet(1) enterprises.apc.apcmgmt.mconfig.mconfigTrapReceiverTable.mconfigTrapReceiverEntry.receiveTrapType.4 = powernet(1) enterprises.apc.apcmgmt.mconfig.mconfigBOOTPEnabled.0 = no(2) enterprises.apc.apcmgmt.mconfig.mconfigClock.mconfigClockDate.0 = "05/04/1998" enterprises.apc.apcmgmt.mconfig.mconfigClock.mconfigClockTime.0 = "16:02:54" enterprises.apc.apcmgmt.mcontrol.mcontrolRestartAgent.0 = continueCurrentAgent(2) enterprises.apc.apcmgmt.mtrapargs.mtrapargsInteger.0 = 6766 enterprises.apc.apcmgmt.mtrapargs.mtrapargsIpAddress.0 = IpAddress: 0.0.0.0 enterprises.apc.apcmgmt.mtrapargs.mtrapargsString.0 = Hex: 00 enterprises.apc.apcmgmt.mtrapargs.mtrapargsGauge.0 = Gauge32: 10620 enterprises.apc.apcmgmt.mtrapargs.mtrapargsTimeTicks.0 = Timeticks: (0) 0:0 enterprises.apc.apcmgmt.mfiletransfer.mfiletransferStatus.mfiletransferStatusLastTransferResult.0 = lastFileTransferResultNotAvailable(2) enterprises.apc.apcmgmt.mfiletransfer.mfiletransferConfig.mfiletransferConfigSettings.mfiletransferConfigSettingsFilename.0 = "Unknown" enterprises.apc.apcmgmt.mfiletransfer.mfiletransferConfig.mfiletransferConfigTFTP.mfiletransferConfigTFTPServerAddress.0 = "0.0.0.0" enterprises.apc.apcmgmt.mfiletransfer.mfiletransferConfig.mfiletransferConfigFTP.mfiletransferConfigFTPServerAddress.0 = "0.0.0.0" enterprises.apc.apcmgmt.mfiletransfer.mfiletransferConfig.mfiletransferConfigFTP.mfiletransferConfigFTPServerUser.0 = "apc" enterprises.apc.apcmgmt.mfiletransfer.mfiletransferConfig.mfiletransferConfigFTP.mfiletransferConfigFTPServerPassword.0 = "apc" enterprises.apc.apcmgmt.mfiletransfer.mfiletransferControl.mfiletransferControlInitiateFileTransfer.0 = doNotInitiateFileTransfer(1) End of MIB apcupsd-3.14.14/examples/client.c000066400000000000000000000053321274230402600165660ustar00rootroot00000000000000/* * Client test program for apcnetd * This program reads from standard input and passes the * commands to the apcupsd network information server. * It then prints to stdout the responses from the server. * * Build it with: cc -I../include client.c ../src/lib/libapc.a -o client * * Execute: ./client [host[:port]] [command] * reads commands from STDIN if command is not present * if command is present, it is sent to the daemon, * the output is retrieved, then the program exits. * * The two commands currently (Apr 2001) accepted by the * server are "status" and "events". * * For additional examples of code, see cgi/upsfetch.c */ #include "apc.h" #ifdef HAVE_NISLIB /* Default values, can be changed on command line */ #define SERV_TCP_PORT 3551 #define SERV_HOST_ADDR "127.0.0.1" void handle_client(FILE *fp, int sockfd, char *cmd); void error_abort(const char *msg) { fprintf(stderr, msg); exit(1); } int main(int argc, char *argv[]) { int sockfd, port; char host[200]; char msg[200], *p, *cmd; strcpy(host, SERV_HOST_ADDR); port = SERV_TCP_PORT; if (argc > 1) { strcpy(host, argv[1]); /* get host from command line */ p = strchr(host, ':'); if (p) { *p++ = 0; port = atoi(p); } } if (argc > 2) { cmd = argv[2]; } else { cmd = NULL; } if ((sockfd = net_open(host, NULL, port)) < 0) { sprintf(msg, "client: tcp_open for host %s on %d failed\n", host, port); error_abort(msg); } handle_client(stdin, sockfd, cmd); /* do it all */ net_close(sockfd); exit(0); } /* * Read the contents of the FILE *fp, write each line to the * stream socket (to the server process), then read a line back from * the socket and write it to the standard output. * * Return to the caller when an EOF is encountered on the input file. */ #define MAXLINE 5000 void handle_client(FILE *fp, int sockfd, char *cmd) { int n; char sendline[MAXLINE]; char recvline[MAXLINE+1]; int quit = 0; while (!quit) { if (cmd) { strcpy(sendline, cmd); /* one shot command */ quit = 1; } else if (fgets(sendline, MAXLINE, fp) == NULL) { break; } n = strlen(sendline); if (net_send(sockfd, sendline, n) != n) error_abort("handle_client: write error on socket"); while ((n = net_recv(sockfd, recvline, sizeof(recvline))) > 0) { recvline[n] = 0; fputs(recvline, stdout); } if (n < 0) { char msg[200]; sprintf(msg, "handle_client: net_recv error: %s\n", strerror(-n)); error_abort(msg); } } } #else /* HAVE_NISLIB */ int main(int argc, char *argv[]) { printf("Sorry, NIS code is not compiled in apcupsd.\n"); return 1; } #endif /* HAVE_NISLIB */ apcupsd-3.14.14/examples/gui/000077500000000000000000000000001274230402600157255ustar00rootroot00000000000000apcupsd-3.14.14/examples/gui/about.tcl000066400000000000000000000011641274230402600175450ustar00rootroot00000000000000proc AboutCmd {} { toplevel .about -class Dialog wm title .about "About Apcupsd" wm transient .about . image create photo .about.image -file "apcupsd_logo.gif" label .about.label -image .about.image -borderwidth 1 set msg "Copyright 2001, Kern Sibbald\n" append msg "Licensed under GPL version 2\n" append msg "Apcupsd release 3.9.6 (21 Sep 2001)" message .about.copyright -justify center -text $msg -width 400 button .about.ok -borderwidth 1 -text " OK " -command {destroy .about} pack .about.label -side top pack .about.copyright -side top -pady 5 pack .about.ok -side bottom -pady 5 } apcupsd-3.14.14/examples/gui/apcupsd.tcl000066400000000000000000000015351274230402600200740ustar00rootroot00000000000000# # Apcupsd Graphic Interface # proc MessageBox {msg type} { tk_messageBox -icon $type -message $msg } proc ExitCmd {} { exit 0 } proc RefreshCmd {} { GetStatus destroy .main.text destroy .main.image1 destroy .main.image2 destroy .main.image3 DisplayStatus GetEvents update } proc HelpCmd {} { exec netscape www.sibbald.com/apcupsd/manual/ & } wm title . "Apcupsd" # wm minsize . 600 390 foreach File [list \ mainwindow.tcl \ about.tcl \ dialog.tcl \ splash.tcl \ status.tcl \ events.tcl \ ] { if {![file exists "$File"]} { puts "Unable to find required source file $File" exit 1 } else { source $File } } unset File DisplaySplash CreateMainWindow GetStatus DisplayStatus GetEvents update after 1000 destroy .splash wm deiconify . apcupsd-3.14.14/examples/gui/dialog.tcl000066400000000000000000000024271274230402600176750ustar00rootroot00000000000000 proc dialog_create {class {win "auto"}} { if {$win == "auto"} { set count 0 set win ".dialog[incr count]" while {[winfo exists $win]} { set win ".dialog[incr count]" } } toplevel $win -class $class frame $win.info pack $win.info -expand yes -fill both -padx 4 -pady 4 frame $win.sep -height 2 -borderwidth 1 -relief sunken pack $win.sep -fill x -pady 4 frame $win.controls pack $win.controls -fill x -padx 4 -pady 4 wm title $win $class wm group $win . after idle [format { update idletasks wm minsize %s [winfo reqwidth %s] [winfo reqheight %s] } $win $win $win] return $win } proc dialog_info {win} { return "$win.info" } proc dialog_controls {win} { return "$win.controls" } proc dialog_wait {win varName} { dialog_safeguard $win set x [expr [winfo rootx .]+50] set y [expr [winfo rooty .]+50] wm geometry $win "+$x+$y" wm deiconify $win grab set $win vwait $varName grab release $win wm withdraw $win } bind modalDialog { wm deiconify %W raise %W } proc dialog_safeguard {win} { if {[lsearch [bindtags $win] modalDialog] < 0} { bindtags $win [linsert [bindtags $win] 0 modalDialog] } } apcupsd-3.14.14/examples/gui/events.tcl000066400000000000000000000004221274230402600177330ustar00rootroot00000000000000proc GetEvents {} { .events.text delete 0.0 end set fd [open "| ./client localhost:7000 events" "r"] while {[gets $fd line] > 0} { .events.text insert end "\n" .events.text insert end $line } catch {close $fd} .events.text delete 0.0 2.0 } apcupsd-3.14.14/examples/gui/mainwindow.tcl000066400000000000000000000037051274230402600206120ustar00rootroot00000000000000proc CreateMainWindow {} { global statustext StatusText set StatusText " Ready ..." . configure -menu .mbar menu .mbar .mbar add cascade -label "File" -underline 0 -menu .mbar.file menu .mbar.file .mbar.file add separator .mbar.file add command -label "Exit" -underline 0 -command {ExitCmd} .mbar add cascade -label "Options" -underline 0 -menu .mbar.options menu .mbar.options .mbar.options add command -label "Refresh Now" -underline 0 -command {RefreshCmd} .mbar add cascade -label "Help" -underline 0 -menu .mbar.help menu .mbar.help .mbar.help add command -label "About Apcupsd" -underline 0 -command {AboutCmd} .mbar.help add command -label "Help" -underline 0 -command {HelpCmd} frame .sep1 -height 10 -borderwidth 0 pack .sep1 -fill x -side top text .sep1.text -relief groove -height 1 .sep1.text configure -tabs {2.5i 4.5i 6.5i} .sep1.text insert end "\tBattery V\tMains V\tMains V" pack .sep1.text -side top -fill x frame .main -borderwidth 0 pack .main -side top -fill x frame .sep2 -height 2 -borderwidth 1 -relief sunken pack .sep2 -fill x -pady 4 frame .elab pack .elab -side top -fill x label .elab.lab1 -text "Events:" -anchor e pack .elab.lab1 -side left -padx 4 frame .events pack .events -fill x -padx 4 -pady 4 scrollbar .events.sbar -command ".events.text yview" pack .events.sbar -side right -fill y text .events.text -height 10 -wrap word -yscrollcommand ".events.sbar set" pack .events.text -side top -fill x frame .status -borderwidth 1 -relief raised pack .status -side bottom -fill x -pady 2 label .statusLabel -text "Status:" -anchor e -fg magenta set statustext [label .statusText -relief sunken \ -borderwidth 1 -textvariable StatusText -anchor w] grid columnconfigure .status 1 -weight 1 grid .statusLabel -in .status -row 0 -column 0 grid .statusText -in .status -row 0 -column 1 -sticky ew -padx 3 } apcupsd-3.14.14/examples/gui/pkgIndex.tcl000066400000000000000000000011111274230402600201740ustar00rootroot00000000000000# Tcl package index file, version 1.1 # This file is generated by the "pkg_mkIndex" command # and sourced either when an application starts up or # by a "package unknown" script. It invokes the # "package ifneeded" command to set up package-related # information so that packages will be loaded automatically # in response to "package require" commands. When this # script is sourced, the variable $dir must contain the # full path name of this file's directory. package ifneeded Bnet 1.0 [list tclPkgSetup $dir Bnet 1.0 {{tclbnet.so load {BnetClose BnetConnect BnetGet BnetPut}}}] apcupsd-3.14.14/examples/gui/splash.tcl000066400000000000000000000010371274230402600177240ustar00rootroot00000000000000proc DisplaySplash {} { wm withdraw . toplevel .splash -borderwidth 4 -relief raised wm overrideredirect .splash 1 after idle { update idletasks set xmax [winfo screenwidth .splash] set ymax [winfo screenheight .splash] set x0 [expr ($xmax-[winfo reqwidth .splash])/2] set y0 [expr ($ymax-[winfo reqheight .splash])/2] wm geometry .splash "+$x0+$y0" } image create photo .splash.image -file "apcupsd_logo.gif" label .splash.label -image .splash.image pack .splash.label update } apcupsd-3.14.14/examples/gui/status.tcl000066400000000000000000000146121274230402600177600ustar00rootroot00000000000000proc DrawTickLines {c imwid imhgt} { $c create line 50 60 150 60 -fill darkgrey $c create line 50 120 150 120 -fill darkgrey $c create line 50 180 150 180 -fill darkgrey $c create line 50 240 150 240 -fill darkgrey $c create line 50 300 150 300 -fill darkgrey $c create line 50 0 50 300 150 300 150 1 50 1 -fill black } proc DrawText {c min step imwid imhgt} { set next $min $c create text 46 300 -anchor se -text [format "%d" $next] set next [expr $next + $step] $c create text 46 240 -anchor e -text [format "%d" $next] set next [expr $next + $step] $c create text 46 180 -anchor e -text [format "%d" $next] set next [expr $next + $step] $c create text 46 120 -anchor e -text [format "%d" $next] set next [expr $next + $step] $c create text 46 60 -anchor e -text [format "%d" $next] set next [expr $next + $step] $c create text 46 0 -anchor ne -text [format "%d" $next] } proc DrawBattVolt {c imwid imhgt} { global BattV NomBattV switch -- $NomBattV { 12.0 { set minv 3 set maxv 18 set hip [expr 12 + 3] set lowp [expr 12 - 3] } 24.0 { set minv 15 set maxv 30 set hip [expr 24 + 5] set lowp [expr 24 - 5] } 48.0 { set minv 30 set maxv 60 set hip [expr 48 + 7] set lowp [expr 48 - 7] } default { set minv 0 set maxv [expr 10 * (($BattV / 10) + 1)] set hip [expr $BattV + 5] set lowp [expr $BattV -5] } } set deltav [expr $maxv - $minv] set battpos [expr $imhgt - (($BattV - $minv) * $imhgt / $deltav)] set hipos [expr $imhgt - (($hip - $minv) * $imhgt / $deltav)] set lowpos [expr $imhgt - (($lowp - $minv) * $imhgt / $deltav)] $c create rectangle 50 0 150 $imhgt -fill green $c create rectangle 50 0 150 $hipos -fill red -width 0 $c create rectangle 50 $lowpos 150 $imhgt -fill red -width 0 $c create rectangle 75 $battpos 125 $imhgt -fill black $c create text 75 [expr $imhgt + 10] -anchor w -text [format "%.1f VDC" $BattV] DrawTickLines $c $imwid $imhgt DrawText $c $minv [expr $deltav/5] $imwid $imhgt } proc DrawUtility {c imwid imhgt} { global LineV LowTrans HiTrans set minv 175 set deltav 75 set utilpos [expr $imhgt - (($LineV - $minv) * $imhgt / $deltav)] set hipos [expr $imhgt - (($HiTrans - $minv) * $imhgt / $deltav)] set lowpos [expr $imhgt - (($LowTrans - $minv) * $imhgt / $deltav)] $c create rectangle 50 0 150 $imhgt -fill green $c create rectangle 50 0 150 $hipos -fill red $c create rectangle 50 $lowpos 150 $imhgt -fill red $c create rectangle 75 $utilpos 125 $imhgt -fill black $c create text 75 [expr $imhgt + 10] -anchor w -text [format "%.1f VAC" $LineV] DrawTickLines $c $imwid $imhgt DrawText $c $minv [expr $deltav/5] $imwid $imhgt } proc DisplayStatus {} { global BattChg TimeLeft LoadPct HostName Release LineV RetPct global LineFreq BattV NomBattV ITemp global Model Status set imhgt 300 set imwid 100 frame .main.text -borderwidth 2 pack .main.text -side left -expand no -pady 4 label .main.text.lab00 -text "Host:" label .main.text.lab01 -text $HostName grid .main.text.lab00 -row 0 -column 0 -sticky e grid .main.text.lab01 -row 0 -column 1 -sticky ew label .main.text.lab10 -text "UPS Model:" label .main.text.lab11 -text $Model grid .main.text.lab10 -row 1 -column 0 -sticky e grid .main.text.lab11 -row 1 -column 1 -sticky ew label .main.text.lab20 -text "UPS Status:" label .main.text.lab21 -text $Status grid .main.text.lab20 -row 2 -column 0 -sticky e grid .main.text.lab21 -row 2 -column 1 -sticky ew label .main.text.lab30 -text "Internal Temp:" label .main.text.lab31 -text $ITemp grid .main.text.lab30 -row 3 -column 0 -sticky e grid .main.text.lab31 -row 3 -column 1 -sticky ew label .main.text.lab40 -text "Apcupsd Release:" label .main.text.lab41 -text $Release grid .main.text.lab40 -row 4 -column 0 -sticky e grid .main.text.lab41 -row 4 -column 1 -sticky ew grid columnconfigure .main.text 1 -weight 1 frame .main.image1 pack .main.image1 -side left -pady 4 canvas .main.image1.c -width [expr $imwid+50] -height [expr $imhgt + 20] DrawBattVolt .main.image1.c $imwid $imhgt pack .main.image1.c frame .main.image2 pack .main.image2 -side left -pady 4 canvas .main.image2.c -width [expr $imwid+50] -height [expr $imhgt + 20] DrawUtility .main.image2.c $imwid $imhgt pack .main.image2.c frame .main.image3 pack .main.image3 -side left -pady 4 canvas .main.image3.c -width [expr $imwid+75] -height [expr $imhgt + 20] DrawUtility .main.image3.c $imwid $imhgt pack .main.image3.c } proc GetStatus {} { global BattChg TimeLeft LoadPct HostName Release LineV RetPct global LineFreq BattV NomBattV ITemp LowTrans HiTrans global Model Status foreach {i} {BattChg TimeLeft LoadPct HostName Release LineV \ RetPct LineFreq BattV ITemp NomBattV LowTrans \ HiTrans Model Status} { set $i 0 } set fd [open "| ./client localhost:7000 status" "r"] while {[gets $fd line] > 0} { scan $line "%9s" label switch -- $label { BCHARGE { scan $line "%*s : %f Percent" BattChg } TIMELEFT { scan $line "%*s : %f Minutes" TimeLeft } LOADPCT { scan $line "%*s : %f Percent" LoadPct } HOSTNAME { scan $line "%*s : %s" HostName } RELEASE { scan $line "%*s : %s" Release } LINEV { scan $line "%*s : %f Volts" LineV } LOTRANS { scan $line "%*s : %f Volts" LowTrans } HITRANS { scan $line "%*s : %f Volts" HiTrans } RETPCT { scan $line "%*s : %f Percent" RetPct } ITEMP { scan $line "%*s : %f C Internal" ITemp } LINEFREQ { scan $line "%*s : %f Hz" LineFreq } BATTV { scan $line "%*s : %f Volts" BattV } NOMBATTV { scan $line "%*s : %f" NomBattV } MODEL { scan $line "%*s : %s" Model } STATUS { scan $line "%*s : %s" Status } default { } } } catch {close $fd} } apcupsd-3.14.14/examples/hid-set.c000066400000000000000000000053341274230402600166470ustar00rootroot00000000000000/* * Copyright (c) 2002 Paul Stewart * * UPS (HID) set values in UPS */ /* * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to . */ #define HID_MAX_USAGES 1024 #include #include #include #include #include #include #include #include #include #include #include #define UPS_USAGE 0x840004 static inline int find_application(int fd, unsigned usage) { int i = 0; unsigned ret; while ((ret = ioctl(fd, HIDIOCAPPLICATION, i)) != -1 && ret != usage) { printf("App: %08x\n", ret); i++; } if (ret < 0) { fprintf(stderr, "GUSAGE returns %x", ret); perror(""); } return (ret == usage); } int main (int argc, char **argv) { int fd = -1, i, is_ups = 0; struct hiddev_report_info rinfo; struct hiddev_usage_ref uref; char evdev[20]; for (i = 0; i < 4; i++) { sprintf(evdev, "/dev/usb/hid/hiddev%d", i); if ((fd = open(evdev, O_RDONLY)) >= 0) { if (find_application(fd, UPS_USAGE)) { printf("It's a UPS!\n"); is_ups = 1; } break; } } if (i >= 4) { fprintf(stderr, "Couldn't find hiddev device.\n"); exit(1); } /* Usage: 00840057 val -1 (Feature/53/0/0) [DelayBeforeShutdown] Usage: 00840056 val -1 (Feature/54/0/0) [DelayBeforeStartup] */ memset(&uref, 0, sizeof(uref)); uref.report_type = HID_REPORT_TYPE_FEATURE; if (argc > 1 && strcmp(argv[1], "off")) { uref.report_id = 54; } else { uref.report_id = 53; } uref.field_index = 0; uref.usage_index = 0; uref.value = 5; if (ioctl(fd, HIDIOCSUSAGE, &uref) != 0) perror("SUSAGE/S"); rinfo.report_type = uref.report_type; rinfo.report_id = uref.report_id; if (ioctl(fd, HIDIOCSREPORT, &rinfo) != 0) perror("SREPORT/S"); printf("Set 5 in report id %d\n", uref.report_id); exit(0); } apcupsd-3.14.14/examples/hid-ups.c000066400000000000000000000556241274230402600166720ustar00rootroot00000000000000/* * $Id: hid-ups.c,v 1.13.2.2 2007-07-17 22:54:25 adk0212 Exp $ * * Copyright (c) 2001 Vojtech Pavlik * Copyright (c) 2001 Paul Stewart * * Tweaked by Kern Sibbald to learn * about USB UPSes. * * HID UPS device test program */ /* * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Simunkova 1492, Prague 8, 182 00 Czech Republic */ #define DEBUG 1 /* if set prints full reports */ #define TESTING 1 /* if set disables actual operation */ #define HID_MAX_USAGES 1024 #include #include #include #include #include #include #include #include #include #include #include #include #include #define PWRSTAT "/etc/powerstatus" #define DEBOUNCE_TIMEOUT 15 /* increase this if you get false alerts */ #define UPS_USAGE 0x840000 #define UPS_SERIAL 0x8400fe #define BAT_CHEMISTRY 0x850089 #define UPS_CAPACITY_MODE 0x85002c #define UPS_SHUTDOWN_IMMINENT 0x840069 #define UPS_BATTERY_VOLTAGE 0x840030 #define UPS_BELOW_RCL 0x840042 #define UPS_CHARING 0x840044 #define UPS_DISCHARGING 0x850045 #define UPS_REMAINING_CAPACITY 0x850066 #define UPS_RUNTIME_TO_EMPTY 0x850068 #define UPS_AC_PRESENT 0x8500d0 #define STATE_NORMAL 0 /* unit powered */ #define STATE_DEBOUNCE 1 /* power failure */ #define STATE_BATTERY 2 /* power failure confirmed */ /* USB Vendor ID's */ #define Vendor_APC 0x51D #define Vendor_MGE 0x463 #ifdef DEBUG /* * The type field indicates the type or units to be * applied to the value. */ #define T_NONE 0 /* No units */ #define T_INDEX 1 /* String index */ #define T_CAPACITY 2 /* Capacity (usually %) */ #define T_BITS 3 /* bit field */ #define T_UNITS 4 /* use units/exponent field */ #define T_DATE 5 /* date */ #define T_APCDATE 6 /* APC date format */ struct s_ups_info { unsigned usage; int type; const char *label; } ups_info[] = { /* MGE & APC */ { 0x000000, T_NONE, "None" }, /* Page 0x84 is the Power Device Page */ { 0x840000, T_NONE, "UPS-Power" }, { 0x840001, T_INDEX, "iName" }, { 0x840002, T_NONE, "PresentStatus" }, { 0x840004, T_NONE, "UPS" }, { 0x840012, T_NONE, "Battery" }, { 0x840016, T_NONE, "PowerConverter" }, { 0x840018, T_NONE, "OutletSystem" }, { 0x840017, T_NONE, "PowerConverterID" }, { 0x840019, T_NONE, "OutletSystemID" }, { 0x84001a, T_NONE, "Input" }, { 0x84001c, T_NONE, "Output" }, { 0x84001e, T_NONE, "Flow" }, { 0x84001d, T_NONE, "OutputID" }, { 0x84001f, T_NONE, "FlowID" }, { 0x840020, T_NONE, "Outlet" }, { 0x840021, T_NONE, "OutletID" }, { 0x840024, T_NONE, "PowerSummary" }, { 0x840025, T_NONE, "PowerSummaryID" }, { 0x840030, T_UNITS, "Voltage" }, { 0x840031, T_UNITS, "Current" }, { 0x840032, T_UNITS, "Frequency" }, { 0x840033, T_UNITS, "ApparentPower" }, { 0x840034, T_UNITS, "ActivePower" }, { 0x840035, T_UNITS, "PercentLoad" }, { 0x840036, T_UNITS, "Temperature" }, { 0x840037, T_UNITS, "Humidity" }, { 0x840040, T_UNITS, "ConfigVoltage" }, { 0x840042, T_UNITS, "ConfigFrequency" }, { 0x840043, T_UNITS, "ConfigApparentPower" }, { 0x840044, T_UNITS, "ConfigActivePower" }, { 0x840053, T_UNITS, "LowVoltageTransfer" }, { 0x840054, T_UNITS, "HighVoltageTransfer" }, { 0x840055, T_UNITS, "DelayBeforeReboot" }, { 0x840056, T_UNITS, "DelayBeforeStartup" }, { 0x840057, T_NONE, "DelayBeforeShutdown" }, { 0x840058, T_NONE, "Test" }, { 0x84005a, T_NONE, "AudibleAlarmControl" }, { 0x840061, T_NONE, "Good" }, { 0x840062, T_NONE, "InternalFailure" }, { 0x840065, T_NONE, "Overload" }, { 0x840068, T_NONE, "ShutdownRequested" }, { 0x840069, T_NONE, "ShutdownImminent" }, { 0x84006b, T_NONE, "Switch On/Off" }, { 0x84006c, T_NONE, "Switchable" }, { 0x84006e, T_NONE, "Boost" }, { 0x84006f, T_NONE, "Trim" }, { 0x840073, T_NONE, "CommunicationLost" }, { 0x8400fd, T_INDEX, "iManufacturer" }, { 0x8400fe, T_INDEX, "iProduct" }, { 0x8400ff, T_INDEX, "iSerialNumber" }, /* Page 0x85 is the Battery System Page */ { 0x850000, T_NONE, "UPS-Batt" }, { 0x850029, T_CAPACITY, "RemainingCapacityLimit" }, { 0x85002a, T_UNITS, "RemainingTimeLimit" }, { 0x85002c, T_CAPACITY, "CapacityMode" }, { 0x850042, T_NONE, "BelowRemainingCapacityLimit" }, { 0x850043, T_NONE, "RemainingTimeLimitExpired" }, { 0x850044, T_NONE, "Charging" }, { 0x850045, T_NONE, "Discharging" }, { 0x85004b, T_NONE, "NeedReplacement" }, { 0x850058, T_NONE, "BUPHibernate" }, /* APC proprietary */ { 0x850066, T_CAPACITY, "RemainingCapacity" }, { 0x850067, T_CAPACITY, "FullChargeCapacity" }, { 0x850068, T_UNITS, "RunTimeToEmpty" }, { 0x85006b, T_NONE, "CycleCount" }, { 0x850080, T_NONE, "BattPackLevel" }, { 0x850083, T_CAPACITY, "DesignCapacity" }, { 0x850085, T_DATE, "ManufactureDate" }, { 0x850088, T_INDEX, "iDeviceName" }, { 0x850089, T_INDEX, "iDeviceChemistry" }, { 0x85008b, T_NONE, "Rechargeable" }, { 0x85008c, T_CAPACITY, "WarningCapacityLimit" }, { 0x85008d, T_CAPACITY, "CapacityGranularity1" }, { 0x85008e, T_CAPACITY, "CapacityGranularity2" }, { 0x85008f, T_INDEX, "iOEMInformation" }, { 0x8500d0, T_NONE, "ACPresent" }, { 0x8500d1, T_NONE, "BatteryPresent" }, { 0x8500db, T_NONE, "VoltageNotRegulated" }, /* * Page 0x86 is reserved for Power Devices, but not defined in the HID * standard. APC has defined a few usages on this page for themselves. */ { 0x860010, T_NONE, "BUPSelfTest" }, /* APC proprietary */ { 0x860012, T_NONE, "BUPBattCapBeforeStartup" }, /* APC proprietary */ { 0x860076, T_NONE, "BUPDelayBeforeStartup" }, /* APC proprietary */ /* Pages 0xFF00 to 0xFFFF are vendor specific */ { 0xFF860005, T_NONE, "APCGeneralCollection" }, { 0xFF860013, T_NONE, "APC860013_SetMinReturn?" }, { 0xFF860016, T_APCDATE,"APCBattReplacementDate" }, { 0xFF860019, T_UNITS, "APCBattCapBeforeStartup" }, { 0xFF860023, T_NONE, "APC860023_??????" }, { 0xFF860024, T_NONE, "APC860024_??????" }, { 0xFF860025, T_NONE, "APC860025_??????" }, { 0xFF860026, T_NONE, "APC860026_??????" }, { 0xFF860029, T_NONE, "APC860029_??????" }, { 0xFF86002A, T_NONE, "APC86002A_??????" }, { 0xFF860042, T_INDEX, "APC_UPS_FirmwareRevision" }, { 0xFF860052, T_NONE, "APCLineFailCause" }, { 0xFF860060, T_BITS, "APCStatusFlag" }, { 0xFF860061, T_NONE, "APCSensitivity" }, { 0xFF860062, T_NONE, "APC860062_SetHiTransV?" }, { 0xFF860064, T_NONE, "APC860064_SetLoTransV?" }, { 0xFF860072, T_NONE, "APCPanelTest" }, { 0xFF860074, T_NONE, "APC860074_SetSens?" }, { 0xFF860076, T_UNITS, "APCShutdownAfterDelay" }, { 0xFF860077, T_NONE, "APC860077_SetWakeUpDelay?" }, { 0xFF860079, T_INDEX, "APC_USB_FirmwareRevision" }, { 0xFF86007C, T_NONE, "APCForceShutdown" }, { 0xFF86007D, T_UNITS, "APCDelayBeforeShutdown" }, { 0xFF86007E, T_UNITS, "APCDelayBeforeStartup" }, { 0xFF8600FC, T_UNITS, "ModbusRTURx" }, { 0xFF8600FD, T_UNITS, "ModbusRTUTx" }, }; #define UPS_INFO_SZ (sizeof(ups_info)/sizeof(ups_info[0])) const char *reports[] = { "Unknown", "Input", "Output", "Feature" }; static int CapacityMode = 2; /* default = % */ char unknown[24]; #define MADDR "stewart@wetlogic.net" void log_status(const char *msg) { #ifndef TESTING char buf[256]; printf("[Log message \"%s\"]\n", msg); sprintf(buf, "/bin/echo %s | /bin/mail -s \"UPS System\" %s", msg, MADDR); system(buf); #else printf("[Log message \"%s\"]\n", msg); #endif } static const char* info(unsigned int detail) { unsigned int i; for (i = 0; i < UPS_INFO_SZ; i++) { if (ups_info[i].usage == detail) { return ups_info[i].label; } } sprintf(unknown, "[%06x]", detail); return unknown; } static struct s_ups_info *info_entry(unsigned int detail) { unsigned int i; static struct s_ups_info info = {0, T_NONE, unknown}; for (i = 0; i < UPS_INFO_SZ; i++) { if (ups_info[i].usage == detail) { return &ups_info[i]; } } sprintf(unknown, "[%06x]", detail); return &info; } #else /* DEBUG */ #define log_status(s) #endif /* DEBUG */ /* Tell init the power has either gone or is back. */ void powerfail(int state) { #ifndef TESTING int fd; /* Create an info file needed by init to shutdown/cancel shutdown */ unlink(PWRSTAT); if ((fd = open(PWRSTAT, O_CREAT|O_WRONLY, 0644)) >= 0) { if (state > 0) write(fd, "FAIL\n", 5); else if (state < 0) write(fd, "LOW\n", 4); else write(fd, "OK\n", 3); close(fd); } kill(1, SIGPWR); #else printf("We are in powerfail() with state=%d ", state); if (state > 0) printf("POWER FAILURE\n"); else if (state < 0) printf("BATTERY LOW\n"); else printf("OK\n"); #endif } static inline int find_application(int fd, unsigned usage) { int i = 0, ret; while ((ret = ioctl(fd, HIDIOCAPPLICATION, i)) > 0 && (ret & 0xffff0000) != (usage & 0xffff0000)) i++; return ((ret & 0xffff000) == (usage & 0xffff0000)); } /* * Get a string from the device given the string's index */ static const char *get_string(int fd, int sindex) { static struct hiddev_string_descriptor sdesc; static char buf[200]; if (sindex == 0) { return ""; } sdesc.index = sindex; if (ioctl(fd, HIDIOCGSTRING, &sdesc) < 0) { sprintf(buf, "String index %d returned ERR=%s\n", sindex, strerror(errno)); return buf; } return sdesc.value; } /* * Give units code and exponent, returns string * describing the units used. (doesn't work for percentages). */ static const char *get_units(unsigned unit, int exponent) { static char buf[200]; if (exponent > 7) { exponent = exponent - 16; } switch (unit) { case 1: /* special kludge for CapacityMode */ switch (exponent) { case 0: return "maH"; case 1: return "mwH"; case 2: return "percent"; case 3: return "boolean"; default: return ""; } case 0x00F0D121: if (exponent == 7) { return "Volts"; } else if (exponent == 5) { return "CentiVolts"; } else if (exponent == 6) { return "DeciVolts"; } else { sprintf(buf, "Volts with %d exponent", exponent); return buf; } case 0x00100001: if (exponent == -2) { return "CentiAmps"; } else if (exponent == 0) { return "Amps"; } else { sprintf(buf, "Amps with %d exponent", exponent); return buf; } case 0xF001: if (exponent == 0) { return "Hertz"; } else if (exponent == -2) { return "CentiHertz"; } else { sprintf(buf, "Hertz with %d exponent", exponent); return buf; } case 0x1001: if (exponent == 0) { return "Seconds"; } else { sprintf(buf, "Seconds with %d exponent", exponent); return buf; } case 0xD121: return "Watts"; case 0x010001: if (exponent == 0) { return "Degrees K"; } else { sprintf(buf, "Degrees K with %d exponent", exponent); return buf; } case 0x0101001: return "AmpSecs"; case 0: return ""; default: sprintf(buf, "0x%x", unit); return buf; } } static char evdev[50]; static int vendor = 0; int main (int argc, char **argv) { time_t start_seconds; int fd = -1, rd, j, RemainingCapacity; unsigned int i; struct hiddev_event ev[64]; struct hiddev_devinfo dinfo; char name[256] = "Unknown"; int state = 0; fd_set fdset; struct timeval timev, *tv = NULL; struct hiddev_usage_ref uref; if (argc < 2) { /* deal with either standard location or Red Hat's */ const char *hid_dirs[] = {"/dev/usb/hid", "/dev/usb","/dev"}; for (i = 0; i < sizeof(hid_dirs)/sizeof(hid_dirs[0]); i++) { for (j = 0; j < 4; j++) { sprintf(evdev, "%s/hiddev%d", hid_dirs[i], j); if ((fd = open(evdev, O_RDONLY)) < 0) { if (errno == EACCES) { fprintf(stderr, "No permission, try this as root.\n"); exit(1); } } else { if (find_application(fd, UPS_USAGE)) goto foundit; close(fd); } } } fprintf(stderr, "Couldn't find USB UPS device, check your /dev.\n"); exit(1); foundit: printf("Found UPS at %s\n", evdev); } else { strncpy(evdev, argv[argc -1], sizeof(evdev)-1); printf("Found UPS at %s\n", evdev); if ((fd = open(evdev, O_RDONLY)) < 0) { perror("hiddev open"); exit(1); } if (!find_application(fd, UPS_USAGE)) { fprintf(stderr, "%s is not a UPS\n", argv[argc - 1]); exit(1); } } #ifdef DEBUG { unsigned version; ioctl(fd, HIDIOCGVERSION, &version); printf("hiddev driver version is %d.%d.%d\n", version >> 16, (version >> 8) & 0xff, version & 0xff); ioctl(fd, HIDIOCGDEVINFO, &dinfo); printf("HID: vendor 0x%x product 0x%x version 0x%x ", dinfo.vendor, dinfo.product & 0xffff, dinfo.version); printf("app %s", info(ioctl(fd, HIDIOCAPPLICATION, 0))); for (i = 1; i < dinfo.num_applications; i++) printf(", %s", info(ioctl(fd, HIDIOCAPPLICATION, i))); printf("\n"); printf("HID: bus: %d devnum: %d ifnum: %d\n", dinfo.busnum, dinfo.devnum, dinfo.ifnum); vendor = dinfo.vendor; } #endif ioctl(fd, HIDIOCINITREPORT, 0); ioctl(fd, HIDIOCGNAME(sizeof(name)), name); printf("UPS HID device name: \"%s\"\n", name); memset(&uref, 0, sizeof(uref)); uref.report_type = HID_REPORT_TYPE_FEATURE; uref.report_id = HID_REPORT_ID_UNKNOWN; uref.usage_code = BAT_CHEMISTRY; if (ioctl(fd, HIDIOCGUSAGE, &uref) == 0) { printf("Battery Chemistry: \"%s\" (%d)\n", get_string(fd, uref.value), uref.value); } memset(&uref, 0, sizeof(uref)); uref.report_type = HID_REPORT_TYPE_FEATURE; uref.report_id = HID_REPORT_ID_UNKNOWN; uref.usage_code = UPS_CAPACITY_MODE; if (ioctl(fd, HIDIOCGUSAGE, &uref) == 0) { CapacityMode = uref.value; } #ifdef DEBUG /* To traverse the report descriptor info */ { struct hiddev_report_info rinfo; struct hiddev_field_info finfo; struct hiddev_usage_ref uref; int rtype; unsigned int i, j; for (rtype = HID_REPORT_TYPE_MIN; rtype <= HID_REPORT_TYPE_MAX; rtype++) { rinfo.report_type = rtype; rinfo.report_id = HID_REPORT_ID_FIRST; while (ioctl(fd, HIDIOCGREPORTINFO, &rinfo) >= 0) { printf("\n%sReport %d\n", reports[rinfo.report_type], rinfo.report_id); for (i = 0; i < rinfo.num_fields; i++) { struct s_ups_info *p; memset(&finfo, 0, sizeof(finfo)); finfo.report_type = rinfo.report_type; finfo.report_id = rinfo.report_id; finfo.field_index = i; ioctl(fd, HIDIOCGFIELDINFO, &finfo); printf(" Field %d, app %s, phys %s, log %s\n", i, info(finfo.application), info(finfo.physical), info(finfo.logical)); memset(&uref, 0, sizeof(uref)); for (j = 0; j < finfo.maxusage; j++) { unsigned unit; int exponent; int v, yy, mm, dd; uref.report_type = finfo.report_type; uref.report_id = finfo.report_id; uref.field_index = i; uref.usage_index = j; ioctl(fd, HIDIOCGUCODE, &uref); ioctl(fd, HIDIOCGUSAGE, &uref); p = info_entry(uref.usage_code); switch (p->type) { case T_CAPACITY: unit = 1; printf("Exponent %d lost.\n", finfo.unit_exponent); exponent = CapacityMode; break; case T_UNITS: unit = finfo.unit; exponent = finfo.unit_exponent; break; default: unit = 0; exponent = 0; break; } printf(" Usage %d, %s = %d %s", j, p->label, uref.value, get_units(unit, exponent)); switch (p->type) { case T_INDEX: printf(" %s\n", get_string(fd, uref.value)); break; case T_BITS: /* binary bits */ printf(" 0x%x\n", uref.value); break; case T_DATE: /* packed integer date */ printf(" %4d-%02d-%02d\n", (uref.value >> 9) + 1980, (uref.value >> 5) & 0xF, uref.value & 0x1F); break; case T_APCDATE: /* APC date */ v = uref.value; yy = ((v>>4) & 0xF)*10 + (v&0xF) + 2000; v >>= 8; dd = ((v>>4) & 0xF)*10 + (v&0xF); v >>= 8; mm = ((v>>4) & 0xF)*10 + (v&0xF); printf(" %4d-%02d-%02d\n", yy, mm, dd); default: printf("\n"); break; } } } rinfo.report_id |= HID_REPORT_ID_NEXT; } } } printf("\nWaiting for events ... (interrupt to exit)\n"); fflush(stdout); #endif start_seconds = time(NULL); FD_ZERO(&fdset); while (1) { if (fd < 0) { sleep(5); fd = open(evdev, O_RDONLY); if (fd < 0) { perror("\nOpen error"); continue; } if (!find_application(fd, UPS_USAGE)) { fprintf(stderr, "\nCould not find_application.\n"); close(fd); fd = -1; } continue; } switch (state) { case STATE_NORMAL: tv = NULL; break; case STATE_BATTERY: case STATE_DEBOUNCE: timev.tv_sec = DEBOUNCE_TIMEOUT; timev.tv_usec = 0; tv = &timev; break; } FD_SET(fd, &fdset); rd = select(fd+1, &fdset, NULL, NULL, tv); if (rd > 0) { rd = read(fd, ev, sizeof(ev)); if (rd < (int) sizeof(ev[0])) { if (rd < 0) perror("\nevtest: error reading"); else fprintf(stderr, "\nevtest: got short read from device!\n"); // exit (1); close(fd); fd = -1; continue; } else { printf("time %lu\n", time(NULL) - start_seconds); } for (i = 0; i < rd / sizeof(ev[0]); i++) { #ifdef DEBUG printf("Event: %s = %d\n", info(ev[i].hid), ev[i].value); #endif /* DEBUG */ if (ev[i].hid == UPS_SHUTDOWN_IMMINENT && ev[i].value == 1) { log_status("UPS shutdown imminent!"); powerfail(-1); state = STATE_BATTERY; RemainingCapacity = -1; } switch (state) { case STATE_BATTERY: if (ev[i].hid == UPS_DISCHARGING && ev[i].value == 0) { log_status("System back on AC power"); powerfail(0); state = STATE_NORMAL; RemainingCapacity = -1; } break; case STATE_DEBOUNCE: if (ev[i].hid == UPS_DISCHARGING && ev[i].value == 0) { state = STATE_NORMAL; RemainingCapacity = -1; } break; case STATE_NORMAL: if (ev[i].hid == UPS_DISCHARGING && ev[i].value == 1) { state = STATE_DEBOUNCE; RemainingCapacity = -1; } break; } } } else { /* Our timer has expired */ switch (state) { case STATE_DEBOUNCE: log_status("System switched to battery power"); state = STATE_BATTERY; powerfail(1); break; default: break; } } fflush(stdout); } } apcupsd-3.14.14/examples/hiddev.h000066400000000000000000000132461274230402600165630ustar00rootroot00000000000000#ifndef _HIDDEV_H #define _HIDDEV_H /* * $Id: hiddev.h,v 1.1.1.1 2002-05-28 13:34:21 kerns Exp $ * * Copyright (c) 1999-2000 Vojtech Pavlik * * Sponsored by SuSE */ /* * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic */ /* * The event structure itself */ struct hiddev_event { unsigned hid; signed int value; }; struct hiddev_devinfo { unsigned int bustype; unsigned int busnum; unsigned int devnum; unsigned int ifnum; short vendor; short product; short version; unsigned num_applications; }; #define HID_STRING_SIZE 256 struct hiddev_string_descriptor { int index; char value[HID_STRING_SIZE]; }; struct hiddev_report_info { unsigned report_type; unsigned report_id; unsigned num_fields; }; /* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and * report_id. Set report_id to REPORT_ID_UNKNOWN if the rest of the fields * are unknown. Otherwise use a usage_ref struct filled in from a previous * successful GUSAGE/SUSAGE call to save time. To actually send a value * to the device, perform a SUSAGE first, followed by a SREPORT. If an * INITREPORT is done, a GREPORT isn't necessary before a GUSAGE. */ #define HID_REPORT_ID_UNKNOWN 0xffffffff #define HID_REPORT_ID_FIRST 0x00000100 #define HID_REPORT_ID_NEXT 0x00000200 #define HID_REPORT_ID_MASK 0x000000ff #define HID_REPORT_ID_MAX 0x000000ff #define HID_REPORT_TYPE_INPUT 1 #define HID_REPORT_TYPE_OUTPUT 2 #define HID_REPORT_TYPE_FEATURE 3 #define HID_REPORT_TYPE_MIN 1 #define HID_REPORT_TYPE_MAX 3 struct hiddev_field_info { unsigned report_type; unsigned report_id; unsigned field_index; unsigned maxusage; unsigned flags; unsigned physical; /* physical usage for this field */ unsigned logical; /* logical usage for this field */ unsigned application; /* application usage for this field */ __s32 logical_minimum; __s32 logical_maximum; __s32 physical_minimum; __s32 physical_maximum; unsigned unit_exponent; unsigned unit; }; /* Fill in report_type, report_id and field_index to get the information on a * field. */ #define HID_FIELD_CONSTANT 0x001 #define HID_FIELD_VARIABLE 0x002 #define HID_FIELD_RELATIVE 0x004 #define HID_FIELD_WRAP 0x008 #define HID_FIELD_NONLINEAR 0x010 #define HID_FIELD_NO_PREFERRED 0x020 #define HID_FIELD_NULL_STATE 0x040 #define HID_FIELD_VOLATILE 0x080 #define HID_FIELD_BUFFERED_BYTE 0x100 struct hiddev_usage_ref { unsigned report_type; unsigned report_id; unsigned field_index; unsigned usage_index; unsigned usage_code; __s32 value; }; /* * Protocol version. */ #define HID_VERSION 0x010002 /* * IOCTLs (0x00 - 0x7f) */ #define HIDIOCGVERSION _IOR('H', 0x01, int) #define HIDIOCAPPLICATION _IO('H', 0x02) #define HIDIOCGDEVINFO _IOR('H', 0x03, struct hiddev_devinfo) #define HIDIOCGSTRING _IOR('H', 0x04, struct hiddev_string_descriptor) #define HIDIOCINITREPORT _IO('H', 0x05) #define HIDIOCGNAME(len) _IOC(_IOC_READ, 'H', 0x06, len) #define HIDIOCGREPORT _IOW('H', 0x07, struct hiddev_report_info) #define HIDIOCSREPORT _IOW('H', 0x08, struct hiddev_report_info) #define HIDIOCGREPORTINFO _IOWR('H', 0x09, struct hiddev_report_info) #define HIDIOCGFIELDINFO _IOWR('H', 0x0A, struct hiddev_field_info) #define HIDIOCGUSAGE _IOWR('H', 0x0B, struct hiddev_usage_ref) #define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref) #define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) /* To traverse the input report descriptor info for a HID device, perform the * following: * * rinfo.report_type = HID_REPORT_TYPE_INPUT; * rinfo.report_id = HID_REPORT_ID_FIRST; * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo); * * while (ret >= 0) { * for (i = 0; i < rinfo.num_fields; i++) { * finfo.report_type = rinfo.report_type; * finfo.report_id = rinfo.report_id; * finfo.field_index = i; * ioctl(fd, HIDIOCGFIELDINFO, &finfo); * for (j = 0; j < finfo.maxusage; j++) { * uref.field_index = i; * uref.usage_index = j; * ioctl(fd, HIDIOCGUCODE, &uref); * ioctl(fd, HIDIOCGUSAGE, &uref); * } * } * uref.report_id |= HID_REPORT_ID_NEXT; * ret = ioctl(fd, HIDIOCGREPORTINFO, &uref); * } */ #ifdef __KERNEL__ /* * In-kernel definitions. */ #ifdef CONFIG_USB_HIDDEV int hiddev_connect(struct hid_device *); void hiddev_disconnect(struct hid_device *); void hiddev_hid_event(struct hid_device *, unsigned int usage, int value); int __init hiddev_init(void); void __exit hiddev_exit(void); #else static inline void *hiddev_connect(struct hid_device *hid) { return NULL; } static inline void hiddev_disconnect(struct hid_device *hid) { } static inline void hiddev_event(struct hid_device *hid, unsigned int usage, int value) { } static inline int hiddev_init(void) { return 0; } static inline void hiddev_exit(void) { } #endif #endif #endif apcupsd-3.14.14/examples/index.php000066400000000000000000000151431274230402600167650ustar00rootroot00000000000000 \n"; echo "\n"; if (file_exists($statusfile_location)) { // Open the Status file. $statusfile = file($statusfile_location); // Get the word status ("ONLINE", "ON-BATT", etc.) $dumbvar = split(":", $statusfile[10]); $status = $dumbvar[1]; if (eregi('online', $status)) { $statusbg = $goodcolour; } else $statusbg = $warncolour; // Get the current UPS load $dumbvar = split(":", $statusfile[12]); $load = floatval($dumbvar[1]); if ($load > 75) { $loadbg = $badcolour; } else if ($load > 25) { $loadbg = $warncolour; } else $loadbg = $goodcolour; // Get the battery charge level $dumbvar = split(":", $statusfile[13]); $charge = floatval($dumbvar[1]); if ($charge > 60) { $chargebg = $goodcolour; } else if ($charge > 25) { $chargebg = $warncolour; } else $chargebg = $badcolour; // Get the estimated time remaining $dumbvar = split(":", $statusfile[14]); $etl = $dumbvar[1]; // Draw the table entry. echo "\n"; }; if (file_exists($logfile_location)) { // Open the log file. $logfile = file($logfile_location); $loglines = count($logfile); if ($loglines < $showloglines) $showloglines = $loglines; // Draw the table echo "\n"; echo "\n"; } else { // By default, just show the last X lines. Save some screen real estate. echo "
APCUPSD UPS Network Monitor
Sun Jan 16 12:07:27 CET 2000
System Model Status
UPS Status
\n"; echo "
\n"; echo "Battery Status:" . $status . "
\n"; echo "UPS Load:" . $load . "
\n"; echo "Battery Charge:". $charge . "
\n"; echo "Estimated time left:" . $etl . "
"; if ($showlog == "yes") { // If the user has clicked the "Show entire log" link, show the whole shebang in reverse order. echo ""; for ($i = 0; $i <= $loglines; $i++) { $newline = $logfile[($loglines - $i - 1)]; $notifycolour = "white"; if (eregi("power is back", $newline)) { $notifycolour = $goodcolour; } else if (eregi("power failure", $newline)) { $notifycolour = $badcolour; } else if (eregi("startup succeeded", $newline)) { $notifycolour = $goodcolour; } else if (eregi("exiting", $newline)) { $notifycolour = $warncolour; } else if (eregi("shutdown succeeded", $newline)) { $notifycolour = $goodcolour; } else if (eregi("ups batteries", $newline)) { $notifycolour = $warncolour; } else if (eregi("exhausted", $newline)) { $notifycolour = $badcolour; } else { $notifycolour = $warncolour; }; echo "\n"; } echo "
"; echo $newline; echo "
\n"; echo "
\n"; // Add a link so that the user can switch this view off. echo "Hide old log entries
"; for ($i = 0; $i < $showloglines; $i++) { $newline = $logfile[($loglines - $i - 1)]; $notifycolour = "white"; if (eregi("power is back", $newline)) { $notifycolour = $goodcolour; } else if (eregi("power failure", $newline)) { $notifycolour = $badcolour; } else if (eregi("startup succeeded", $newline)) { $notifycolour = $goodcolour; } else if (eregi("exiting", $newline)) { $notifycolour = $warncolour; } else if (eregi("shutdown succeeded", $newline)) { $notifycolour = $goodcolour; } else if (eregi("ups batteries", $newline)) { $notifycolour = $warncolour; } else if (eregi("exhausted", $newline)) { $notifycolour = $badcolour; } else { $notifycolour = $warncolour; }; echo "\n"; } echo "
"; echo $newline; echo "
\n"; echo "
\n"; // Add a link so the user can see the entire log from the beginning. echo "Show entire log
"; ?> apcupsd-3.14.14/examples/libusb.h000066400000000000000000000064051274230402600165770ustar00rootroot00000000000000/* $NetBSD: usb.h,v 1.7 2000/04/02 11:10:53 augustss Exp $ */ /* * Copyright (c) 1999 Lennart Augustsson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/lib/libusb/libusb.h,v 1.1.2.1 2000/07/02 13:14:00 n_hibma Exp $ * */ typedef struct report_desc *report_desc_t; typedef struct hid_data *hid_data_t; typedef enum hid_kind { hid_input, hid_output, hid_feature, hid_collection, hid_endcollection }hid_kind_t; typedef struct hid_item { /* Global */ int _usage_page; int logical_minimum; int logical_maximum; int physical_minimum; int physical_maximum; int unit_exponent; int unit; int report_size; int report_ID; #define NO_REPORT_ID 0 int report_count; /* Local */ unsigned int usage; int usage_minimum; int usage_maximum; int designator_index; int designator_minimum; int designator_maximum; int string_index; int string_minimum; int string_maximum; int set_delimiter; /* Misc */ int collection; int collevel; enum hid_kind kind; unsigned int flags; /* Absolute data position (bits) */ unsigned int pos; /* */ struct hid_item *next; } hid_item_t; #define HID_PAGE(u) ((u) >> 16) #define HID_USAGE(u) ((u) & 0xffff) /* Obtaining a report descriptor, descr.c: */ report_desc_t hid_get_report_desc __P((int file)); void hid_dispose_report_desc __P((report_desc_t)); /* Parsing of a HID report descriptor, parse.c: */ hid_data_t hid_start_parse __P((report_desc_t d, int kindset)); void hid_end_parse __P((hid_data_t s)); int hid_get_item __P((hid_data_t s, hid_item_t *h)); int hid_report_size __P((report_desc_t d, enum hid_kind k, int *idp)); int hid_locate __P((report_desc_t d, unsigned int usage, enum hid_kind k, hid_item_t *h)); /* Conversion to/from usage names, usage.c: */ const char *hid_usage_page __P((int i)); const char *hid_usage_in_page __P((unsigned int u)); void hid_init __P((const char *file)); /* Extracting/insertion of data, data.c: */ int hid_get_data __P((const void *p, const hid_item_t *h)); void hid_set_data __P((void *p, const hid_item_t *h, int data)); apcupsd-3.14.14/examples/make-hiddev000077500000000000000000000011621274230402600172450ustar00rootroot00000000000000#!/bin/sh mkdir -p /dev/usb/hid mknod /dev/usb/hid/hiddev0 c 180 96 mknod /dev/usb/hid/hiddev1 c 180 97 mknod /dev/usb/hid/hiddev2 c 180 98 mknod /dev/usb/hid/hiddev3 c 180 99 mknod /dev/usb/hid/hiddev4 c 180 100 mknod /dev/usb/hid/hiddev5 c 180 101 mknod /dev/usb/hid/hiddev6 c 180 102 mknod /dev/usb/hid/hiddev7 c 180 103 mknod /dev/usb/hid/hiddev8 c 180 104 mknod /dev/usb/hid/hiddev9 c 180 105 mknod /dev/usb/hid/hiddev10 c 180 106 mknod /dev/usb/hid/hiddev11 c 180 107 mknod /dev/usb/hid/hiddev12 c 180 108 mknod /dev/usb/hid/hiddev13 c 180 109 mknod /dev/usb/hid/hiddev14 c 180 110 mknod /dev/usb/hid/hiddev15 c 180 111 apcupsd-3.14.14/examples/megaclient.c000066400000000000000000000062501274230402600174200ustar00rootroot00000000000000/* * Client test program for apcnet * * This program beats the living daylights out of your * server by sending it one million requests. * * Optionally, it can send one million requests, connecting * and disconnecting each time. * * * Build it with: cc megaclient.c ../lib/libapc.a -o megaclient * * Execute: ./megaclient [host[:port]] * * For additional examples of code, see cgi/upsfetch.c */ /* * If RECONNECT is defined, megaclient will disconnect * and reconnect for every request (iteration), which is the normal * way that apcupsd is currently accessed. * * If RECONNECT is not defined, a single connection * is made with multiple requests. */ #define RECONNECT 1 #define ITERATIONS 80000 #include "apc.h" #ifdef HAVE_NISLIB /* Default values, can be changed on command line */ #define SERV_TCP_PORT 3551 #define SERV_HOST_ADDR "127.0.0.1" #define MAXLINE 5000 void error_abort(const char *msg) { fprintf(stderr, msg); exit(1); } int main(int argc, char *argv[]) { int sockfd, port; char host[200]; char msg[200], *p, *cmd; int i, n, line; time_t now, done; char recvline[MAXLINE+1]; strcpy(host, SERV_HOST_ADDR); port = SERV_TCP_PORT; if (argc > 1) { strcpy(host, argv[1]); /* get host from command line */ p = strchr(host, ':'); if (p) { *p++ = 0; port = atoi(p); } } if (argc > 2) { cmd = argv[2]; } else { cmd = NULL; } #ifdef RECONNECT now = time(NULL); for (i=0; i 0) { recvline[n] = 0; line++; /* fputs(recvline, stdout); */ } if (n < 0) { char msg[200]; sprintf(msg, "handle_client: net_recv error: %s\n", strerror(-n)); error_abort(msg); } if ( (i % 100) == 0) { printf("%d lines=%d\n", i, line); } net_close(sockfd); } #else /* Open once only */ if ((sockfd = net_open(host, NULL, port)) < 0) { sprintf(msg, "client: tcp_open for host %s on %d failed\n", host, port); error_abort(msg); } now = time(NULL); for (i=0; i 0) { recvline[n] = 0; line++; /* fputs(recvline, stdout); */ } if (n < 0) { char msg[200]; sprintf(msg, "handle_client: net_recv error: %s\n", strerror(-n)); error_abort(msg); } if ( (i % 100) == 0) { printf("%d lines=%d\n", i, line); } } net_close(sockfd); #endif done = time(NULL); printf("Total time = %ld secs.\n", done - now); exit(0); } #else /* HAVE_NISLIB */ int main(int argc, char *argv[]) { printf("Sorry, NIS code is not compiled in apcupsd.\n"); return 1; } #endif /* HAVE_NISLIB */ apcupsd-3.14.14/examples/nagios_plugin_check_apcupsd.c000066400000000000000000000217631274230402600230300ustar00rootroot00000000000000/* * Check-Plugin for Nagios to check status of an APC-UPS * monitored by APCUPSD * * Written by Christian Masopust, November 2005 * * Build it with: cc check_apcupsd.c ../lib/libapc.a -o check_apcupsd * * Execute: ./check_apcupsd [host[:port]] * */ #include "apc.h" #ifdef HAVE_NISLIB /* Default values, can be changed on command line */ #define SERV_TCP_PORT 3551 #define SERV_HOST_ADDR "127.0.0.1" #define BIGBUF 4096 char statbuf[BIGBUF]; int statlen = BIGBUF; #define NAGIOS_OK 0 #define NAGIOS_WARNING 1 #define NAGIOS_CRITICAL 2 #define NAGIOS_UNKNOWN 3 #define S_NAGIOS_OK "OK: " #define S_NAGIOS_WARNING "WARNING: " #define S_NAGIOS_CRITICAL "CRITICAL: " #define S_NAGIOS_UNKNOWN "UNKNOWN: " /* List of variables that can be read by getupsvar() * First field is that name given to getupsvar(), * Second field is our internal name as produced by the STATUS * output from apcupsd. * Third field, if 0 returns everything to the end of the * line, and if 1 returns only to first space (e.g. integers, * and floating point values. */ static struct { char *request; char *upskeyword; int nfields; } cmdtrans[] = { {"model", "MODEL", 0}, {"upsmodel", "UPSMODEL", 0}, {"date", "DATE", 0}, {"battcap", "BCHARGE", 1}, {"mbattchg", "MBATTCHG", 1}, {"battvolt", "BATTV", 1}, {"nombattv", "NOMBATTV", 1}, {"utility", "LINEV", 1}, {"upsload", "LOADPCT", 1}, {"loadpct", "LOADPCT", 1}, {"outputv", "OUTPUTV", 1}, {"status", "STATFLAG", 1}, {"linemin", "MINLINEV", 1}, {"linemax", "MAXLINEV", 1}, {"upstemp", "ITEMP", 1}, {"outputfreq", "LINEFREQ", 1}, {"translo", "LOTRANS", 1}, {"transhi", "HITRANS", 1}, {"runtime", "TIMELEFT", 1}, {"mintimel", "MINTIMEL", 1}, {"retpct", "RETPCT", 1}, /* min batt to turn on UPS */ {"sense", "SENSE", 1}, {"hostname", "HOSTNAME", 1}, {"battdate", "BATTDATE", 1}, {"serialno", "SERIALNO", 1}, {"lastxfer", "LASTXFER", 0}, /* reason for last xfer to batteries */ {"selftest", "SELFTEST", 1}, /* results of last self test */ {"laststest", "LASTSTEST", 0}, {"version", "VERSION", 1}, {"upsname", "UPSNAME", 1}, {"lowbatt", "DLOWBATT", 1}, /* low battery power off delay */ {"battpct", "BCHARGE", 1}, {"highxfer", "HITRANS", 1}, {"lowxfer", "LOTRANS", 1}, {"cable", "CABLE", 0}, {"firmware", "FIRMWARE", 0}, {NULL, NULL} }; int fetch_data(char *host, int port); int getupsvar(char *host, int port, char *request, char *answer, int anslen); int fill_buffer(int sockfd); extern int net_errno; struct sockaddr_in tcp_serv_addr; void error_abort(char *msg) { fprintf(stdout, msg); exit(NAGIOS_CRITICAL); } int main(int argc, char *argv[]) { int port; char host[200]; char msg[200], *p; char hostname[100]; char model[100]; char upsname[100]; char status[1000]; int iStatus; char sStatus[10]; char loadpct[100]; char runtime[100]; int retVal; retVal = NAGIOS_UNKNOWN; strcpy (sStatus, S_NAGIOS_UNKNOWN); strcpy(host, SERV_HOST_ADDR); port = SERV_TCP_PORT; if (argc > 1) { strcpy(host, argv[1]); /* get host from command line */ p = strchr(host, ':'); if (p) { *p++ = 0; port = atoi(p); } } if (getupsvar(host, port, "hostname", msg, sizeof(msg)) <= 0) { printf("%scannot get hostname from UPS-Server\n", S_NAGIOS_CRITICAL); exit(NAGIOS_CRITICAL); } strcpy(hostname, msg); if (getupsvar(host, port, "model", msg, sizeof(msg)) <= 0) { printf("%scannot get model from UPS-Server\n", S_NAGIOS_CRITICAL); exit(NAGIOS_CRITICAL); } strcpy(model, msg); if (getupsvar(host, port, "upsname", msg, sizeof(msg)) <= 0) { printf("%scannot get upsname from UPS-Server\n", S_NAGIOS_CRITICAL); exit(NAGIOS_CRITICAL); } strcpy(upsname, msg); if (getupsvar(host, port, "status", msg, sizeof(msg)) <= 0) { printf("%scannot get status from UPS-Server\n", S_NAGIOS_CRITICAL); exit(NAGIOS_CRITICAL); } iStatus = strtol(msg, 0, 16); status[0] = '\0'; if (iStatus & UPS_calibration) { strcat(status, "CALIBRATION "); retVal = NAGIOS_OK; strcpy(sStatus, S_NAGIOS_OK); } if (iStatus & UPS_trim) { strcat(status, "SMART TRIM "); retVal = NAGIOS_OK; strcpy(sStatus, S_NAGIOS_OK); } if (iStatus & UPS_boost) { strcat(status, "SMART BOOST "); retVal = NAGIOS_OK; strcpy(sStatus, S_NAGIOS_OK); } if (iStatus & UPS_online) { strcat(status, "ONLINE "); retVal = NAGIOS_OK; strcpy(sStatus, S_NAGIOS_OK); } if (iStatus & UPS_onbatt) { strcat(status, "ON BATTERY "); retVal = NAGIOS_WARNING; strcpy(sStatus, S_NAGIOS_WARNING); } if (iStatus & UPS_overload) { strcat(status, "OVERLOADED "); retVal = NAGIOS_CRITICAL; strcpy(sStatus, S_NAGIOS_CRITICAL); } if (iStatus & UPS_battlow) { strcat(status, "BATTERY LOW "); retVal = NAGIOS_CRITICAL; strcpy(sStatus, S_NAGIOS_CRITICAL); } if (iStatus & UPS_replacebatt) { strcat(status, "REPLACE BATTERY "); retVal = NAGIOS_WARNING; strcpy(sStatus, S_NAGIOS_WARNING); } if (iStatus & UPS_commlost) { strcat(status, "COMMUNICATION LOST "); retVal = NAGIOS_CRITICAL; strcpy(sStatus, S_NAGIOS_CRITICAL); } if (iStatus & UPS_shutdown) { strcat(status, "SHUTDOWN "); retVal = NAGIOS_OK; strcpy(sStatus, S_NAGIOS_OK); } if (iStatus & UPS_slave) { strcat(status, "SLAVE "); retVal = NAGIOS_OK; strcpy(sStatus, S_NAGIOS_OK); } if (strlen(status) > 0) { status[strlen(status) - 1] = '\0'; } if (getupsvar(host, port, "loadpct", msg, sizeof(msg)) <= 0) { printf("%scannot get loadpct from UPS-Server\n", S_NAGIOS_CRITICAL); exit(NAGIOS_CRITICAL); } strcpy(loadpct, msg); if (getupsvar(host, port, "runtime", msg, sizeof(msg)) <= 0) { printf("%scannot get runtime from UPS-Server\n", S_NAGIOS_CRITICAL); exit(NAGIOS_CRITICAL); } strcpy(runtime, msg); printf ("%sUPS: %s, Load: %s%%, Runtime: %smin, Status: %s\n", sStatus, model, loadpct, runtime, status); /* printf("For host=%s ups=%s model=%s, the Status=%s, loadpct=%s, runtime=%s\n", hostname, upsname, model, status, loadpct, runtime); */ exit(retVal); } /* * Read data into memory buffer to be used by getupsvar() * Returns 0 on error * Returns 1 if data fetched */ int fetch_data(char *host, int port) { int sockfd; int stat; if ((sockfd = net_open(host, NULL, port)) < 0) { printf("fetch_data: tcp_open failed for %s port %d", host, port); return 0; } stat = fill_buffer(sockfd); /* fill statbuf */ net_close(sockfd); return stat; } /* * * Returns 1 if var found * answer has var * Returns 0 if variable name not found * answer has "Not found" is variable name not found * answer may have "N/A" if the UPS does not support this * feature * Returns -1 if network problem * answer has "N/A" if host is not available or network error */ int getupsvar(char *host, int port, char *request, char *answer, int anslen) { int i; char *stat_match = NULL; char *find; int nfields = 0; if (!fetch_data(host, port)) { strcpy(answer, "N/A"); return -1; } for (i=0; cmdtrans[i].request; i++) if (!(strcmp(cmdtrans[i].request, request))) { stat_match = cmdtrans[i].upskeyword; nfields = cmdtrans[i].nfields; } if (stat_match != NULL) { if ((find=strstr(statbuf, stat_match)) != NULL) { if (nfields == 1) /* get one field */ sscanf (find, "%*s %*s %s", answer); else { /* get everything to eol */ i = 0; find += 11; /* skip label */ while (*find != '\n') answer[i++] = *find++; answer[i] = 0; } if (strcmp(answer, "N/A") == 0) return 0; return 1; } } strcpy(answer, "Not found"); return 0; } #define MAXLINE 512 /* Fill buffer with data from UPS network daemon * Returns 0 on error * Returns 1 if OK */ int fill_buffer(int sockfd) { int n, stat = 1; char buf[1000]; statbuf[0] = 0; statlen = 0; if (net_send(sockfd, "status", 6) != 6) { printf("fill_buffer: write error on socket\n"); return 0; } while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) { buf[n] = 0; strcat(statbuf, buf); } if (n < 0) stat = 0; statlen = strlen(statbuf); return stat; } #else /* HAVE_NISLIB */ int main(int argc, char *argv[]) { printf("Sorry, NIS code is not compiled in apcupsd.\n"); return 1; } #endif /* HAVE_NISLIB */ apcupsd-3.14.14/examples/newslave.c000066400000000000000000000140151274230402600171320ustar00rootroot00000000000000/* * Client test program for apcnisd to be used * as a base for the new master/slave code. * * Build it with: cc newslave.c ../lib/libapc.a -o newclient * * Execute: ./newslave [host[:port]] * * The two commands currently (Apr 2001) accepted by the * server are "status" and "events". * */ #include "apc.h" #ifdef HAVE_NISLIB /* Default values, can be changed on command line */ #define SERV_TCP_PORT 3551 #define SERV_HOST_ADDR "127.0.0.1" #define BIGBUF 4096 char statbuf[BIGBUF]; int statlen = BIGBUF; /* List of variables that can be read by getupsvar() * First field is that name given to getupsvar(), * Second field is our internal name as produced by the STATUS * output from apcupsd. * Third field, if 0 returns everything to the end of the * line, and if 1 returns only to first space (e.g. integers, * and floating point values. */ static struct { const char *request; const char *upskeyword; int nfields; } cmdtrans[] = { {"model", "MODEL", 0}, {"upsmodel", "UPSMODEL", 0}, {"date", "DATE", 0}, {"battcap", "BCHARGE", 1}, {"mbattchg", "MBATTCHG", 1}, {"battvolt", "BATTV", 1}, {"nombattv", "NOMBATTV", 1}, {"utility", "LINEV", 1}, {"upsload", "LOADPCT", 1}, {"loadpct", "LOADPCT", 1}, {"outputv", "OUTPUTV", 1}, {"status", "STATFLAG", 1}, {"linemin", "MINLINEV", 1}, {"linemax", "MAXLINEV", 1}, {"upstemp", "ITEMP", 1}, {"outputfreq", "LINEFREQ", 1}, {"translo", "LOTRANS", 1}, {"transhi", "HITRANS", 1}, {"runtime", "TIMELEFT", 1}, {"mintimel", "MINTIMEL", 1}, {"retpct", "RETPCT", 1}, /* min batt to turn on UPS */ {"sense", "SENSE", 1}, {"hostname", "HOSTNAME", 1}, {"battdate", "BATTDATE", 1}, {"serialno", "SERIALNO", 1}, {"lastxfer", "LASTXFER", 0}, /* reason for last xfer to batteries */ {"selftest", "SELFTEST", 1}, /* results of last self test */ {"laststest", "LASTSTEST", 0}, {"version", "VERSION", 1}, {"upsname", "UPSNAME", 1}, {"lowbatt", "DLOWBATT", 1}, /* low battery power off delay */ {"battpct", "BCHARGE", 1}, {"highxfer", "HITRANS", 1}, {"lowxfer", "LOTRANS", 1}, {"cable", "CABLE", 0}, {"firmware", "FIRMWARE", 0}, {NULL, NULL} }; int fetch_data(char *host, int port); int getupsvar(char *host, int port, const char *request, char *answer, int anslen); int fill_buffer(int sockfd); extern int net_errno; void error_abort(char *msg) { fprintf(stderr, msg); exit(1); } int main(int argc, char *argv[]) { int port; char host[200]; char msg[200], *p; char hostname[100]; char release[100]; char upsname[100]; char status[100]; strcpy(host, SERV_HOST_ADDR); port = SERV_TCP_PORT; if (argc > 1) { strcpy(host, argv[1]); /* get host from command line */ p = strchr(host, ':'); if (p) { *p++ = 0; port = atoi(p); } } if (getupsvar(host, port, "hostname", msg, sizeof(msg)) <= 0) { printf("Error getting variable\n"); exit(1); } strcpy(hostname, msg); if (getupsvar(host, port, "version", msg, sizeof(msg)) <= 0) { printf("Error getting variable\n"); exit(1); } strcpy(release, msg); if (getupsvar(host, port, "upsname", msg, sizeof(msg)) <= 0) { printf("Error getting variable\n"); exit(1); } strcpy(upsname, msg); if (getupsvar(host, port, "status", msg, sizeof(msg)) <= 0) { printf("Error getting variable\n"); exit(1); } strcpy(status, msg); printf("For host=%s ups=%s apcupsd version=%s, the Status=%s\n", hostname, upsname, release, status); exit(0); } /* * Read data into memory buffer to be used by getupsvar() * Returns 0 on error * Returns 1 if data fetched */ int fetch_data(char *host, int port) { int sockfd; int stat; if ((sockfd = net_open(host, NULL, port)) < 0) { printf("fetch_data: tcp_open failed for %s port %d", host, port); return 0; } stat = fill_buffer(sockfd); /* fill statbuf */ net_close(sockfd); return stat; } /* * * Returns 1 if var found * answer has var * Returns 0 if variable name not found * answer has "Not found" is variable name not found * answer may have "N/A" if the UPS does not support this * feature * Returns -1 if network problem * answer has "N/A" if host is not available or network error */ int getupsvar(char *host, int port, const char *request, char *answer, int anslen) { int i; const char *stat_match = NULL; char *find; int nfields = 0; if (!fetch_data(host, port)) { strcpy(answer, "N/A"); return -1; } for (i=0; cmdtrans[i].request; i++) if (!(strcmp(cmdtrans[i].request, request))) { stat_match = cmdtrans[i].upskeyword; nfields = cmdtrans[i].nfields; } if (stat_match != NULL) { if ((find=strstr(statbuf, stat_match)) != NULL) { if (nfields == 1) /* get one field */ sscanf (find, "%*s %*s %s", answer); else { /* get everything to eol */ i = 0; find += 11; /* skip label */ while (*find != '\n') answer[i++] = *find++; answer[i] = 0; } if (strcmp(answer, "N/A") == 0) return 0; return 1; } } strcpy(answer, "Not found"); return 0; } #define MAXLINE 512 /* Fill buffer with data from UPS network daemon * Returns 0 on error * Returns 1 if OK */ int fill_buffer(int sockfd) { int n, stat = 1; char buf[1000]; statbuf[0] = 0; statlen = 0; if (net_send(sockfd, "status", 6) != 6) { printf("fill_buffer: write error on socket\n"); return 0; } while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) { buf[n] = 0; strcat(statbuf, buf); } if (n < 0) stat = 0; statlen = strlen(statbuf); return stat; } #else /* HAVE_NISLIB */ int main(int argc, char *argv[]) { printf("Sorry, NIS code is not compiled in apcupsd.\n"); return 1; } #endif /* HAVE_NISLIB */ apcupsd-3.14.14/examples/offbattery.cpufreq000077500000000000000000000022341274230402600207010ustar00rootroot00000000000000#!/bin/sh # # This shell script if placed in /etc/apcupsd will be # called by /etc/apcupsd/apccontrol when the UPS goes # back on to the mains after a power failure. # # We scale the CPU clock frequency to maximum and # send an email message to root to notify him. # # NOTE: Assumes Linux-2.6.x kernel with CPUFREQ # support for your chipset. SYSADMIN=root APCUPSD_MAIL="/bin/mail" # Iterate over all CPUs, enabling the userspace governor # and programming the current clock speed to the maximum. # This is redundant on hyperthread siblings, but it # doesn't hurt anything and it keeps the code simple. for CPU in /sys/devices/system/cpu/cpu*/cpufreq ; do echo -n userspace > $CPU/scaling_governor cat $CPU/scaling_max_freq > $CPU/scaling_setspeed done # Send an email to root HOSTNAME=`hostname` MSG="$HOSTNAME Power has returned" # ( echo "Subject: $MSG" echo " " echo "$MSG" echo " " for CPU in `ls -1 /sys/devices/system/cpu` ; do echo -n "$CPU freq scaled to " cat /sys/devices/system/cpu/$CPU/cpufreq/scaling_setspeed | tr -d '\n' echo " MHz" done echo " " /sbin/apcaccess status ) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN exit 0 apcupsd-3.14.14/examples/onbattery.cpufreq000077500000000000000000000027571274230402600205550ustar00rootroot00000000000000#!/bin/sh # # This shell script if placed in /etc/apcupsd will be # called by /etc/apcupsd/apccontrol when the UPS goes # on batteries. # # We scale the CPU clock frequency back to save power # and send an email message to root to notify him. # # NOTE: Assumes Linux-2.6.x kernel with CPUFREQ # support for your chipset. Enable appropriate # modprobe line below to match your hardware. SYSADMIN=root APCUPSD_MAIL="/bin/mail" # Load the appropriate cpufreq module. This is best done # in boot scripts, but throw it here to make sure it has # been done. modprobe p4_clockmod #modprobe cpufreq-nforce2 #modprobe powernow-k6 #modprobe powernow-k8 #modprobe speedstep-smi # Give the cpufreq module a chance to initialize sleep 1 # Iterate over all CPUs, enabling the userspace governor # and programming the current clock speed to the minimum. # This is redundant on hyperthread siblings, but it # doesn't hurt anything and it keeps the code simple. for CPU in /sys/devices/system/cpu/cpu*/cpufreq ; do echo -n userspace > $CPU/scaling_governor cat $CPU/scaling_min_freq > $CPU/scaling_setspeed done # Send an email to root HOSTNAME=`hostname` MSG="$HOSTNAME Power Failure!" # ( echo "Subject: $MSG" echo " " echo "$MSG" echo " " for CPU in `ls -1 /sys/devices/system/cpu` ; do echo -n "$CPU freq scaled to " cat /sys/devices/system/cpu/$CPU/cpufreq/scaling_setspeed | tr -d '\n' echo " MHz" done echo " " /sbin/apcaccess status ) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN exit 0 apcupsd-3.14.14/examples/php-monitor.txt000066400000000000000000000031301274230402600201530ustar00rootroot00000000000000From rob@killerbob.ca Tue Apr 26 14:27:01 2005 Date: Tue, 26 Apr 2005 08:27:01 -0400 From: Rob Kroll To: Gerry Kroll CC: Kern Sibbald , gkroll@killerbob.ca, Adam Kropelin Subject: Re: apcupsd And here it is again, with a logic fix and some handling for events I hadn't tested yet. (behaviour when the battery dies completely) Thanks, again, -RK Gerry Kroll wrote: > Kern: > Sorry, here's the file again. > > The attachment is now a ZIP file, apcupsd_rk.zip containing index.php. > > I hope that's satisfactory. > > Regards, > Gerry Kroll (canajun2eh) for > Rob Kroll. > > Kern Sibbald wrote: > >> Hello Rob, >> >> Thanks for your thanks. :-) >> >> This looks like a really nice contribution. Could you resend me your >> file, but as an attachment? -- that will avoid lines getting messed >> up due to wrapping by browsers. >> >> On Tuesday 26 April 2005 03:33, Rob Kroll wrote: >> >> >>> Hi, Kern, >>> >>> I'd like to start by thanking you for the work you and your team have >>> put into this project. It's an excellent piece of software, and I'm >>> glad >>> that I was able to find it. >>> >>> That said, I've written a php script that parses the apcupsd.events and >>> apcupsd.status files, and displays the most important information for >>> the user. I thought you folks might like to include it with the >>> distribution, as it allows for web-based monitoring of the UPS status. >>> >>> I've attached the file to this e-mail. >>> >>> >>> Thanks again, >>> -RK >>> >> Included file is in apcupsd-source/examples/index.php apcupsd-3.14.14/examples/rpt/000077500000000000000000000000001274230402600157465ustar00rootroot00000000000000apcupsd-3.14.14/examples/rpt/Back-UPS-350-USB.rpt000066400000000000000000000073451274230402600207470ustar00rootroot00000000000000Found UPS at /dev/usb/hid/hiddev0 hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x100 app UPS HID: bus: 1 devnum: 3 ifnum: 0 UPS HID device name: "American Power Conversion Back-UPS 350 FW: 5.2.I USB FW: c1 " Battery Chemistry: "PbAc" (4) InputReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 InputReport 12 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 1380 Seconds InputReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 InputReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 1 Field 0, app UPS, phys PowerSummary Usage 0, iProduct = 1 Back-UPS 350 FW: 5.2.I USB FW: c1 FeatureReport 2 Field 0, app UPS, phys PowerSummary Usage 0, iSerialNumber = 2 BB0115017954 FeatureReport 3 Field 0, app UPS, phys PowerSummary Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 4 Field 0, app UPS, phys PowerSummary Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys PowerSummary Usage 0, Rechargeable = 1 FeatureReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 FeatureReport 7 Field 0, app UPS, phys PowerSummary Usage 0, ManufactureDate = 10896 2001-04-16 FeatureReport 8 Field 0, app UPS, phys PowerSummary Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 9 Field 0, app UPS, phys PowerSummary Usage 0, Voltage = 1342 CentiVolts FeatureReport 10 Field 0, app UPS, phys PowerSummary Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 11 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 12 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 1380 Seconds FeatureReport 13 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, DesignCapacity = 100 percent FeatureReport 14 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 15 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 16 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 17 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 18 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent FeatureReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 FeatureReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 53 Field 0, app UPS, phys PowerSummary Usage 0, APCPanelTest = 0 FeatureReport 28 Field 0, app UPS, phys PowerSummary Usage 0, APCBattReplacementDate = 267777 2001-04-16 FeatureReport 64 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCForceShutdown = 0 Waiting for events ... (interrupt to exit) Event: Voltage = 1342 Event: RemainingCapacity = 95 Event: Charging = 1 Event: RunTimeToEmpty = 2580 apcupsd-3.14.14/examples/rpt/Back-UPS-350ES.rpt000066400000000000000000000072121274230402600205410ustar00rootroot00000000000000Found UPS at /dev/usb/hid/hiddev0 hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x100 app UPS HID: bus: 1 devnum: 2 ifnum: 0 UPS HID device name: "American Power Conversion Back-UPS ES/CyberFort 350 FW: 3.1.I USB FW: d1" Battery Chemistry: "PbAc" (4) InputReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 InputReport 12 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 360 Seconds InputReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 InputReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 1 Field 0, app UPS, phys PowerSummary Usage 0, iProduct = 1 Back-UPS ES/CyberFort 350 FW: 3.1.I USB FW: d1 FeatureReport 2 Field 0, app UPS, phys PowerSummary Usage 0, iSerialNumber = 2 AB0233221824 FeatureReport 3 Field 0, app UPS, phys PowerSummary Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 4 Field 0, app UPS, phys PowerSummary Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys PowerSummary Usage 0, Rechargeable = 1 FeatureReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 FeatureReport 7 Field 0, app UPS, phys PowerSummary Usage 0, ManufactureDate = 11535 2002-08-15 FeatureReport 8 Field 0, app UPS, phys PowerSummary Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 9 Field 0, app UPS, phys PowerSummary Usage 0, Voltage = 1327 CentiVolts FeatureReport 10 Field 0, app UPS, phys PowerSummary Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 11 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 12 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 360 Seconds FeatureReport 13 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, DesignCapacity = 100 percent FeatureReport 14 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 15 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 16 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 17 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 18 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent FeatureReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 FeatureReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 53 Field 0, app UPS, phys PowerSummary Usage 0, APCPanelTest = 0 FeatureReport 28 Field 0, app UPS, phys PowerSummary Usage 0, APCBattReplacementDate = 529666 2002-08-15 FeatureReport 64 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCForceShutdown = 0 Waiting for events ... (interrupt to exit) apcupsd-3.14.14/examples/rpt/Back-UPS-500-USB.rpt000066400000000000000000000073451274230402600207440ustar00rootroot00000000000000Found UPS at /dev/usb/hid/hiddev0 hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x100 app UPS HID: bus: 1 devnum: 4 ifnum: 0 UPS HID device name: "American Power Conversion Back-UPS 500 FW: 6.2.I USB FW: c1 " Battery Chemistry: "PbAc" (4) InputReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 16 0x10 InputReport 12 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 2580 Seconds InputReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 InputReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 1 Field 0, app UPS, phys PowerSummary Usage 0, iProduct = 1 Back-UPS 500 FW: 6.2.I USB FW: c1 FeatureReport 2 Field 0, app UPS, phys PowerSummary Usage 0, iSerialNumber = 2 BB0134078947 FeatureReport 3 Field 0, app UPS, phys PowerSummary Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 4 Field 0, app UPS, phys PowerSummary Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys PowerSummary Usage 0, Rechargeable = 1 FeatureReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 16 0x10 FeatureReport 7 Field 0, app UPS, phys PowerSummary Usage 0, ManufactureDate = 11035 2001-08-27 FeatureReport 8 Field 0, app UPS, phys PowerSummary Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 9 Field 0, app UPS, phys PowerSummary Usage 0, Voltage = 1366 CentiVolts FeatureReport 10 Field 0, app UPS, phys PowerSummary Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 11 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 12 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 2580 Seconds FeatureReport 13 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, DesignCapacity = 100 percent FeatureReport 14 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 15 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 16 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 17 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 18 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent FeatureReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 FeatureReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 53 Field 0, app UPS, phys PowerSummary Usage 0, APCPanelTest = 0 FeatureReport 28 Field 0, app UPS, phys PowerSummary Usage 0, APCBattReplacementDate = 534273 2001-08-27 FeatureReport 64 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCForceShutdown = 0 Waiting for events ... (interrupt to exit) Event: Voltage = 1366 Event: RemainingCapacity = 95 Event: Charging = 1 Event: APCStatusFlag = 8 apcupsd-3.14.14/examples/rpt/Back-UPS-500ES.rpt000066400000000000000000000163331274230402600205420ustar00rootroot00000000000000hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x106 app UPS HID: bus: 4 devnum: 3 ifnum: 0 UPS HID device name: "APC Back-UPS ES 500 FW:2.e2.D USB FW:e2" Battery Chemistry: "PbAc" (4) InputReport 6 Field 0, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 InputReport 12 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 5017 Seconds InputReport 22 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, ACPresent = 1 Field 3, app UPS, phys PowerSummary Usage 0, BatteryPresent = 1 Field 4, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys PowerSummary Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys PowerSummary Usage 0, NeedReplacement = 0 Field 8, app UPS, phys PowerSummary Usage 0, Overload = 0 FeatureReport 1 Field 0, app UPS, phys PowerSummary Usage 0, iProduct = 1 Back-UPS ES 500 FW:2.e2.D USB FW:e2 FeatureReport 2 Field 0, app UPS, phys PowerSummary Usage 0, iSerialNumber = 2 JB0221019999 FeatureReport 3 Field 0, app UPS, phys PowerSummary Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 4 Field 0, app UPS, phys PowerSummary Usage 0, iOEMInformation = 3 APC FeatureReport 5 Field 0, app UPS, phys PowerSummary Usage 0, Rechargeable = 1 FeatureReport 6 Field 0, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 FeatureReport 7 Field 0, app UPS, phys PowerSummary Usage 0, ManufactureDate = 11449 2002-05-25 FeatureReport 8 Field 0, app UPS, phys PowerSummary Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 9 Field 0, app UPS, phys PowerSummary Usage 0, Voltage = 1359 CentiVolts FeatureReport 10 Field 0, app UPS, phys PowerSummary Usage 0, iManufacturer = 3 APC FeatureReport 11 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 12 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 5017 Seconds FeatureReport 13 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, DesignCapacity = 100 percent FeatureReport 14 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 15 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 16 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 17 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 18 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent FeatureReport 22 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, ACPresent = 1 Field 3, app UPS, phys PowerSummary Usage 0, BatteryPresent = 1 Field 4, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys PowerSummary Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys PowerSummary Usage 0, NeedReplacement = 0 Field 8, app UPS, phys PowerSummary Usage 0, Overload = 0 FeatureReport 23 Field 0, app UPS, phys PowerSummary Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 24 Field 0, app UPS, phys PowerSummary Usage 0, AudibleAlarmControl = 2 FeatureReport 28 Field 0, app UPS, phys Battery Usage 0, APCBattReplacementDate = 0 2000-00-00 FeatureReport 32 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 11449 2002-05-25 FeatureReport 34 Field 0, app UPS, phys Battery Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent FeatureReport 35 Field 0, app UPS, phys Battery Usage 0, RunTimeToEmpty = 5017 Seconds FeatureReport 36 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 37 Field 0, app UPS, phys Battery Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 38 Field 0, app UPS, phys Battery Usage 0, Voltage = 1359 CentiVolts FeatureReport 39 Field 0, app UPS, phys Battery Usage 0, [ff860024] = 243 FeatureReport 40 Field 0, app UPS, phys Battery Usage 0, [ff860018] = 0 FeatureReport 48 Field 0, app UPS, phys Input Usage 0, ConfigVoltage = 120 Volts FeatureReport 49 Field 0, app UPS, phys Input Usage 0, Voltage = 119 Volts FeatureReport 50 Field 0, app UPS, phys Input Usage 0, LowVoltageTransfer = 88 Volts FeatureReport 51 Field 0, app UPS, phys Input Usage 0, HighVoltageTransfer = 138 Volts FeatureReport 52 Field 0, app UPS, phys Input Usage 0, [ff860024] = 176 FeatureReport 53 Field 0, app UPS, phys Input Usage 0, [ff860061] = 2 FeatureReport 54 Field 0, app UPS, phys Input Usage 0, [ff860052] = 3 FeatureReport 64 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCForceShutdown = 0 FeatureReport 65 Field 0, app UPS, phys APCGeneralCollection Usage 0, [ff86007d] = -1 FeatureReport 80 Field 0, app UPS, phys PowerConverter Usage 0, PercentLoad = 0 FeatureReport 81 Field 0, app UPS, phys PowerConverter Usage 0, [ff860024] = 189 FeatureReport 96 Field 0, app UPS, phys [ff860001] Usage 0, [ff860023] = 0 FeatureReport 97 Field 0, app UPS, phys [ff860001] Usage 0, [ff860026] = -120 FeatureReport 98 Field 0, app UPS, phys [ff860001] Usage 0, [ff860025] = 0 FeatureReport 127 Field 0, app UPS, phys --- Usage 0, iProduct = 6 2.e2.D FeatureReport 126 Field 0, app UPS, phys --- Usage 0, APC_UPS_FirmwareRevision = 5 FeatureReport 125 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 JB0221019999 FeatureReport 124 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 APC FeatureReport 123 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 11449 2002-05-25 FeatureReport 122 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 8, app UPS, phys --- Usage 0, Overload = 0 FeatureReport 121 Field 0, app UPS, phys --- Usage 0, APCPanelTest = 0 FeatureReport 120 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 FeatureReport 117 Field 0, app UPS, phys --- Usage 0, [ff860029] = 3 FeatureReport 116 Field 0, app UPS, phys --- Usage 0, [ff86002a] = 0 apcupsd-3.14.14/examples/rpt/Back-UPS-BR-800.rpt000066400000000000000000000472371274230402600206250ustar00rootroot00000000000000FROM: Jorge Fbregas Found UPS at /dev/hiddev0 hiddev driver version is 1.0.4 HID: vendor 0x51d product 0x2 version 0x106 app UPS HID: bus: 4 devnum: 2 ifnum: 0 UPS HID device name: "American Power Conversion Back-UPS BR 800 FW:9.o2 .D USB FW:o2" Battery Chemistry: "" (0) InputReport 12 Field 0, app UPS, phys --- Exponent -1075460892 lost. Usage 0, RemainingCapacity = 100 maH InputReport 13 Field 0, app UPS, phys --- Usage 0, RunTimeToEmpty = 1807 Seconds InputReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 InputReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 6 InputReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 0 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 0 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 1 Field 0, app UPS, phys --- Usage 0, iProduct = 1 Back-UPS BR 800 FW:9.o2 .D USB FW:o2 FeatureReport 2 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 QB0645337724 FeatureReport 3 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 4 Field 0, app UPS, phys --- Usage 0, iOEMInformation = 0 FeatureReport 5 Field 0, app UPS, phys --- Usage 0, iDeviceChemistry = 0 FeatureReport 6 Field 0, app UPS, phys --- Usage 0, Rechargeable = 0 Field 1, app UPS, phys --- Exponent 0 lost. Usage 0, CapacityMode = 0 maH FeatureReport 14 Field 0, app UPS, phys --- Exponent 0 lost. Usage 0, DesignCapacity = 0 maH Field 1, app UPS, phys --- Exponent 0 lost. Usage 0, FullChargeCapacity = 0 maH FeatureReport 12 Field 0, app UPS, phys --- Exponent 0 lost. Usage 0, RemainingCapacity = 100 maH FeatureReport 16 Field 0, app UPS, phys --- Exponent 0 lost. Usage 0, CapacityGranularity1 = 0 maH Field 1, app UPS, phys --- Exponent 0 lost. Usage 0, CapacityGranularity2 = 0 maH FeatureReport 15 Field 0, app UPS, phys --- Exponent 0 lost. Usage 0, WarningCapacityLimit = 50 maH FeatureReport 17 Field 0, app UPS, phys --- Exponent 0 lost. Usage 0, RemainingCapacityLimit = 10 maH FeatureReport 9 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 0 1980-00-00 FeatureReport 13 Field 0, app UPS, phys --- Usage 0, RunTimeToEmpty = 1807 Seconds FeatureReport 18 Field 0, app UPS, phys --- Usage 0, DelayBeforeShutdown = -1 FeatureReport 19 Field 0, app UPS, phys --- Usage 0, DelayBeforeReboot = 0 Seconds FeatureReport 8 Field 0, app UPS, phys --- Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 10 Field 0, app UPS, phys --- Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 11 Field 0, app UPS, phys --- Usage 0, Voltage = 0 CentiVolts FeatureReport 20 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 1 FeatureReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 6 FeatureReport 23 Field 0, app UPS, phys Battery Usage 0, APCBattCapBeforeStartup = 0 FeatureReport 27 Field 0, app UPS, phys Battery Usage 0, [ff86001a] = 0 FeatureReport 28 Field 0, app UPS, phys Battery Usage 0, [ff86001b] = 0 FeatureReport 69 Field 0, app UPS, phys Battery Usage 0, APCBattReplacementDate = 599297 2001-09-25 FeatureReport 21 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 13671 2006-11-07 FeatureReport 24 Field 0, app UPS, phys Battery Exponent 0 lost. Usage 0, RemainingCapacity = 0 maH FeatureReport 26 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 0 Seconds FeatureReport 25 Field 0, app UPS, phys Battery Usage 0, RunTimeToEmpty = 0 Seconds FeatureReport 30 Field 0, app UPS, phys Battery Usage 0, Temperature = 3023 Degrees K with -1 exponent FeatureReport 31 Field 0, app UPS, phys Battery Usage 0, ConfigVoltage = 0 CentiVolts FeatureReport 29 Field 0, app UPS, phys Battery Usage 0, Voltage = 2710 CentiVolts FeatureReport 71 Field 0, app UPS, phys Battery Usage 0, APC860024_?????? = 0 FeatureReport 72 Field 0, app UPS, phys Battery Usage 0, [ff860018] = 0 FeatureReport 32 Field 0, app UPS, phys Input Usage 0, Voltage = 591084 DeciVolts FeatureReport 70 Field 0, app UPS, phys Input Usage 0, ConfigVoltage = 0 Volts FeatureReport 33 Field 0, app UPS, phys Input Usage 0, APCLineFailCause = 1 FeatureReport 34 Field 0, app UPS, phys Input Usage 0, APC860061_?????? = 0 FeatureReport 66 Field 0, app UPS, phys Input Usage 0, APC860024_?????? = 0 FeatureReport 44 Field 0, app UPS, phys Output Usage 0, PercentLoad = 270 FeatureReport 82 Field 0, app UPS, phys Output Usage 0, ConfigActivePower = 0 Watts FeatureReport 42 Field 0, app UPS, phys Output Usage 0, Frequency = 6000 CentiHertz FeatureReport 43 Field 0, app UPS, phys Output Usage 0, Voltage = 1200 DeciVolts FeatureReport 45 Field 0, app UPS, phys Output Usage 0, ConfigVoltage = 0 Volts FeatureReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = 138 Volts FeatureReport 36 Field 0, app UPS, phys Output Usage 0, LowVoltageTransfer = 97 Volts FeatureReport 37 Field 0, app UPS, phys Output Usage 0, APCDelayBeforeStartup = 0 Seconds FeatureReport 38 Field 0, app UPS, phys Output Usage 0, APCShutdownAfterDelay = 0 Seconds FeatureReport 39 Field 0, app UPS, phys Output Usage 0, DelayBeforeShutdown = 0 FeatureReport 40 Field 0, app UPS, phys Output Usage 0, DelayBeforeStartup = 0 Seconds FeatureReport 41 Field 0, app UPS, phys Output Usage 0, DelayBeforeReboot = 0 Seconds FeatureReport 64 Field 0, app UPS, phys Output Usage 0, APCForceShutdown = 0 FeatureReport 65 Field 0, app UPS, phys Output Usage 0, APCDelayBeforeShutdown = -1 Seconds FeatureReport 46 Field 0, app UPS, phys --- Usage 0, iProduct = 0 FeatureReport 47 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 0 FeatureReport 48 Field 0, app UPS, phys --- Usage 0, iManufacturer = 0 FeatureReport 49 Field 0, app UPS, phys --- Usage 0, iName = 0 FeatureReport 52 Field 0, app UPS, phys --- Usage 0, APC_UPS_FirmwareRevision = 0 FeatureReport 55 Field 0, app UPS, phys --- Usage 0, APC_USB_FirmwareRevision = 0 FeatureReport 50 Field 0, app UPS, phys --- Usage 0, APCPanelTest = 0 FeatureReport 53 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 0 1980-00-00 FeatureReport 62 Field 0, app UPS, phys --- Usage 0, [ff860027] = 0 FeatureReport 63 Field 0, app UPS, phys --- Usage 0, [ff860028] = 0 FeatureReport 54 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 0 FeatureReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 0 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 0 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 96 Field 0, app UPS, phys [ff860001] Usage 0, APC860023_?????? = 0 FeatureReport 97 Field 0, app UPS, phys [ff860001] Usage 0, APC860026_?????? = 0 FeatureReport 98 Field 0, app UPS, phys [ff860001] Usage 0, APC860025_?????? = 0 FeatureReport 81 Field 0, app UPS, phys PowerConverter Usage 0, APC860024_?????? = 0 Waiting for events ... (interrupt to exit) Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1845 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 Event: RunTimeToEmpty = 1807 Event: RemainingCapacity = 100 Event: Charging = 0 Event: Discharging = 0 Event: ACPresent = 1 Event: BatteryPresent = 1 Event: BelowRemainingCapacityLimit = 0 Event: ShutdownRequested = 0 Event: ShutdownImminent = 0 Event: RemainingTimeLimitExpired = 0 Event: CommunicationLost = 0 Event: NeedReplacement = 0 Event: Overload = 0 Event: VoltageNotRegulated = 0 Event: [ff860080] = 0 Event: Test = 6 apcupsd-3.14.14/examples/rpt/Back-UPS-CS-650.rpt000066400000000000000000000255441274230402600206270ustar00rootroot00000000000000FROM: Jan Ceuleers Found UPS at /dev/usb/hiddev0 hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x6 app UPS HID: bus: 2 devnum: 2 ifnum: 0 UPS HID device name: "American Power Conversion Back-UPS CS 650 FW:817.v4.I USB FW:v4" Battery Chemistry: "PbAc" (4) InputReport 12 Field 0, app UPS, phys --- Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent InputReport 13 Field 0, app UPS, phys --- Usage 0, RunTimeToEmpty = 1462 Seconds InputReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 InputReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 6 InputReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 1 Field 0, app UPS, phys --- Usage 0, iProduct = 1 Back-UPS CS 650 FW:817.v4.I USB FW:v4 FeatureReport 2 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 QB0642232674 FeatureReport 3 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 4 Field 0, app UPS, phys --- Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys --- Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 6 Field 0, app UPS, phys --- Usage 0, Rechargeable = 1 Field 1, app UPS, phys --- Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 14 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, DesignCapacity = 100 percent Field 1, app UPS, phys --- Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 12 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, RemainingCapacity = 100 percent FeatureReport 16 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent Field 1, app UPS, phys --- Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 15 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 17 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 9 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 13644 2006-10-12 FeatureReport 13 Field 0, app UPS, phys --- Usage 0, RunTimeToEmpty = 1530 Seconds FeatureReport 18 Field 0, app UPS, phys --- Usage 0, DelayBeforeShutdown = -1 FeatureReport 19 Field 0, app UPS, phys --- Usage 0, DelayBeforeReboot = 0 Seconds FeatureReport 8 Field 0, app UPS, phys --- Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 10 Field 0, app UPS, phys --- Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 11 Field 0, app UPS, phys --- Usage 0, Voltage = 1351 CentiVolts FeatureReport 20 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 1 FeatureReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 6 FeatureReport 23 Field 0, app UPS, phys Battery Usage 0, APCBattCapBeforeStartup = 0 FeatureReport 27 Field 0, app UPS, phys Battery Usage 0, [ff86001a] = 0 FeatureReport 28 Field 0, app UPS, phys Battery Usage 0, [ff86001b] = 0 FeatureReport 69 Field 0, app UPS, phys Battery Usage 0, APCBattReplacementDate = 1053190 2006-10-12 FeatureReport 21 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 13644 2006-10-12 FeatureReport 24 Field 0, app UPS, phys Battery Exponent 0 lost. Usage 0, RemainingCapacity = 1000 percent FeatureReport 26 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 25 Field 0, app UPS, phys Battery Usage 0, RunTimeToEmpty = 1507 Seconds FeatureReport 30 Field 0, app UPS, phys Battery Usage 0, Temperature = 3023 Degrees K with -1 exponent FeatureReport 31 Field 0, app UPS, phys Battery Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 29 Field 0, app UPS, phys Battery Usage 0, Voltage = 1351 CentiVolts FeatureReport 71 Field 0, app UPS, phys Battery Usage 0, APC860024_?????? = 240 FeatureReport 72 Field 0, app UPS, phys Battery Usage 0, [ff860018] = 0 FeatureReport 32 Field 0, app UPS, phys Input Usage 0, Voltage = 0 DeciVolts FeatureReport 70 Field 0, app UPS, phys Input Usage 0, ConfigVoltage = 230 Volts FeatureReport 33 Field 0, app UPS, phys Input Usage 0, APCLineFailCause = 12 FeatureReport 34 Field 0, app UPS, phys Input Usage 0, APC860061_?????? = 1 FeatureReport 66 Field 0, app UPS, phys Input Usage 0, APC860024_?????? = 126 FeatureReport 44 Field 0, app UPS, phys Output Usage 0, PercentLoad = 250 FeatureReport 82 Field 0, app UPS, phys Output Usage 0, ConfigActivePower = 400 Watts FeatureReport 42 Field 0, app UPS, phys Output Usage 0, Frequency = 5000 CentiHertz FeatureReport 43 Field 0, app UPS, phys Output Usage 0, Voltage = 2300 DeciVolts FeatureReport 45 Field 0, app UPS, phys Output Usage 0, ConfigVoltage = 0 Volts FeatureReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = 260 Volts FeatureReport 36 Field 0, app UPS, phys Output Usage 0, LowVoltageTransfer = 0 Volts FeatureReport 37 Field 0, app UPS, phys Output Usage 0, APCDelayBeforeStartup = 0 Seconds FeatureReport 38 Field 0, app UPS, phys Output Usage 0, APCShutdownAfterDelay = 0 Seconds FeatureReport 39 Field 0, app UPS, phys Output Usage 0, DelayBeforeShutdown = -1 FeatureReport 40 Field 0, app UPS, phys Output Usage 0, DelayBeforeStartup = 0 Seconds FeatureReport 41 Field 0, app UPS, phys Output Usage 0, DelayBeforeReboot = 0 Seconds FeatureReport 64 Field 0, app UPS, phys Output Usage 0, APCForceShutdown = 0 FeatureReport 65 Field 0, app UPS, phys Output Usage 0, APCDelayBeforeShutdown = -1 Seconds FeatureReport 46 Field 0, app UPS, phys --- Usage 0, iProduct = 5 Back-UPS CS 650 FeatureReport 47 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 QB0642232674 FeatureReport 48 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 49 Field 0, app UPS, phys --- Usage 0, iName = 6 APC FeatureReport 52 Field 0, app UPS, phys --- Usage 0, APC_UPS_FirmwareRevision = 7 FeatureReport 55 Field 0, app UPS, phys --- Usage 0, APC_USB_FirmwareRevision = 8 FeatureReport 50 Field 0, app UPS, phys --- Usage 0, APCPanelTest = 0 FeatureReport 53 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 13644 2006-10-12 FeatureReport 62 Field 0, app UPS, phys --- Usage 0, [ff860027] = 0 FeatureReport 63 Field 0, app UPS, phys --- Usage 0, [ff860028] = 0 FeatureReport 54 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 1 FeatureReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 96 Field 0, app UPS, phys [ff860001] Usage 0, APC860023_?????? = 0 FeatureReport 97 Field 0, app UPS, phys [ff860001] Usage 0, APC860026_?????? = 14 FeatureReport 98 Field 0, app UPS, phys [ff860001] Usage 0, APC860025_?????? = 0 FeatureReport 81 Field 0, app UPS, phys PowerConverter Usage 0, APC860024_?????? = 148 Waiting for events ... (interrupt to exit) Event: RunTimeToEmpty = 1507 Event: RunTimeToEmpty = 1507 Event: RunTimeToEmpty = 1485 Event: RunTimeToEmpty = 1462 Event: RunTimeToEmpty = 1485 Event: RunTimeToEmpty = 1507 Event: RunTimeToEmpty = 1530 Event: RunTimeToEmpty = 1507 Event: RunTimeToEmpty = 1530 apcupsd-3.14.14/examples/rpt/Back-UPS-ES-550.rpt000066400000000000000000000224441274230402600206240ustar00rootroot00000000000000FROM: Jan Ceuleers Found UPS at /dev/usb/hid/hiddev0 hiddev driver version is 1.0.4 HID: vendor 0x51d product 0x2 version 0x106 app UPS HID: bus: 1 devnum: 2 ifnum: 0 UPS HID device name: "APC Back-UPS ES 550 FW:828.D2.I USB FW:D2" Battery Chemistry: "PbAc" (4) InputReport 6 Field 0, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 InputReport 12 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 1755 Seconds InputReport 22 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, ACPresent = 1 Field 3, app UPS, phys PowerSummary Usage 0, BatteryPresent = 1 Field 4, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys PowerSummary Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys PowerSummary Usage 0, NeedReplacement = 0 Field 8, app UPS, phys PowerSummary Usage 0, Overload = 0 Field 9, app UPS, phys PowerSummary Usage 0, --- = 0 Usage 1, --- = 0 Usage 2, --- = 0 Usage 3, --- = 0 Usage 4, --- = 0 Usage 5, --- = 0 Usage 6, --- = 0 Usage 7, --- = 0 Usage 8, --- = 0 Usage 9, --- = 0 Usage 10, --- = 0 Usage 11, --- = 0 Usage 12, --- = 0 Usage 13, --- = 0 Usage 14, --- = 0 Usage 15, --- = 0 Usage 16, --- = 0 Usage 17, --- = 0 Usage 18, --- = 0 Usage 19, --- = 0 Usage 20, --- = 0 Usage 21, --- = 0 Usage 22, --- = 0 FeatureReport 1 Field 0, app UPS, phys PowerSummary Usage 0, iProduct = 1 Back-UPS ES 550 FW:828.D2.I USB FW:D2 FeatureReport 2 Field 0, app UPS, phys PowerSummary Usage 0, iSerialNumber = 2 5B0649U02550 FeatureReport 3 Field 0, app UPS, phys PowerSummary Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 4 Field 0, app UPS, phys PowerSummary Usage 0, iOEMInformation = 3 APC FeatureReport 5 Field 0, app UPS, phys PowerSummary Usage 0, Rechargeable = 1 FeatureReport 6 Field 0, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 FeatureReport 7 Field 0, app UPS, phys PowerSummary Usage 0, ManufactureDate = 13692 2006-11-28 FeatureReport 8 Field 0, app UPS, phys PowerSummary Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 9 Field 0, app UPS, phys PowerSummary Usage 0, Voltage = 1353 CentiVolts FeatureReport 10 Field 0, app UPS, phys PowerSummary Usage 0, iManufacturer = 3 APC FeatureReport 11 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 12 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 1755 Seconds FeatureReport 13 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, DesignCapacity = 100 percent FeatureReport 14 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 15 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 16 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 17 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 18 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent FeatureReport 22 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, ACPresent = 1 Field 3, app UPS, phys PowerSummary Usage 0, BatteryPresent = 1 Field 4, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys PowerSummary Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys PowerSummary Usage 0, NeedReplacement = 0 Field 8, app UPS, phys PowerSummary Usage 0, Overload = 0 Field 9, app UPS, phys PowerSummary Usage 0, --- = 0 Usage 1, --- = 0 Usage 2, --- = 0 Usage 3, --- = 0 Usage 4, --- = 0 Usage 5, --- = 0 Usage 6, --- = 0 Usage 7, --- = 0 Usage 8, --- = 0 Usage 9, --- = 0 Usage 10, --- = 0 Usage 11, --- = 0 Usage 12, --- = 0 Usage 13, --- = 0 Usage 14, --- = 0 Usage 15, --- = 0 Usage 16, --- = 0 Usage 17, --- = 0 Usage 18, --- = 0 Usage 19, --- = 0 Usage 20, --- = 0 Usage 21, --- = 0 Usage 22, --- = 0 FeatureReport 23 Field 0, app UPS, phys PowerSummary Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 24 Field 0, app UPS, phys PowerSummary Usage 0, AudibleAlarmControl = 1 FeatureReport 28 Field 0, app UPS, phys Battery Usage 0, APCBattReplacementDate = 0 2000-00-00 FeatureReport 32 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 13692 2006-11-28 FeatureReport 34 Field 0, app UPS, phys Battery Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent FeatureReport 35 Field 0, app UPS, phys Battery Usage 0, RunTimeToEmpty = 1755 Seconds FeatureReport 36 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 37 Field 0, app UPS, phys Battery Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 38 Field 0, app UPS, phys Battery Usage 0, Voltage = 1353 CentiVolts FeatureReport 39 Field 0, app UPS, phys Battery Usage 0, APC860024_?????? = 240 FeatureReport 40 Field 0, app UPS, phys Battery Usage 0, [ff860018] = 0 FeatureReport 48 Field 0, app UPS, phys Input Usage 0, ConfigVoltage = 230 Volts FeatureReport 49 Field 0, app UPS, phys Input Usage 0, Voltage = 230 Volts FeatureReport 50 Field 0, app UPS, phys Input Usage 0, LowVoltageTransfer = 190 Volts FeatureReport 51 Field 0, app UPS, phys Input Usage 0, HighVoltageTransfer = 260 Volts FeatureReport 52 Field 0, app UPS, phys Input Usage 0, APC860024_?????? = 128 FeatureReport 53 Field 0, app UPS, phys Input Usage 0, APC860061_?????? = 1 FeatureReport 54 Field 0, app UPS, phys Input Usage 0, APCLineFailCause = 0 FeatureReport 64 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCForceShutdown = 0 FeatureReport 65 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCDelayBeforeShutdown = -1 Seconds FeatureReport 80 Field 0, app UPS, phys PowerConverter Usage 0, PercentLoad = 14 FeatureReport 81 Field 0, app UPS, phys PowerConverter Usage 0, APC860024_?????? = 124 FeatureReport 96 Field 0, app UPS, phys [ff860001] Usage 0, APC860023_?????? = 0 FeatureReport 97 Field 0, app UPS, phys [ff860001] Usage 0, APC860026_?????? = 10 FeatureReport 98 Field 0, app UPS, phys [ff860001] Usage 0, APC860025_?????? = 0 FeatureReport 127 Field 0, app UPS, phys --- Usage 0, iProduct = 6 828.D2.I FeatureReport 126 Field 0, app UPS, phys --- Usage 0, APC_UPS_FirmwareRevision = 5 FeatureReport 125 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 5B0649U02550 FeatureReport 124 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 APC FeatureReport 123 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 13692 2006-11-28 FeatureReport 122 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 8, app UPS, phys --- Usage 0, Overload = 0 Field 9, app UPS, phys --- Usage 0, --- = 0 Usage 1, --- = 0 Usage 2, --- = 0 Usage 3, --- = 0 Usage 4, --- = 0 Usage 5, --- = 0 Usage 6, --- = 0 Usage 7, --- = 0 Usage 8, --- = 0 Usage 9, --- = 0 Usage 10, --- = 0 Usage 11, --- = 0 Usage 12, --- = 0 Usage 13, --- = 0 Usage 14, --- = 0 Usage 15, --- = 0 Usage 16, --- = 0 Usage 17, --- = 0 Usage 18, --- = 0 Usage 19, --- = 0 Usage 20, --- = 0 Usage 21, --- = 0 Usage 22, --- = 0 FeatureReport 121 Field 0, app UPS, phys --- Usage 0, APCPanelTest = 0 FeatureReport 120 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 1 Waiting for events ... (interrupt to exit) apcupsd-3.14.14/examples/rpt/Back-UPS-XS-1300-LCD.rpt000066400000000000000000000262301274230402600213160ustar00rootroot00000000000000FROM: Michael Guidero Found UPS at /dev/hiddev0 hiddev driver version is 1.0.4 HID: vendor 0x51d product 0x2 version 0x101 app UPS HID: bus: 2 devnum: 2 ifnum: 0 UPS HID device name: "American Power Conversion Back-UPS XS 1300 LCD FW:836.H4 .D USB" Battery Chemistry: "PbAc" (4) InputReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 InputReport 12 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 1356 Seconds InputReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 InputReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 InputReport 22 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, ACPresent = 1 Field 3, app UPS, phys PowerSummary Usage 0, BatteryPresent = 1 Field 4, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys PowerSummary Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys PowerSummary Usage 0, CommunicationLost = 0 Field 8, app UPS, phys PowerSummary Usage 0, NeedReplacement = 0 Field 9, app UPS, phys PowerSummary Usage 0, Overload = 0 Field 10, app UPS, phys PowerSummary Usage 0, VoltageNotRegulated = 0 Field 11, app UPS, phys PowerSummary Usage 0, --- = 0 Usage 1, --- = 0 Usage 2, --- = 0 Usage 3, --- = 0 Usage 4, --- = 0 Usage 5, --- = 0 Usage 6, --- = 0 Usage 7, --- = 0 Usage 8, --- = 0 Usage 9, --- = 0 Usage 10, --- = 0 Usage 11, --- = 0 Usage 12, --- = 0 Usage 13, --- = 0 Usage 14, --- = 0 Usage 15, --- = 0 Usage 16, --- = 0 Usage 17, --- = 0 Usage 18, --- = 0 Usage 19, --- = 0 Usage 20, --- = 0 InputReport 33 Field 0, app UPS, phys Battery Usage 0, Test = 6 FeatureReport 1 Field 0, app UPS, phys PowerSummary Usage 0, iProduct = 1 Back-UPS XS 1300 LCD FW:836.H4 .D USB FW:H4 FeatureReport 2 Field 0, app UPS, phys PowerSummary Usage 0, iSerialNumber = 2 JB0641011335 FeatureReport 3 Field 0, app UPS, phys PowerSummary Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 4 Field 0, app UPS, phys PowerSummary Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys PowerSummary Usage 0, Rechargeable = 1 FeatureReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 FeatureReport 7 Field 0, app UPS, phys PowerSummary Usage 0, ManufactureDate = 16 1980-00-16 FeatureReport 8 Field 0, app UPS, phys PowerSummary Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 9 Field 0, app UPS, phys PowerSummary Usage 0, Voltage = 2689 CentiVolts FeatureReport 10 Field 0, app UPS, phys PowerSummary Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 11 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 12 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 1356 Seconds FeatureReport 13 Field 0, app UPS, phys PowerSummary Exponent 0 lost. Usage 0, DesignCapacity = 100 percent FeatureReport 14 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 15 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 16 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 17 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 18 Field 0, app UPS, phys PowerSummary Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent FeatureReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 FeatureReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 21 Field 0, app UPS, phys PowerSummary Usage 0, DelayBeforeShutdown = -1 FeatureReport 22 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, ACPresent = 0 Field 3, app UPS, phys PowerSummary Usage 0, BatteryPresent = 0 Field 4, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys PowerSummary Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys PowerSummary Usage 0, CommunicationLost = 0 Field 8, app UPS, phys PowerSummary Usage 0, NeedReplacement = 0 Field 9, app UPS, phys PowerSummary Usage 0, Overload = 0 Field 10, app UPS, phys PowerSummary Usage 0, VoltageNotRegulated = 0 Field 11, app UPS, phys PowerSummary Usage 0, --- = 0 Usage 1, --- = 0 Usage 2, --- = 0 Usage 3, --- = 0 Usage 4, --- = 0 Usage 5, --- = 0 Usage 6, --- = 0 Usage 7, --- = 0 Usage 8, --- = 0 Usage 9, --- = 0 Usage 10, --- = 0 Usage 11, --- = 0 Usage 12, --- = 0 Usage 13, --- = 0 Usage 14, --- = 0 Usage 15, --- = 0 Usage 16, --- = 0 Usage 17, --- = 0 Usage 18, --- = 0 Usage 19, --- = 0 Usage 20, --- = 0 FeatureReport 23 Field 0, app UPS, phys PowerSummary Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 24 Field 0, app UPS, phys PowerSummary Usage 0, AudibleAlarmControl = 2 FeatureReport 28 Field 0, app UPS, phys Battery Usage 0, APCBattReplacementDate = 0 2000-00-00 FeatureReport 32 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 13638 2006-10-06 FeatureReport 33 Field 0, app UPS, phys Battery Usage 0, Test = 6 FeatureReport 34 Field 0, app UPS, phys Battery Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent FeatureReport 35 Field 0, app UPS, phys Battery Usage 0, RunTimeToEmpty = 1356 Seconds FeatureReport 36 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 37 Field 0, app UPS, phys Battery Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 38 Field 0, app UPS, phys Battery Usage 0, Voltage = 2672 CentiVolts FeatureReport 39 Field 0, app UPS, phys Battery Usage 0, APC860024_?????? = 245 FeatureReport 40 Field 0, app UPS, phys Battery Usage 0, [ff860018] = 0 FeatureReport 48 Field 0, app UPS, phys Input Usage 0, ConfigVoltage = 120 Volts FeatureReport 49 Field 0, app UPS, phys Input Usage 0, Voltage = 116 Volts FeatureReport 50 Field 0, app UPS, phys Input Usage 0, LowVoltageTransfer = 88 Volts FeatureReport 51 Field 0, app UPS, phys Input Usage 0, HighVoltageTransfer = 139 Volts FeatureReport 52 Field 0, app UPS, phys Input Usage 0, APC860024_?????? = 127 FeatureReport 53 Field 0, app UPS, phys Input Usage 0, APCSensitivity = 1 FeatureReport 54 Field 0, app UPS, phys Input Usage 0, APCLineFailCause = 11 FeatureReport 64 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCForceShutdown = 0 FeatureReport 65 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCDelayBeforeShutdown = -1 Seconds FeatureReport 66 Field 0, app UPS, phys APCGeneralCollection Usage 0, DelayBeforeShutdown = -1 FeatureReport 80 Field 0, app UPS, phys PowerConverter Usage 0, PercentLoad = 26 FeatureReport 81 Field 0, app UPS, phys PowerConverter Usage 0, APC860024_?????? = 225 FeatureReport 82 Field 0, app UPS, phys PowerConverter Usage 0, ConfigActivePower = 780 Watts FeatureReport 96 Field 0, app UPS, phys [ff860001] Usage 0, APC860023_?????? = 0 FeatureReport 97 Field 0, app UPS, phys [ff860001] Usage 0, APC860026_?????? = 16 FeatureReport 98 Field 0, app UPS, phys [ff860001] Usage 0, APC860025_?????? = 0 FeatureReport 127 Field 0, app UPS, phys --- Usage 0, iProduct = 5 Back-UPS XS 1300 LCD FeatureReport 126 Field 0, app UPS, phys --- Usage 0, APC_UPS_FirmwareRevision = 7 FeatureReport 125 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 JB0641011335 FeatureReport 124 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 123 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 13638 2006-10-06 FeatureReport 122 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 0 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 0 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 6, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 7, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 8, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 9, app UPS, phys --- Usage 0, Overload = 0 Field 10, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 11, app UPS, phys --- Usage 0, --- = 0 Usage 1, --- = 0 Usage 2, --- = 0 Usage 3, --- = 0 Usage 4, --- = 0 Usage 5, --- = 0 Usage 6, --- = 0 Usage 7, --- = 0 Usage 8, --- = 0 Usage 9, --- = 0 Usage 10, --- = 0 Usage 11, --- = 0 Usage 12, --- = 0 Usage 13, --- = 0 Usage 14, --- = 0 Usage 15, --- = 0 Usage 16, --- = 0 Usage 17, --- = 0 Usage 18, --- = 0 Usage 19, --- = 0 Usage 20, --- = 0 FeatureReport 121 Field 0, app UPS, phys --- Usage 0, APCPanelTest = 0 FeatureReport 120 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 FeatureReport 117 Field 0, app UPS, phys --- Usage 0, APC860029_?????? = 98 FeatureReport 116 Field 0, app UPS, phys --- Usage 0, APC86002A_?????? = 0 FeatureReport 128 Field 0, app UPS, phys --- Usage 0, [ff000055] = 157 FeatureReport 129 Field 0, app UPS, phys --- Usage 0, [ff000058] = 0 Usage 1, [ff000058] = 0 Usage 2, [ff000058] = 0 Usage 3, [ff000058] = 0 Usage 4, [ff000058] = 0 Usage 5, [ff000058] = 0 FeatureReport 130 Field 0, app UPS, phys --- Usage 0, [ff000059] = 157 FeatureReport 131 Field 0, app UPS, phys --- Usage 0, [ff000060] = 157 Waiting for events ... (interrupt to exit) Event: ManufactureDate = 13638 Event: Voltage = 2689 Event: Voltage = 2672 Event: [ff000055] = 157 Event: ManufactureDate = 16 Event: [ff000059] = 157 Event: [ff000060] = 157 apcupsd-3.14.14/examples/rpt/BackUPS.rpt000066400000000000000000000067061274230402600177360ustar00rootroot00000000000000hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x100 app UPS HID: bus: 1 devnum: 22 ifnum: 0 UPS HID device name: "American Power Conversion Back-UPS 350 FW: 5.2.I USB FW: c1 " Battery Chemistry: "PbAc" (4) InputReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 InputReport 12 Field 0, app UPS, phys PowerSummary Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 2580 Seconds InputReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 InputReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 1 Field 0, app UPS, phys PowerSummary Usage 0, iProduct = 1 Back-UPS 350 FW: 5.2.I USB FW: c1 FeatureReport 2 Field 0, app UPS, phys PowerSummary Usage 0, iSerialNumber = 2 B%0%0%0%0%0% FeatureReport 3 Field 0, app UPS, phys PowerSummary Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 4 Field 0, app UPS, phys PowerSummary Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys PowerSummary Usage 0, Rechargeable = 1 FeatureReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 FeatureReport 7 Field 0, app UPS, phys PowerSummary Usage 0, ManufactureDate = 10896 2001-04-16 FeatureReport 8 Field 0, app UPS, phys PowerSummary Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 9 Field 0, app UPS, phys PowerSummary Usage 0, Voltage = 1335 CentiVolts FeatureReport 10 Field 0, app UPS, phys PowerSummary Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 11 Field 0, app UPS, phys PowerSummary Usage 0, CapacityMode = 2 percent FeatureReport 12 Field 0, app UPS, phys PowerSummary Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 2580 Seconds FeatureReport 13 Field 0, app UPS, phys PowerSummary Usage 0, DesignCapacity = 100 percent FeatureReport 14 Field 0, app UPS, phys PowerSummary Usage 0, FullChargeCapacity = 100 percent FeatureReport 15 Field 0, app UPS, phys PowerSummary Usage 0, WarningCapacityLimit = 50 percent FeatureReport 16 Field 0, app UPS, phys PowerSummary Usage 0, CapacityGranularity2 = 1 percent FeatureReport 17 Field 0, app UPS, phys PowerSummary Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 18 Field 0, app UPS, phys PowerSummary Usage 0, CapacityGranularity1 = 1 percent FeatureReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 FeatureReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 53 Field 0, app UPS, phys PowerSummary Usage 0, APCPanelTest = 0 FeatureReport 28 Field 0, app UPS, phys PowerSummary Usage 0, APCBattReplacementDate = 267777 2001-04-16 FeatureReport 64 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCForceShutdown = 0 Waiting for events ... (interrupt to exit) apcupsd-3.14.14/examples/rpt/Smart-UPS-1500.rpt000066400000000000000000000262371274230402600206250ustar00rootroot00000000000000FROM: Marc Swenson Found UPS at /dev/usb/hid/hiddev0 hiddev driver version is 1.0.4 HID: vendor 0x51d product 0x2 version 0x6 app UPS HID: bus: 2 devnum: 2 ifnum: 0 UPS HID device name: "American Power Conversion Smart-UPS 1500 FW:601.3.D USB FW:1.5" Battery Chemistry: "PbAc" (4) InputReport 12 Field 0, app UPS, phys --- Exponent 0 lost. Usage 0, RemainingCapacity = 76 percent InputReport 13 Field 0, app UPS, phys --- Usage 0, RunTimeToEmpty = 240 Seconds InputReport 8 Field 0, app UPS, phys --- Usage 0, RemainingTimeLimit = 0 Seconds InputReport 20 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 InputReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 1 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 InputReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 6 InputReport 23 Field 0, app UPS, phys Battery Usage 0, APCBattCapBeforeStartup = 15 InputReport 27 Field 0, app UPS, phys Battery Usage 0, [ff86001a] = 3 InputReport 28 Field 0, app UPS, phys Battery Usage 0, [ff86001b] = 0 InputReport 21 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 12409 2004-03-25 InputReport 26 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 Seconds InputReport 33 Field 0, app UPS, phys Input Usage 0, APCLineFailCause = 4 InputReport 34 Field 0, app UPS, phys Input Usage 0, APCSensitivity = 2 InputReport 45 Field 0, app UPS, phys Output Usage 0, ConfigVoltage = 120 Volts InputReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = 127 Volts InputReport 36 Field 0, app UPS, phys Output Usage 0, LowVoltageTransfer = 106 Volts InputReport 37 Field 0, app UPS, phys Output Usage 0, APCDelayBeforeStartup = 60 Seconds InputReport 38 Field 0, app UPS, phys Output Usage 0, APCShutdownAfterDelay = 180 Seconds InputReport 54 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 InputReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 1 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 1 Field 0, app UPS, phys --- Usage 0, iProduct = 1 Smart-UPS 1500 FW:601.3.D USB FW:1.5 FeatureReport 2 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 AS0413231246 FeatureReport 3 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 4 Field 0, app UPS, phys --- Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys --- Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 6 Field 0, app UPS, phys --- Usage 0, Rechargeable = 1 Field 1, app UPS, phys --- Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 14 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, DesignCapacity = 100 percent Field 1, app UPS, phys --- Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 12 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, RemainingCapacity = 76 percent FeatureReport 16 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent Field 1, app UPS, phys --- Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 15 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 17 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 9 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 12409 2004-03-25 FeatureReport 13 Field 0, app UPS, phys --- Usage 0, RunTimeToEmpty = 240 Seconds FeatureReport 18 Field 0, app UPS, phys --- Usage 0, DelayBeforeShutdown = -1 FeatureReport 19 Field 0, app UPS, phys --- Usage 0, DelayBeforeReboot = -1 Seconds FeatureReport 8 Field 0, app UPS, phys --- Usage 0, RemainingTimeLimit = 0 Seconds FeatureReport 10 Field 0, app UPS, phys --- Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 11 Field 0, app UPS, phys --- Usage 0, Voltage = 2740 CentiVolts FeatureReport 20 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 FeatureReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 1 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 6 FeatureReport 23 Field 0, app UPS, phys Battery Usage 0, APCBattCapBeforeStartup = 15 FeatureReport 27 Field 0, app UPS, phys Battery Usage 0, [ff86001a] = 3 FeatureReport 28 Field 0, app UPS, phys Battery Usage 0, [ff86001b] = 0 FeatureReport 21 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 12409 2004-03-25 FeatureReport 24 Field 0, app UPS, phys Battery Exponent 0 lost. Usage 0, RemainingCapacity = 760 percent FeatureReport 26 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 Seconds FeatureReport 25 Field 0, app UPS, phys Battery Usage 0, RunTimeToEmpty = 240 Seconds FeatureReport 30 Field 0, app UPS, phys Battery Usage 0, Temperature = 3032 Degrees K with -1 exponent FeatureReport 31 Field 0, app UPS, phys Battery Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 29 Field 0, app UPS, phys Battery Usage 0, Voltage = 2740 CentiVolts FeatureReport 32 Field 0, app UPS, phys Input Usage 0, Voltage = 1238 DeciVolts FeatureReport 33 Field 0, app UPS, phys Input Usage 0, APCLineFailCause = 4 FeatureReport 34 Field 0, app UPS, phys Input Usage 0, APCSensitivity = 2 FeatureReport 44 Field 0, app UPS, phys Output Usage 0, PercentLoad = 442 FeatureReport 42 Field 0, app UPS, phys Output Usage 0, Frequency = 6000 CentiHertz FeatureReport 43 Field 0, app UPS, phys Output Usage 0, Voltage = 1238 DeciVolts FeatureReport 45 Field 0, app UPS, phys Output Usage 0, ConfigVoltage = 120 Volts FeatureReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = 127 Volts FeatureReport 36 Field 0, app UPS, phys Output Usage 0, LowVoltageTransfer = 106 Volts FeatureReport 37 Field 0, app UPS, phys Output Usage 0, APCDelayBeforeStartup = 60 Seconds FeatureReport 38 Field 0, app UPS, phys Output Usage 0, APCShutdownAfterDelay = 180 Seconds FeatureReport 39 Field 0, app UPS, phys Output Usage 0, DelayBeforeShutdown = -1 FeatureReport 40 Field 0, app UPS, phys Output Usage 0, DelayBeforeStartup = -1 Seconds FeatureReport 41 Field 0, app UPS, phys Output Usage 0, DelayBeforeReboot = -1 Seconds FeatureReport 46 Field 0, app UPS, phys --- Usage 0, iProduct = 5 Smart-UPS 1500 FeatureReport 47 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 AS0413231246 FeatureReport 48 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 49 Field 0, app UPS, phys --- Usage 0, iName = 6 UPS_IDEN FeatureReport 52 Field 0, app UPS, phys --- Usage 0, APC_UPS_FirmwareRevision = 7 FeatureReport 55 Field 0, app UPS, phys --- Usage 0, APC_USB_FirmwareRevision = 8 FeatureReport 50 Field 0, app UPS, phys --- Usage 0, APCPanelTest = 1 FeatureReport 53 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 12409 2004-03-25 FeatureReport 62 Field 0, app UPS, phys --- Usage 0, [ff860027] = 0 FeatureReport 63 Field 0, app UPS, phys --- Usage 0, [ff860028] = 0 FeatureReport 54 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 FeatureReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 1 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 Waiting for events ... (interrupt to exit) Event: RemainingCapacity = 76 Event: RunTimeToEmpty = 240 Event: AudibleAlarmControl = 2 Event: Charging = 1 Event: Discharging = 0 Event: ACPresent = 1 Event: RemainingTimeLimitExpired = 0 Event: [ff86001b] = 0 Event: RemainingCapacity = 760 Event: RunTimeToEmpty = 240 Event: AudibleAlarmControl = 2 Event: RemainingCapacity = 77 apcupsd-3.14.14/examples/rpt/SmartUPS-USB.rpt000066400000000000000000000242401274230402600206040ustar00rootroot00000000000000Found UPS at /dev/usb/hid/hiddev0 hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x6 app UPS HID: bus: 2 devnum: 2 ifnum: 0 UPS HID device name: "American Power Conversion Smart-UPS 1000 FW:600.1.I USB FW:1.2" Battery Chemistry: "PbAc" (4) InputReport 12 Field 0, app UPS, phys --- Exponent 0 lost. Usage 0, RemainingCapacity = 100 percent InputReport 8 Field 0, app UPS, phys --- Usage 0, RemainingTimeLimit = 0 Seconds InputReport 20 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 InputReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 InputReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 1 InputReport 23 Field 0, app UPS, phys Battery Usage 0, [ff860019] = 0 InputReport 27 Field 0, app UPS, phys Battery Usage 0, [ff86001a] = 3 InputReport 28 Field 0, app UPS, phys Battery Usage 0, [ff86001b] = 0 InputReport 21 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 11032 2001-08-24 InputReport 26 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 InputReport 33 Field 0, app UPS, phys Input Usage 0, [ff860052] = 5 InputReport 34 Field 0, app UPS, phys Input Usage 0, [ff860061] = 2 InputReport 45 Field 0, app UPS, phys Output Usage 0, ConfigVoltage = 230 Volts InputReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = 253 Volts InputReport 36 Field 0, app UPS, phys Output Usage 0, LowVoltageTransfer = 208 Volts InputReport 37 Field 0, app UPS, phys Output Usage 0, [ff86007e] = 0 InputReport 38 Field 0, app UPS, phys Output Usage 0, APCShutdownAfterDelay = 90 InputReport 54 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 InputReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 1 Field 0, app UPS, phys --- Usage 0, iProduct = 1 Smart-UPS 1000 FW:600.1.I USB FW:1.2 FeatureReport 2 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 AS0134132215 FeatureReport 3 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 4 Field 0, app UPS, phys --- Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys --- Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 6 Field 0, app UPS, phys --- Usage 0, Rechargeable = 1 Field 1, app UPS, phys --- Exponent 0 lost. Usage 0, CapacityMode = 2 percent FeatureReport 14 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, DesignCapacity = 100 percent Field 1, app UPS, phys --- Exponent 2 lost. Usage 0, FullChargeCapacity = 100 percent FeatureReport 12 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, RemainingCapacity = 100 percent FeatureReport 16 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, CapacityGranularity1 = 1 percent Field 1, app UPS, phys --- Exponent 2 lost. Usage 0, CapacityGranularity2 = 1 percent FeatureReport 15 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, WarningCapacityLimit = 50 percent FeatureReport 17 Field 0, app UPS, phys --- Exponent 2 lost. Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 9 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 11032 2001-08-24 FeatureReport 13 Field 0, app UPS, phys --- Usage 0, RunTimeToEmpty = 21000 Seconds FeatureReport 18 Field 0, app UPS, phys --- Usage 0, DelayBeforeShutdown = -1 FeatureReport 19 Field 0, app UPS, phys --- Usage 0, DelayBeforeReboot = -1 Seconds FeatureReport 8 Field 0, app UPS, phys --- Usage 0, RemainingTimeLimit = 0 Seconds FeatureReport 10 Field 0, app UPS, phys --- Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 11 Field 0, app UPS, phys --- Usage 0, Voltage = 2754 CentiVolts FeatureReport 20 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 FeatureReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 1 FeatureReport 23 Field 0, app UPS, phys Battery Usage 0, [ff860019] = 0 FeatureReport 27 Field 0, app UPS, phys Battery Usage 0, [ff86001a] = 3 FeatureReport 28 Field 0, app UPS, phys Battery Usage 0, [ff86001b] = 0 FeatureReport 21 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 11032 2001-08-24 FeatureReport 24 Field 0, app UPS, phys Battery Exponent 0 lost. Usage 0, RemainingCapacity = 1000 percent FeatureReport 26 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 FeatureReport 25 Field 0, app UPS, phys Battery Usage 0, RunTimeToEmpty = 21000 FeatureReport 30 Field 0, app UPS, phys Battery Usage 0, Temperature = 2996 Degrees K with -1 exponent FeatureReport 31 Field 0, app UPS, phys Battery Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 29 Field 0, app UPS, phys Battery Usage 0, Voltage = 2754 CentiVolts FeatureReport 32 Field 0, app UPS, phys Input Usage 0, Voltage = 2347 DeciVolts FeatureReport 33 Field 0, app UPS, phys Input Usage 0, [ff860052] = 5 FeatureReport 34 Field 0, app UPS, phys Input Usage 0, [ff860061] = 2 FeatureReport 44 Field 0, app UPS, phys Output Usage 0, PercentLoad = 0 FeatureReport 42 Field 0, app UPS, phys Output Usage 0, Frequency = 5000 CentiHertz FeatureReport 43 Field 0, app UPS, phys Output Usage 0, Voltage = 2347 DeciVolts FeatureReport 45 Field 0, app UPS, phys Output Usage 0, ConfigVoltage = 230 Volts FeatureReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = 253 Volts FeatureReport 36 Field 0, app UPS, phys Output Usage 0, LowVoltageTransfer = 208 Volts FeatureReport 37 Field 0, app UPS, phys Output Usage 0, [ff86007e] = 0 FeatureReport 38 Field 0, app UPS, phys Output Usage 0, APCShutdownAfterDelay = 90 FeatureReport 39 Field 0, app UPS, phys Output Usage 0, DelayBeforeShutdown = -1 FeatureReport 40 Field 0, app UPS, phys Output Usage 0, DelayBeforeStartup = -1 Seconds FeatureReport 41 Field 0, app UPS, phys Output Usage 0, DelayBeforeReboot = -1 Seconds FeatureReport 46 Field 0, app UPS, phys --- Usage 0, iProduct = 5 Smart-UPS 1000 FeatureReport 47 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 AS0134132215 FeatureReport 48 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 49 Field 0, app UPS, phys --- Usage 0, iName = 6 UPSIDEN FeatureReport 52 Field 0, app UPS, phys --- Usage 0, APC_UPS_FirmwareRevision = 7 FeatureReport 55 Field 0, app UPS, phys --- Usage 0, APC_USB_FirmwareRevision = 8 FeatureReport 50 Field 0, app UPS, phys --- Usage 0, APCPanelTest = 1 FeatureReport 53 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 11032 2001-08-24 FeatureReport 62 Field 0, app UPS, phys --- Usage 0, [ff860027] = 0 FeatureReport 63 Field 0, app UPS, phys --- Usage 0, [ff860028] = 0 FeatureReport 54 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 FeatureReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 Waiting for events ... (interrupt to exit) apcupsd-3.14.14/examples/rpt/SmartUPS.rpt000066400000000000000000000237661274230402600201710ustar00rootroot00000000000000Found UPS at /dev/usb/hid/hiddev0 hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x6 app UPS HID: bus: 2 devnum: 2 ifnum: 0 UPS HID device name: "American Power Conversion Smart-UPS 1000 FW:600.1.I USB FW:1.2" Battery Chemistry: "PbAc" (4) InputReport 12 Field 0, app UPS, phys --- Usage 0, RemainingCapacity = 100 percent InputReport 8 Field 0, app UPS, phys --- Usage 0, RemainingTimeLimit = 0 Seconds InputReport 20 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 InputReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 InputReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 6 InputReport 23 Field 0, app UPS, phys Battery Usage 0, [ff860019] = 0 InputReport 27 Field 0, app UPS, phys Battery Usage 0, [ff86001a] = 3 InputReport 28 Field 0, app UPS, phys Battery Usage 0, [ff86001b] = 0 InputReport 21 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 11032 2001-08-24 InputReport 26 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 InputReport 33 Field 0, app UPS, phys Input Usage 0, [ff860052] = 0 InputReport 34 Field 0, app UPS, phys Input Usage 0, [ff860061] = 2 InputReport 45 Field 0, app UPS, phys Output Usage 0, ConfigVoltage = 230 Volts InputReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = 253 Volts InputReport 36 Field 0, app UPS, phys Output Usage 0, LowVoltageTransfer = 208 Volts InputReport 37 Field 0, app UPS, phys Output Usage 0, [ff86007e] = 0 InputReport 38 Field 0, app UPS, phys Output Usage 0, APCShutdownAfterDelay = 90 InputReport 54 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 InputReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 1 Field 0, app UPS, phys --- Usage 0, iProduct = 1 Smart-UPS 1000 FW:600.1.I USB FW:1.2 FeatureReport 2 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 AS0134132215 FeatureReport 3 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 4 Field 0, app UPS, phys --- Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys --- Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 6 Field 0, app UPS, phys --- Usage 0, Rechargeable = 1 Field 1, app UPS, phys --- Usage 0, CapacityMode = 2 percent FeatureReport 14 Field 0, app UPS, phys --- Usage 0, DesignCapacity = 100 percent Field 1, app UPS, phys --- Usage 0, FullChargeCapacity = 100 percent FeatureReport 12 Field 0, app UPS, phys --- Usage 0, RemainingCapacity = 100 percent FeatureReport 16 Field 0, app UPS, phys --- Usage 0, CapacityGranularity1 = 1 percent Field 1, app UPS, phys --- Usage 0, CapacityGranularity2 = 1 percent FeatureReport 15 Field 0, app UPS, phys --- Usage 0, WarningCapacityLimit = 50 percent FeatureReport 17 Field 0, app UPS, phys --- Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 9 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 11032 2001-08-24 FeatureReport 13 Field 0, app UPS, phys --- Usage 0, RunTimeToEmpty = 21000 Seconds FeatureReport 18 Field 0, app UPS, phys --- Usage 0, DelayBeforeShutdown = -1 FeatureReport 19 Field 0, app UPS, phys --- Usage 0, DelayBeforeReboot = -1 Seconds FeatureReport 8 Field 0, app UPS, phys --- Usage 0, RemainingTimeLimit = 0 Seconds FeatureReport 10 Field 0, app UPS, phys --- Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 11 Field 0, app UPS, phys --- Usage 0, Voltage = 2754 CentiVolts FeatureReport 20 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 FeatureReport 7 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 FeatureReport 22 Field 0, app UPS, phys Battery Usage 0, Test = 6 FeatureReport 23 Field 0, app UPS, phys Battery Usage 0, [ff860019] = 0 FeatureReport 27 Field 0, app UPS, phys Battery Usage 0, [ff86001a] = 3 FeatureReport 28 Field 0, app UPS, phys Battery Usage 0, [ff86001b] = 0 FeatureReport 21 Field 0, app UPS, phys Battery Usage 0, ManufactureDate = 11032 2001-08-24 FeatureReport 24 Field 0, app UPS, phys Battery Usage 0, RemainingCapacity = 1000 percent FeatureReport 26 Field 0, app UPS, phys Battery Usage 0, RemainingTimeLimit = 120 FeatureReport 25 Field 0, app UPS, phys Battery Usage 0, RunTimeToEmpty = 21000 FeatureReport 30 Field 0, app UPS, phys Battery Usage 0, Temperature = 3001 Degrees K with -1 exponent FeatureReport 31 Field 0, app UPS, phys Battery Usage 0, ConfigVoltage = 2400 CentiVolts FeatureReport 29 Field 0, app UPS, phys Battery Usage 0, Voltage = 2754 CentiVolts FeatureReport 32 Field 0, app UPS, phys Input Usage 0, Voltage = 2304 DeciVolts FeatureReport 33 Field 0, app UPS, phys Input Usage 0, [ff860052] = 0 FeatureReport 34 Field 0, app UPS, phys Input Usage 0, [ff860061] = 2 FeatureReport 44 Field 0, app UPS, phys Output Usage 0, PercentLoad = 0 FeatureReport 42 Field 0, app UPS, phys Output Usage 0, Frequency = 5000 CentiHertz FeatureReport 43 Field 0, app UPS, phys Output Usage 0, Voltage = 2304 DeciVolts FeatureReport 45 Field 0, app UPS, phys Output Usage 0, ConfigVoltage = 230 Volts FeatureReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = 253 Volts FeatureReport 36 Field 0, app UPS, phys Output Usage 0, LowVoltageTransfer = 208 Volts FeatureReport 37 Field 0, app UPS, phys Output Usage 0, [ff86007e] = 0 FeatureReport 38 Field 0, app UPS, phys Output Usage 0, APCShutdownAfterDelay = 90 FeatureReport 39 Field 0, app UPS, phys Output Usage 0, DelayBeforeShutdown = -1 FeatureReport 40 Field 0, app UPS, phys Output Usage 0, DelayBeforeStartup = -1 Seconds FeatureReport 41 Field 0, app UPS, phys Output Usage 0, DelayBeforeReboot = -1 Seconds FeatureReport 46 Field 0, app UPS, phys --- Usage 0, iProduct = 5 Smart-UPS 1000 FeatureReport 47 Field 0, app UPS, phys --- Usage 0, iSerialNumber = 2 AS0134132215 FeatureReport 48 Field 0, app UPS, phys --- Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 49 Field 0, app UPS, phys --- Usage 0, iName = 6 UPSIDEN FeatureReport 52 Field 0, app UPS, phys --- Usage 0, APC_UPS_FirmwareRevision = 7 FeatureReport 55 Field 0, app UPS, phys --- Usage 0, APC_USB_FirmwareRevision = 8 FeatureReport 50 Field 0, app UPS, phys --- Usage 0, APCPanelTest = 1 FeatureReport 53 Field 0, app UPS, phys --- Usage 0, ManufactureDate = 11032 2001-08-24 FeatureReport 62 Field 0, app UPS, phys --- Usage 0, [ff860027] = 0 FeatureReport 63 Field 0, app UPS, phys --- Usage 0, [ff860028] = 0 FeatureReport 54 Field 0, app UPS, phys --- Usage 0, AudibleAlarmControl = 2 FeatureReport 51 Field 0, app UPS, phys --- Usage 0, Charging = 0 Field 1, app UPS, phys --- Usage 0, Discharging = 0 Field 2, app UPS, phys --- Usage 0, ACPresent = 1 Field 3, app UPS, phys --- Usage 0, BatteryPresent = 1 Field 4, app UPS, phys --- Usage 0, BelowRemainingCapacityLimit = 0 Field 5, app UPS, phys --- Usage 0, ShutdownRequested = 0 Field 6, app UPS, phys --- Usage 0, ShutdownImminent = 0 Field 7, app UPS, phys --- Usage 0, RemainingTimeLimitExpired = 0 Field 8, app UPS, phys --- Usage 0, CommunicationLost = 0 Field 9, app UPS, phys --- Usage 0, NeedReplacement = 0 Field 10, app UPS, phys --- Usage 0, Overload = 0 Field 11, app UPS, phys --- Usage 0, VoltageNotRegulated = 0 Field 12, app UPS, phys --- Usage 0, [ff860080] = 0 Waiting for events ... (interrupt to exit) apcupsd-3.14.14/examples/rpt/hid-ups.rpt000066400000000000000000000067061274230402600200570ustar00rootroot00000000000000hiddev driver version is 1.0.2 HID: vendor 0x51d product 0x2 version 0x100 app UPS HID: bus: 1 devnum: 22 ifnum: 0 UPS HID device name: "American Power Conversion Back-UPS 350 FW: 5.2.I USB FW: c1 " Battery Chemistry: "PbAc" (4) InputReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 InputReport 12 Field 0, app UPS, phys PowerSummary Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 2580 Seconds InputReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 InputReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 1 Field 0, app UPS, phys PowerSummary Usage 0, iProduct = 1 Back-UPS 350 FW: 5.2.I USB FW: c1 FeatureReport 2 Field 0, app UPS, phys PowerSummary Usage 0, iSerialNumber = 2 B%0%0%0%0%0% FeatureReport 3 Field 0, app UPS, phys PowerSummary Usage 0, iDeviceChemistry = 4 PbAc FeatureReport 4 Field 0, app UPS, phys PowerSummary Usage 0, iOEMInformation = 3 American Power Conversion FeatureReport 5 Field 0, app UPS, phys PowerSummary Usage 0, Rechargeable = 1 FeatureReport 6 Field 0, app UPS, phys PowerSummary Usage 0, Charging = 0 Field 1, app UPS, phys PowerSummary Usage 0, Discharging = 0 Field 2, app UPS, phys PowerSummary Usage 0, APCStatusFlag = 8 0x8 FeatureReport 7 Field 0, app UPS, phys PowerSummary Usage 0, ManufactureDate = 10896 2001-04-16 FeatureReport 8 Field 0, app UPS, phys PowerSummary Usage 0, ConfigVoltage = 1200 CentiVolts FeatureReport 9 Field 0, app UPS, phys PowerSummary Usage 0, Voltage = 1335 CentiVolts FeatureReport 10 Field 0, app UPS, phys PowerSummary Usage 0, iManufacturer = 3 American Power Conversion FeatureReport 11 Field 0, app UPS, phys PowerSummary Usage 0, CapacityMode = 2 percent FeatureReport 12 Field 0, app UPS, phys PowerSummary Usage 0, RemainingCapacity = 100 percent Field 1, app UPS, phys PowerSummary Usage 0, RunTimeToEmpty = 2580 Seconds FeatureReport 13 Field 0, app UPS, phys PowerSummary Usage 0, DesignCapacity = 100 percent FeatureReport 14 Field 0, app UPS, phys PowerSummary Usage 0, FullChargeCapacity = 100 percent FeatureReport 15 Field 0, app UPS, phys PowerSummary Usage 0, WarningCapacityLimit = 50 percent FeatureReport 16 Field 0, app UPS, phys PowerSummary Usage 0, CapacityGranularity2 = 1 percent FeatureReport 17 Field 0, app UPS, phys PowerSummary Usage 0, RemainingCapacityLimit = 10 percent FeatureReport 18 Field 0, app UPS, phys PowerSummary Usage 0, CapacityGranularity1 = 1 percent FeatureReport 19 Field 0, app UPS, phys PowerSummary Usage 0, ACPresent = 1 FeatureReport 20 Field 0, app UPS, phys PowerSummary Usage 0, BelowRemainingCapacityLimit = 0 Field 1, app UPS, phys PowerSummary Usage 0, ShutdownImminent = 0 FeatureReport 53 Field 0, app UPS, phys PowerSummary Usage 0, APCPanelTest = 0 FeatureReport 28 Field 0, app UPS, phys PowerSummary Usage 0, APCBattReplacementDate = 267777 2001-04-16 FeatureReport 64 Field 0, app UPS, phys APCGeneralCollection Usage 0, APCForceShutdown = 0 Waiting for events ... (interrupt to exit) apcupsd-3.14.14/examples/safe.apccontrol.in000077500000000000000000000052641274230402600205640ustar00rootroot00000000000000#!@SCRIPTSHELL@ # # Safe apccontrol for testing. # # This apccontrol can be used for testing without fear # that it will bring your system down # @configure_input@ # prefix=@prefix@ exec_prefix=@exec_prefix@ APCUPSD=@sbindir@/apcupsd SHUTDOWN=@SHUTDOWN@ SCRIPTDIR=@sysconfdir@ # case "$1" in killpower) wall < #include #include #include #include #include #include #include #define DEFAULT_LINEF 60.0 #define DEFAULT_LOADPCT 25.0 #define DEFAULT_BATTPCT 100.0 #define DEfAULT_TIMELEFT 20.0 #define DEFAULT_BATTV 24.0 #define DEFAULT_LINEV 120.0 #define DEFAULT_OUTV 120.0 #define DEFAULT_REG2 0x00 int debug = 1; int ups = -1; /* UPS variables */ float linefreq = DEFAULT_LINEF; float loadpct = DEFAULT_LOADPCT; float battpct = DEFAULT_BATTPCT; float timeleft = DEfAULT_TIMELEFT; float battv = DEFAULT_BATTV; float linev = DEFAULT_LINEV; float outv = DEFAULT_OUTV; unsigned char reg2 = DEFAULT_REG2; char xfercause[] = "O"; char selftest[] = "OK"; int onbatt = 0; int online = 1; int overload = 0; int battlow = 0; int rebatt = 0; int trim = 0; int boost = 0; int commfail = 0; #define dbg(str, args...) \ do \ { \ if (debug) \ { \ printf(str, ## args); \ fflush(stdout); \ } \ } \ while(0) /* Response callbacks */ static void rsp_string(const void* arg); static void rsp_float(const void* arg); static void rsp_cmds(const void* arg); static void rsp_status(const void* arg); static void rsp_hex(const void *arg); /* Mapping of UPS commands to response callbacks */ struct upscmd { char cmd; void (*func)(const void*); const void* arg; } upscmds[] = { { 'Y', rsp_string, "SM" }, { '\x01', rsp_string, "SMART-UPS Simulator" }, { 'c', rsp_string, "SMARTSIM" }, { 'F', rsp_float, &linefreq }, { 'Q', rsp_status, NULL }, { 'P', rsp_float, &loadpct }, { 'f', rsp_float, &battpct }, { 'a', rsp_cmds, NULL }, { 'j', rsp_float, &timeleft }, { 'G', rsp_string, xfercause }, { 'X', rsp_string, selftest }, { 'B', rsp_float, &battv }, { 'L', rsp_float, &linev }, { 'O', rsp_float, &outv }, { '\'', rsp_hex, ®2 }, { 'V', rsp_string, "Lzy" }, { '\0', NULL, NULL } }; /* The alert characters we support */ const char alerts[] = "!$%+#"; static void key_toggle(const void* arg); static void key_onbatt(const void* arg); static void key_battlow(const void* arg); static void key_inc(const void* arg); static void key_dec(const void* arg); static void key_selftest(const void* arg); static void key_rebatt(const void* arg); static void key_batdet(const void *arg); static void key_commfail(const void *arg); static void key_help(const void *arg); /* Mapping of keyboard commands to callbacks */ struct keycmd { char key; void (*func)(const void*); void* arg; } keycmds[] = { { 'b', key_onbatt, NULL }, { 'o', key_toggle, &overload }, { 't', key_toggle, &trim }, { 's', key_toggle, &boost }, { 'l', key_battlow, NULL }, { '7', key_inc, &battpct }, { '4', key_dec, &battpct }, { '8', key_inc, &loadpct }, { '5', key_dec, &loadpct }, { '9', key_inc, &timeleft }, { '6', key_dec, &timeleft }, { 'x', key_selftest, NULL }, { 'r', key_rebatt, NULL }, { 'd', key_batdet, NULL }, { 'c', key_commfail, NULL }, { '?', key_help, NULL }, { '\0', NULL, NULL } }; /* Defaults */ #define DEFAULT_DEVICE "/dev/ttyS0"; void wups(const char* str, int len) { if (debug) write(fileno(stdout), str, len); write(ups, str, len); } void rsp_string(const void* arg) { wups((char*)arg, strlen((char*)arg)); wups("\r\n", 2); } void rsp_float(const void* arg) { char buf[20]; sprintf(buf, "%03.3f\r\n", *(float*)arg); wups(buf, strlen(buf)); } void rsp_hex(const void* arg) { char buf[20]; sprintf(buf, "%02x\r\n", *(unsigned char*)arg); wups(buf, strlen(buf)); } void rsp_cmds(const void* arg) { int x; /* Protocol version */ wups("3.", 2); /* Supported alert characters */ wups(alerts, sizeof(alerts)-1); wups(".", 1); /* Supported commands */ for (x=0; upscmds[x].func; x++) wups(&upscmds[x].cmd, 1); wups("\r\n", 2); } void rsp_status(const void* arg) { char buf[20]; sprintf(buf, "%02x\r\n", (trim << 1) | (boost << 2) | (online << 3) | (onbatt << 4) | (overload << 5) | (battlow << 6) | (rebatt << 7)); wups(buf, strlen(buf)); } static void key_toggle(const void* arg) { *(int *)arg = !*(int *)arg; } static void key_onbatt(const void* arg) { if (!onbatt) { online = 0; onbatt = 1; xfercause[0] = 'L'; linev = 0; dbg("ALERT: "); wups("!", 1); dbg("\n"); } else { online = 1; onbatt = 0; linev = DEFAULT_LINEV; dbg("ALERT: "); wups("$", 1); dbg("\n"); } } static void key_battlow(const void* arg) { if (!battlow) { battlow = 1; dbg("ALERT: "); wups("%", 1); dbg("\n"); } else { battlow = 0; dbg("ALERT: "); wups("+", 1); dbg("\n"); } } static void key_inc(const void* arg) { *(float*)arg += 1; dbg("%3.3f\n", *(float*)arg); } static void key_dec(const void* arg) { *(float*)arg -= 1; dbg("%3.3f\n", *(float*)arg); } static void key_selftest(const void* arg) { key_onbatt(NULL); if (onbatt) xfercause[0] = 'S'; } static void key_rebatt(const void* arg) { if (!rebatt) { rebatt = 1; dbg("ALERT: "); wups("#", 1); dbg("\n"); } else { rebatt = 0; } } static void key_batdet(const void *arg) { if (reg2 & 0x20) reg2 &= ~0x20; else reg2 |= 0x20; } static void key_commfail(const void *arg) { if (commfail) { commfail = 0; dbg("COMMFAIL disabled\n"); } else { commfail = 1; dbg("COMMFAIL enabled\n"); } } static void key_help(const void *arg) { dbg("Commands:\n"); dbg("? Help\n"); dbg("b Onbattery toggle\n"); dbg("o Overload toggle\n"); dbg("t Trim toggle\n"); dbg("s Boost toggle\n"); dbg("l BattLow toggle\n"); dbg("x Selftest toggle\n"); dbg("r ReplaceBatt toggle\n"); dbg("d BattDetach toggle\n"); dbg("c CommFail toggle\n"); dbg("7/4 BattPct (inc/dec) (use numeric keypad)\n"); dbg("8/5 LoadPct (inc/dec) (use numeric keypad)\n"); dbg("9/6 TimeLeft (inc/dec) (use numeric keypad)\n"); } void handle_ups_cmd(char cmd) { int x; if (commfail) { dbg("\n"); return; } for (x=0; upscmds[x].func; x++) { if (upscmds[x].cmd == cmd) { upscmds[x].func(upscmds[x].arg); break; } } if (!upscmds[x].func) rsp_string("NA"); } void handle_key_cmd(char cmd) { int x; for (x=0; keycmds[x].func; x++) { if (keycmds[x].key == cmd) { keycmds[x].func(keycmds[x].arg); break; } } } #define max(a,b) \ ( ((a) > (b)) ? (a) : (b) ) int main(int argc, char* argv[]) { fd_set fds; int rc; char cmd; struct termios tio; const char* dev; int con; /* Allow serial port device to be supplied on command line */ if (argc == 2) dev = argv[1]; else dev = DEFAULT_DEVICE; /* Open serial port device */ ups = open(dev, O_RDWR | O_NOCTTY); if (ups < 0) { perror("open"); return 1; } /* Set serial port for 2400 baud, N81 */ tio.c_cflag = B2400 | CS8 | CLOCAL | CREAD; tio.c_iflag = IGNPAR; /* Ignore errors, raw input */ tio.c_oflag = 0; /* Raw output */ tio.c_lflag = 0; /* No local echo */ cfsetospeed(&tio, B2400); cfsetispeed(&tio, B2400); tcflush(ups, TCIFLUSH); tcsetattr(ups, TCSANOW, &tio); tcflush(ups, TCIFLUSH); /* Disable echo and line buffering on stdin */ con = fileno(stdin); tcgetattr(con, &tio); tio.c_lflag &= ~(ECHO|ICANON); tcsetattr(con, TCSANOW, &tio); while (1) { FD_ZERO(&fds); FD_SET(ups, &fds); FD_SET(con, &fds); do { rc = select(max(con,ups)+1, &fds, NULL, NULL, NULL); } while (rc == -1 && (errno == EAGAIN || errno == EINTR)); if (rc == -1) { perror("select"); return 1; } if (FD_ISSET(ups, &fds)) { do { rc = read(ups, &cmd, 1); } while (rc != 1 && (errno == EAGAIN || errno == EINTR)); if (rc != 1) { perror("read"); return 1; } dbg("CMD: "); if (cmd == 0) dbg(""); else if (cmd >= 1 && cmd <= 26) dbg("^%c", cmd+64); else dbg("%c", cmd); dbg("\nRSP: "); handle_ups_cmd(cmd); } if (FD_ISSET(con, &fds)) { do { rc = read(con, &cmd, 1); } while (rc != 1 && (errno == EAGAIN || errno == EINTR)); if (rc != 1) { perror("read"); return 1; } handle_key_cmd(cmd); } } return 0; } apcupsd-3.14.14/examples/snoopdecode.c000066400000000000000000000246241274230402600176170ustar00rootroot00000000000000/* * snoopdecode.c * * Decodes traces captured by 'usbsnoop' * (http://benoit.papillault.free.fr/usbsnoop/index.php) * * See usbsnoop.txt for details. */ /* * Copyright (C) 2004-2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include #define MAX_LINE 1024 char line[MAX_LINE] = ""; FILE* file; enum { DIR_UNKNOWN = 0, DIR_TO_DEVICE, DIR_FROM_DEVICE }; enum { FUNC_UNKNOWN = 0, FUNC_CONTROL_TXFER, FUNC_CLASS_INTERFACE, FUNC_GET_DESC, FUNC_SELECT_CONFIG, FUNC_GET_DESC_FROM_IFACE, FUNC_BULK_TXFER, FUNC_RESET_PIPE, FUNC_ABORT_PIPE, }; enum { REQ_GET_REPORT = 1, REQ_GET_IDLE = 2, REQ_GET_PROTOCOL = 3, REQ_SET_REPORT = 9, REQ_SET_IDLE = 10, REQ_SET_PROTOCOL = 11 }; struct urb { int seq; unsigned long len; unsigned char* data; unsigned long flags; unsigned long index; unsigned long type; unsigned long reserved; unsigned long request; unsigned long value; int time; int dir; int func; }; struct rpt { struct rpt* next; unsigned char* data; int seq; unsigned short len; unsigned char id; unsigned long value; }; struct rpt* rpts = NULL; /* [197 ms] >>> URB 1 going down >>> -- URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: TransferBufferLength = 00000012 TransferBuffer = 864c9208 TransferBufferMDL = 00000000 Index = 00000000 DescriptorType = 00000001 (USB_DEVICE_DESCRIPTOR_TYPE) LanguageId = 00000000 [203 ms] UsbSnoop - MyInternalIOCTLCompletion(f7b91db0) : fido=00000000, Irp=863df850, Context=86405d10, IRQL=2 [203 ms] <<< URB 1 coming back <<< -- URB_FUNCTION_CONTROL_TRANSFER: PipeHandle = 863e4150 TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000012 TransferBuffer = 864c9208 TransferBufferMDL = 8640f108 00000000: 12 01 10 01 00 00 00 08 1d 05 02 00 06 00 03 01 00000010: 02 01 UrbLink = 00000000 */ /* [59563 ms] >>> URB 346 going down >>> -- URB_FUNCTION_CLASS_INTERFACE: TransferFlags = 00000001 (USBD_TRANSFER_DIRECTION_IN, ~USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000005 TransferBuffer = f7f12ba0 TransferBufferMDL = 00000000 UrbLink = 00000000 RequestTypeReservedBits = 00000022 Request = 00000001 Value = 0000032f Index = 00000000 [59567 ms] UsbSnoop - MyInternalIOCTLCompletion(f7b91db0) : fido=86397288, Irp=85ff4b40, Context=85f4b3d8, IRQL=2 [59567 ms] <<< URB 346 coming back <<< -- URB_FUNCTION_CONTROL_TRANSFER: PipeHandle = 863e4150 TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000002 TransferBuffer = f7f12ba0 TransferBufferMDL = 85f102f0 00000000: 2f 02 UrbLink = 00000000 SetupPacket = 00000000: a1 01 2f 03 00 00 05 00 */ int fetch_line() { return !!fgets(line, sizeof(line), file); } int find_urb() { do { if (line[0] == '[' && strstr(line, " URB ") && (strstr(line, "going down") || strstr(line, "coming back"))) { return 1; } } while( fetch_line() ); return 0; } int init_urb(struct urb* urb) { memset(urb, 0, sizeof(*urb)); if (!find_urb()) return 0; urb->time = atoi(line+1); if (strstr(line, "going down")) urb->dir = DIR_TO_DEVICE; else if(strstr(line, "coming back")) urb->dir = DIR_FROM_DEVICE; else urb->dir = DIR_UNKNOWN; urb->seq = atoi(strstr(line,"URB ")+4); return 1; } unsigned long get_hex_value() { char* ptr = strchr(line, '='); if (!ptr) return 0xffff; return strtoul(ptr+2, NULL, 16); } unsigned char* parse_data_dump(int len) { int count = 0; char* ptr= NULL; unsigned char* data = (unsigned char *)malloc(len); if (!data) return NULL; while(count < len) { if ((count % 16) == 0) { if (count) { if (!fetch_line()) { free(data); return NULL; } } ptr = strchr(line, ':'); if (!ptr) { free(data); return NULL; } ptr += 2; } data[count++] = strtoul(ptr, NULL, 16); ptr += 3; } return data; } void parse_urb_body(struct urb* urb) { int setup_packet = 0; while (fetch_line()) { if (line[0] == '[') break; if (strstr(line, "TransferBufferLength")) { urb->len = get_hex_value(); } else if (strstr(line, "TransferFlags")) { urb->flags = get_hex_value(); } else if (strstr(line, "Index")) { urb->index = get_hex_value(); } else if (strstr(line, "DescriptorType")) { urb->type = get_hex_value(); } else if (strstr(line, "RequestTypeReservedBits")) { urb->reserved = get_hex_value(); } else if (strstr(line, "Request")) { urb->request = get_hex_value(); } else if (strstr(line, "Value")) { urb->value = get_hex_value(); } else if (strstr(line, "SetupPacket")) { setup_packet = 1; } else if (strstr(line, "00000000:")) { if (!setup_packet && !urb->data) urb->data = parse_data_dump(urb->len); } else if (strstr(line, "-- URB_FUNCTION_")) { if (strstr(line, "URB_FUNCTION_CONTROL_TRANSFER")) urb->func = FUNC_CONTROL_TXFER; else if (strstr(line, "URB_FUNCTION_CLASS_INTERFACE")) urb->func = FUNC_CLASS_INTERFACE; else if (strstr(line, "URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE")) urb->func = FUNC_GET_DESC; else if (strstr(line, "URB_FUNCTION_SELECT_CONFIGURATION")) urb->func = FUNC_SELECT_CONFIG; else if (strstr(line, "URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE")) urb->func = FUNC_GET_DESC_FROM_IFACE; else if (strstr(line, "URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER")) urb->func = FUNC_BULK_TXFER; else if (strstr(line, "URB_FUNCTION_RESET_PIPE")) urb->func = FUNC_RESET_PIPE; else if (strstr(line, "URB_FUNCTION_ABORT_PIPE")) urb->func = FUNC_ABORT_PIPE; else { urb->func = FUNC_UNKNOWN; printf("Unknown FUNC: %s\n", line); exit(0); } } } } void free_urb(struct urb* urb) { free(urb->data); } void print_urb(struct urb* urb) { unsigned int x; printf("[%08d ms] %05d %c ", urb->time, urb->seq, (urb->dir == DIR_TO_DEVICE) ? '>' : (urb->dir == DIR_FROM_DEVICE) ? '<' : '?'); printf("req=%04lx value=%04lx", urb->request, urb->value); if( urb->data ) { printf(" ["); for(x=0; xlen; x++) { printf( "%02x", urb->data[x] ); if (x < urb->len-1) printf(" "); } printf("]"); } printf("\n"); } struct rpt* find_report_by_seq(int seq) { struct rpt* rpt = rpts; while( rpt ) { if (rpt->seq == seq) break; rpt = rpt->next; } return rpt; } struct rpt* find_report_by_id(unsigned char id) { struct rpt* rpt = rpts; while( rpt ) { if (rpt->id == id) break; rpt = rpt->next; } return rpt; } void del_report(struct urb* urb) { unsigned char id = urb->data[0]; struct rpt* rpt = rpts; struct rpt** prev = &rpts; while( rpt ) { if (rpt->id == id) break; prev = &(rpt->next); rpt = rpt->next; } if (rpt) { *prev = rpt->next; free(rpt); } } void add_report(struct urb* urb) { struct rpt* rpt; unsigned char id; if (urb->data) id = urb->data[0]; else id = urb->value & 0xff; if ((rpt = find_report_by_id(id))) { rpt->seq = urb->seq; rpt->value = urb->value; return; } rpt = (struct rpt*)malloc(sizeof(*rpt)); memset(rpt, 0, sizeof(*rpt)); rpt->id = id; rpt->seq = urb->seq; rpt->value = urb->value; rpt->next = rpts; rpts = rpt; } int check_and_update_report(struct urb* urb) { struct rpt* rpt; rpt = find_report_by_seq(urb->seq); if (!rpt) return 0; if (rpt->data && !memcmp(rpt->data, urb->data+1, urb->len-1)) return 0; free(rpt->data); rpt->len = urb->len-1; rpt->data = (unsigned char *)malloc(rpt->len); memcpy(rpt->data, urb->data+1, rpt->len); return 1; } void display_report(struct urb* urb) { unsigned long data = 0; char buf[9]; unsigned int n; n = printf( "[%04d s] %05d %c %s 0x%02x (%03u) ", urb->time/1000, urb->seq, urb->func == FUNC_BULK_TXFER ? '*' : ' ', urb->dir==DIR_TO_DEVICE ? "WRITE" : " READ", urb->data[0], urb->data[0]); switch (urb->len) { case 5: data = (data << 8) | urb->data[4]; case 4: data = (data << 8) | urb->data[3]; case 3: data = (data << 8) | urb->data[2]; case 2: data = (data << 8) | urb->data[1]; sprintf(buf, "%0*lx", (int)(urb->len-1)*2, data); n += printf( "%8s (%lu)", buf, data ); break; default: n += printf( "-------- (----------)" ); break; } printf( "%*c", 55-n, ' '); for (n=0; nlen-1; n++) printf("%02x ", urb->data[n+1]); printf("\n"); fflush(stdout); } void update_reports(struct urb* urb) { if (urb->dir == DIR_TO_DEVICE) { // Only care about class requests if (urb->func != FUNC_CLASS_INTERFACE) return; if (urb->request == REQ_GET_REPORT) { add_report(urb); } else if (urb->request == REQ_SET_REPORT) { display_report(urb); del_report(urb); } } else { if (urb->func == FUNC_CONTROL_TXFER) { if (check_and_update_report(urb)) display_report(urb); } else if (urb->data && urb->func == FUNC_BULK_TXFER) { add_report(urb); if (check_and_update_report(urb)) display_report(urb); } } } int main(int argc, char* argv[]) { struct urb urb; file = stdin; while(init_urb(&urb)) { parse_urb_body(&urb); update_reports(&urb); free_urb(&urb); } return 0; } apcupsd-3.14.14/examples/status/000077500000000000000000000000001274230402600164645ustar00rootroot00000000000000apcupsd-3.14.14/examples/status/Back-UPS-BX-1500.status000066400000000000000000000016251274230402600221340ustar00rootroot00000000000000APC : 001,035,0897 DATE : Sun Jun 05 21:20:37 PDT 2005 HOSTNAME : linux RELEASE : 3.10.17 VERSION : 3.10.17 (18 March 2005) suse UPSNAME : APC_BX1500 CABLE : USB Cable MODEL : Back-UPS RS 1500 UPSMODE : Stand Alone STARTTIME: Sun Jun 05 20:29:25 PDT 2005 STATUS : ONLINE LINEV : 118.0 Volts LOADPCT : 0.0 Percent Load Capacity BCHARGE : 100.0 Percent TIMELEFT : 737.5 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds LOTRANS : 097.0 Volts HITRANS : 138.0 Volts ALARMDEL : Always BATTV : 26.8 Volts NUMXFERS : 2 XONBATT : Sun Jun 05 20:49:18 PDT 2005 TONBATT : 0 seconds CUMONBATT: 7 seconds XOFFBATT : Sun Jun 05 20:49:19 PDT 2005 SELFTEST : NO STATFLAG : 0x02000008 Status Flag MANDATE : 2005-02-15 SERIALNO : JB0416347259 BATTDATE : 2001-09-25 NOMBATTV : 24.0 FIRMWARE : .g9 .D USB FW:g9 APCMODEL : Back-UPS RS 1500 END APC : Sun Jun 05 21:21:22 PDT 2005 apcupsd-3.14.14/examples/status/Back-UPS-Pro-1000.status000066400000000000000000000021201274230402600223450ustar00rootroot00000000000000APC : 001,056,1080 DATE : Thu Mar 08 11:22:30 EST 2001 HOSTNAME : doc RELEASE : 3.8.1-3 CABLE : Custom Cable Smart MODEL : BACK-UPS PRO 1000 UPSMODE : Net Master STARTTIME: Thu Mar 08 11:22:12 EST 2001 SHARE : NetworkUPS UPSNAME : N/A STATUS : ONLINE LINEV : N/A LOADPCT : N/A BCHARGE : N/A TIMELEFT : N/A MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 900 Seconds MAXLINEV : N/A MINLINEV : N/A OUTPUTV : N/A SENSE : N/A DWAKE : N/A DSHUTD : N/A DLOWBATT : N/A LOTRANS : N/A HITRANS : N/A RETPCT : N/A ITEMP : N/A ALARMDEL : N/A BATTV : N/A LINEFREQ : N/A LASTXFER : Line voltage notch or spike NUMXFERS : 0 XONBATT : N/A TONBATT : 0 seconds CUMONBATT: 0 seconds XOFFBATT : N/A SELFTEST : NO STESTI : N/A STATFLAG : 0x08 Status Flag DIPSW : N/A REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : N/A SERIALNO : QB0030120516 BATTDATE : N/A NOMOUTV : N/A NOMBATTV : N/A HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : N/A BADBATTS : N/A FIRMWARE : 13.J.D APCMODEL : N/A END APC : Thu Mar 08 11:22:33 EST 2001 apcupsd-3.14.14/examples/status/BackUPS-USB.status000066400000000000000000000014151274230402600216110ustar00rootroot00000000000000APC : 001,029,0757 DATE : Thu Dec 06 10:02:37 CET 2001 HOSTNAME : rufus.sibbald.com RELEASE : 3.9.7 VERSION : 3.9.7 (12 November 2001) redhat UPSNAME : rufus.usb CABLE : USB Cable MODEL : Back-UPS 350 UPSMODE : Stand Alone STARTTIME: Mon Dec 03 17:18:29 CET 2001 STATUS : ONLINE BCHARGE : 100.0 Percent TIMELEFT : 43.0 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds BATTV : 13.3 Volts NUMXFERS : 70 XONBATT : Thu Dec 06 08:39:31 CET 2001 TONBATT : 0 seconds CUMONBATT: 246 seconds XOFFBATT : Thu Dec 06 08:39:32 CET 2001 STATFLAG : 0x008 Status Flag MANDATE : 2001-04-16 SERIALNO : BB0115017954 BATTDATE : 2001-04-16 NOMBATTV : 12.0 FIRMWARE : 5.2.I USB FW: c1 APCMODEL : Back-UPS 350 END APC : Thu Dec 06 10:03:19 CET 2001 apcupsd-3.14.14/examples/status/JapaneseUPS.status000066400000000000000000000021451274230402600220510ustar00rootroot00000000000000APC : 001,050,1103 DATE : Mon Sep 11 13:51:14 JST 2000 HOSTNAME : master RELEASE : 3.7.2 CABLE : Custom Cable Smart MODEL : APC Smart-UPS 1250 UPSMODE : Net Master SHARE : NetworkUPS UPSNAME : UPS_IDEN STATUS : ONLINE LINEV : 098.5 Volts LOADPCT : 20.8 Percent Load Capacity BCHARGE : 100.0 Percent TIMELEFT : 70.0 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 300 Seconds MAXLINEV : 098.5 Volts MINLINEV : 097.9 Volts OUTPUTV : 098.5 Volts SENSE : High DWAKE : 000 Seconds DSHUTD : 020 Seconds DLOWBATT : 02 Minutes LOTRANS : 085.0 Volts HITRANS : 112.0 Volts RETPCT : 090.0 Percent ITEMP : 49.0 C Internal ALARMDEL : 30 seconds BATTV : 27.7 Volts LINEFREQ : 50.0 Hz LASTXFER : High line voltage SELFTEST : NO STESTI : 336 STATFLAG : 0x08 Status Flag DIPSW : 0x00 Dip Switch REG1 : N/A REG2 : N/A REG3 : 0x00 Register 3 MANDATE : 11/14/94 SERIALNO : 01234567 BATTDATE : 10/24/95 NOMOUTV : 100 NOMBATTV : 24.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : N/A BADBATTS : N/A FIRMWARE : N/A APCMODEL : 8VA END APC : Mon Sep 11 13:51:16 JST 2000 apcupsd-3.14.14/examples/status/PowerStack450.status000066400000000000000000000023551274230402600222510ustar00rootroot00000000000000APC : 001,051,1237 DATE : Sun Apr 14 05:52:47 PDT 2002 HOSTNAME : PSI RELEASE : 3.8.5 UPSNAME : UPS_IDEN CABLE : Custom Cable Smart MODEL : PowerStack 450 UPSMODE : Net Master STARTTIME: Sun Mar 31 01:23:34 PST 2002 SHARE : NetworkUPS STATUS : ONLINE LINEV : 122.4 Volts LOADPCT : 44.8 Percent Load Capacity BCHARGE : 100.0 Percent TIMELEFT : 25.0 Minutes MBATTCHG : 5 Percent MINTIMEL : 10 Minutes MAXTIME : 0 Seconds MAXLINEV : 123.8 Volts MINLINEV : 121.6 Volts OUTPUTV : 122.4 Volts SENSE : High DWAKE : 000 Seconds DSHUTD : 020 Seconds DLOWBATT : 02 Minutes LOTRANS : 106.0 Volts HITRANS : 127.0 Volts RETPCT : 000.0 Percent ALARMDEL : 5 seconds BATTV : 13.6 Volts LINEFREQ : 60.0 Hz LASTXFER : Line voltage notch or spike NUMXFERS : 2 XONBATT : Wed Apr 10 00:52:03 PDT 2002 TONBATT : 0 seconds CUMONBATT: 9 seconds XOFFBATT : Wed Apr 10 00:52:09 PDT 2002 LASTSTEST: Wed Apr 10 00:52:03 PDT 2002 SELFTEST : NO STESTI : 336 STATFLAG : 0x008 Status Flag REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 12/18/01 SERIALNO : NS0151240614 BATTDATE : 12/18/01 NOMOUTV : 115 NOMBATTV : 12.0 FIRMWARE : 26.5.D APCMODEL : DWD END APC : Sun Apr 14 05:52:52 PDT 2002 apcupsd-3.14.14/examples/status/SmartUPS-vs-650.status000066400000000000000000000020421274230402600223430ustar00rootroot00000000000000APC : 001,052,0981 DATE : Tue Dec 14 20:43:59 CET 1999 HOSTNAME : azuth RELEASE : 3.7.0-beta-1 CABLE : Custom Cable Smart MODEL : Smart-UPS v/s 650 UPSMODE : Stand Alone LINEFAIL : OK BATTSTAT : OK LINEVOLT : OK UPSNAME : N/A LINEV : N/A MAXLINEV : N/A MINLINEV : N/A LINEFREQ : N/A OUTPUTV : N/A LOADPCT : N/A BATTV : N/A BCHARGE : N/A MBATTCHG : 5 Percent TIMELEFT : N/A MINTIMEL : 3 Minutes MAXTIME : 0 Seconds SENSE : N/A DWAKE : N/A DSHUTD : N/A LOTRANS : N/A HITRANS : N/A RETPCT : N/A STATFLAG : 0x08 Status Flag STATUS : ONLINE ITEMP : N/A ALARMDEL : N/A LASTXFER : Line voltage notch or spike SELFTEST : NO STESTI : N/A DLOWBATT : N/A DIPSW : N/A REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : N/A SERIALNO : gs9734969448 BATTDATE : N/A NOMOUTV : N/A NOMBATTV : N/A HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : N/A BADBATTS : N/A FIRMWARE : 62.J.I APCMODEL : N/A END APC : Tue Dec 14 20:44:00 CET 1999 apcupsd-3.14.14/examples/status/SmartUPS1000.status000066400000000000000000000023651274230402600217160ustar00rootroot00000000000000DATE : Mon Sep 18 09:34:14 CEST 2000 HOSTNAME : polymatou.sibbald.com RELEASE : 3.7.3-20000911 CABLE : Custom Cable Smart MODEL : SMART-UPS 1000 UPSMODE : Stand Alone STARTTIME: Sat Sep 16 17:13:00 CEST 2000 UPSNAME : UPS_IDEN STATUS : ONLINE LINEV : 235.3 Volts LOADPCT : 12.4 Percent Load Capacity BCHARGE : 100.0 Percent TIMELEFT : 105.0 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds MAXLINEV : 237.9 Volts MINLINEV : 234.0 Volts OUTPUTV : 235.3 Volts SENSE : High DWAKE : 000 Seconds DSHUTD : 020 Seconds DLOWBATT : 02 Minutes LOTRANS : 196.0 Volts HITRANS : 253.0 Volts RETPCT : 000.0 Percent ITEMP : 32.8 C Internal ALARMDEL : 5 seconds BATTV : 27.9 Volts LINEFREQ : 50.0 Hz LASTXFER : Automatic or explicit self test NUMXFERS : 0 XONBATT : N/A TONBATT : 0 seconds CUMONBATT: 0 seconds XOFFBATT : N/A SELFTEST : NO STESTI : 336 STATFLAG : 0x08 Status Flag DIPSW : 0x00 Dip Switch REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 07/31/99 SERIALNO : QS9931125245 BATTDATE : 07/31/99 NOMOUTV : 230 NOMBATTV : 24.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : 0 BADBATTS : N/A FIRMWARE : 60.11.I APCMODEL : IWI END APC : Mon Sep 18 09:34:21 CEST 2000 apcupsd-3.14.14/examples/status/SmartUPS1400.status000066400000000000000000000021421274230402600217130ustar00rootroot00000000000000DATE : Fri Jan 14 17:20:31 MET 2000 HOSTNAME : diesse RELEASE : 3.7.0-beta3 CABLE : Custom Cable Smart MODEL : SMART-UPS 1400 UPSMODE : Stand Alone UPSNAME : UPS_IDEN STATUS : ONLINE LINEV : 235.3 Volts LOADPCT : 33.2 Percent Load Capacity BCHARGE : 096.0 Percent TIMELEFT : 39.0 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds MAXLINEV : 236.6 Volts MINLINEV : 234.0 Volts OUTPUTV : 235.3 Volts SENSE : High DWAKE : 060 Seconds DSHUTD : 020 Seconds DLOWBATT : 05 Minutes LOTRANS : 196.0 Volts HITRANS : 253.0 Volts RETPCT : 015.0 Percent ITEMP : 30.6 C Internal ALARMDEL : 30 seconds BATTV : 28.0 Volts LINEFREQ : 50.0 Hz LASTXFER : Line voltage notch or spike SELFTEST : NO STESTI : OFF STATFLAG : 0x08 Status Flag DIPSW : 0x00 Dip Switch REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 05/19/97 SERIALNO : gs9720551835 BATTDATE : 05/19/97 NOMOUTV : 230 NOMBATTV : 24.0 HUMIDITY : 25.6 AMBTEMP : 22.1 EXTBATTS : 0 BADBATTS : N/A FIRMWARE : 70.9.I APCMODEL : KWI END APC : Fri Jan 14 17:20:39 MET 2000 apcupsd-3.14.14/examples/status/SmartUPS3000.status000066400000000000000000000013221274230402600217100ustar00rootroot00000000000000DATE : Wed Dec 29 19:11:16 PST 1999 HOSTNAME : adsl-63-195-162-81 RELEASE : 3.7.0-beta2 CABLE : APC Cable 940-0024C MODEL : SMART-UPS 3000 UPSMODE : Stand Alone UPSNAME : UPS_IDEN LINEV : 120.9 Volts MAXLINEV : 121.5 Volts MINLINEV : 120.2 Volts LINEFREQ : 60.0 Hz OUTPUTV : 120.9 Volts LOADPCT : 21.8 Percent Load Capacity BATTV : 54.5 Volts BCHARGE : 100.0 Percent MBATTCHG : 5 Percent TIMELEFT : 31.0 Minutes MINTIMEL : 3 Minutes MAXTIME : 0 Seconds STATFLAG : 0x08 Status Flag STATUS : ONLINE ITEMP : 37.3 C Internal LASTXFER : Line voltage notch or spike HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : 0 BADBATTS : N/A FIRMWARE : 90.11.D APCMODEL : OWD END APC : Wed Dec 29 19:11:20 PST 1999 apcupsd-3.14.14/examples/status/SmartUPS5000.status000066400000000000000000000022201274230402600217100ustar00rootroot00000000000000APC : 001,050,1145 DATE : Tue Aug 29 13:35:43 CEST 2000 HOSTNAME : net-master RELEASE : 3.7.2 CABLE : Custom Cable Smart MODEL : SMART-UPS 5000 RM UPSMODE : Net Master SHARE : NetworkUPS UPSNAME : UPS_IDEN STATUS : ONLINE LINEV : 230.1 Volts LOADPCT : 31.7 Percent Load Capacity BCHARGE : 100.0 Percent TIMELEFT : 40.0 Minutes MBATTCHG : 5 Percent MINTIMEL : 3 Minutes MAXTIME : 0 Seconds MAXLINEV : 230.1 Volts MINLINEV : 228.8 Volts OUTPUTV : 230.1 Volts SENSE : High DWAKE : 000 Seconds DSHUTD : 020 Seconds DLOWBATT : 02 Minutes LOTRANS : 196.0 Volts HITRANS : 253.0 Volts RETPCT : 000.0 Percent ITEMP : 19.3 C Internal ALARMDEL : 5 seconds BATTV : 55.0 Volts LINEFREQ : 50.0 Hz LASTXFER : Line voltage notch or spike SELFTEST : NO STESTI : 336 STATFLAG : 0x08 Status Flag DIPSW : 0x00 Dip Switch REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 11/29/99 SERIALNO : GS9999999999 BATTDATE : 11/29/99 NOMOUTV : 230 NOMBATTV : 48.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : 0 BADBATTS : N/A FIRMWARE : 112.13.I APCMODEL : PWI END APC : Tue Aug 29 13:35:44 CEST 2000 apcupsd-3.14.14/examples/status/SmartUPS600.status000066400000000000000000000021301274230402600216310ustar00rootroot00000000000000APC : 001,048,1088 DATE : Fri Dec 03 16:49:24 EST 1999 HOSTNAME : infarc RELEASE : 3.7.0-beta-1 CABLE : APC Cable 940-0024C MODEL : APC Smart-UPS 600 UPSMODE : Stand Alone UPSNAME : SU600 LINEV : 122.1 Volts MAXLINEV : 123.3 Volts MINLINEV : 122.1 Volts LINEFREQ : 60.0 Hz OUTPUTV : 122.1 Volts LOADPCT : 32.7 Percent Load Capacity BATTV : 26.6 Volts BCHARGE : 095.0 Percent MBATTCHG : 15 Percent TIMELEFT : 19.0 Minutes MINTIMEL : 3 Minutes SENSE : Medium DWAKE : 000 Seconds DSHUTD : 020 Seconds LOTRANS : 106.0 Volts HITRANS : 129.0 Volts RETPCT : 010.0 Percent STATFLAG : 0x08 Status Flag STATUS : ONLINE ITEMP : 34.6 C Internal ALARMDEL : Low Battery LASTXFER : Unacceptable Utility Voltage Change SELFTEST : NO STESTI : 336 DLOWBATT : 05 Minutes DIPSW : 0x00 Dip Switch REG1 : N/A REG2 : N/A REG3 : 0x00 Register 3 MANDATE : 03/30/95 SERIALNO : 13035861 BATTDATE : 05/05/98 NOMOUTV : 115.0 NOMBATTV : 24.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : N/A BADBATTS : N/A FIRMWARE : N/A APCMODEL : 6TD END APC : Fri Dec 03 16:49:25 EST 1999 apcupsd-3.14.14/examples/status/SmartUPS700-2.status000066400000000000000000000021711274230402600217760ustar00rootroot00000000000000APC : 001,049,1121 DATE : Mon Dec 13 09:21:18 MET 1999 HOSTNAME : kaa RELEASE : 3.7.0-beta-1 CABLE : APC Cable 940-0024C MODEL : SMART-UPS 700 UPSMODE : Stand Alone UPSNAME : UPS_KAA4 LINEV : 234.0 Volts MAXLINEV : 236.6 Volts MINLINEV : 232.7 Volts LINEFREQ : 50.0 Hz OUTPUTV : 234.0 Volts LOADPCT : 25.4 Percent Load Capacity BATTV : 27.7 Volts BCHARGE : 100.0 Percent MBATTCHG : 10 Percent TIMELEFT : 46.0 Minutes MINTIMEL : 2 Minutes MAXTIME : 0 Seconds SENSE : High DWAKE : 060 Seconds DSHUTD : 020 Seconds LOTRANS : 323.0 Volts HITRANS : 253.0 Volts RETPCT : 015.0 Percent STATFLAG : 0x08 Status Flag STATUS : ONLINE ITEMP : 41.4 C Internal ALARMDEL : Low Battery LASTXFER : Line voltage notch or spike SELFTEST : NO STESTI : 336 DLOWBATT : 02 Minutes DIPSW : 0x00 Dip Switch REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 07/06/98 SERIALNO : NS9828020773 BATTDATE : 07/06/98 NOMOUTV : 230.0 NOMBATTV : 24.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : 1 BADBATTS : N/A FIRMWARE : 50.9.I APCMODEL : GWI END APC : Mon Dec 13 09:21:21 MET 1999 apcupsd-3.14.14/examples/status/SmartUPS700.status000066400000000000000000000021601274230402600216350ustar00rootroot00000000000000APC : 001,048,1112 DATE : Sun Dec 05 01:24:10 EST 1999 HOSTNAME : infarc RELEASE : 3.7.0-beta-1 CABLE : APC Cable 940-0024C MODEL : SMART-UPS 700 UPSMODE : Stand Alone UPSNAME : SU700-1 LINEV : 007.1 Volts MAXLINEV : 000.0 Volts MINLINEV : 007.8 Volts LINEFREQ : 60.0 Hz OUTPUTV : 119.6 Volts LOADPCT : 27.0 Percent Load Capacity BATTV : 24.6 Volts BCHARGE : 074.0 Percent MBATTCHG : 15 Percent TIMELEFT : 17.0 Minutes MINTIMEL : 3 Minutes SENSE : Medium DWAKE : 000 Seconds DSHUTD : 020 Seconds LOTRANS : 103.0 Volts HITRANS : 132.0 Volts RETPCT : 000.0 Percent STATFLAG : 0x10 Status Flag STATUS : ONBATT ITEMP : 45.9 C Internal ALARMDEL : 30 seconds LASTXFER : Unacceptable Utility Voltage Change SELFTEST : NO STESTI : 336 DLOWBATT : 02 Minutes DIPSW : 0x00 Dip Switch REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 05/25/98 SERIALNO : NS9822059313 BATTDATE : 05/25/98 NOMOUTV : 115.0 NOMBATTV : 24.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : 0 BADBATTS : N/A FIRMWARE : 50.9.D APCMODEL : GWD END APC : Sun Dec 05 01:24:11 EST 1999 apcupsd-3.14.14/examples/status/newbackupspro1.status000066400000000000000000000020241274230402600226730ustar00rootroot00000000000000UPSCABLE smart UPSTYPE newbackupspro /etc/apcupsd/apcupsd.status reads: APC : 001,049,0937 DATE : Sun Sep 17 20:41:37 PDT 2000 HOSTNAME : broken-machine RELEASE : 3.7.0 CABLE : Custom Cable Smart MODEL : BACK-UPS PRO 1000 UPSMODE : Stand Alone UPSNAME : N/A STATUS : ONLINE LINEV : N/A LOADPCT : N/A BCHARGE : N/A TIMELEFT : N/A MBATTCHG : 15 Percent MINTIMEL : 3 Minutes MAXTIME : 180 Seconds MAXLINEV : N/A MINLINEV : N/A OUTPUTV : N/A SENSE : N/A DWAKE : N/A DSHUTD : N/A DLOWBATT : N/A LOTRANS : N/A HITRANS : N/A RETPCT : N/A ITEMP : N/A ALARMDEL : N/A BATTV : N/A LINEFREQ : N/A LASTXFER : Automatic or explicit SelfTest SELFTEST : NO STESTI : N/A STATFLAG : 0x08 Status Flag DIPSW : N/A REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : N/A SERIALNO : QB1234123412 BATTDATE : N/A NOMOUTV : N/A NOMBATTV : N/A HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : N/A BADBATTS : N/A FIRMWARE : 13.J.D APCMODEL : N/A END APC : Sun Sep 17 20:41:37 PDT 2000 apcupsd-3.14.14/examples/status/newbackupspro2.status000066400000000000000000000021401274230402600226730ustar00rootroot00000000000000DATE : Thu Sep 21 15:20:43 BST 2000 HOSTNAME : good-machine RELEASE : 3.7.2 CABLE : APC Cable 940-0095A MODEL : BACK-UPS PRO 420 UPSMODE : Net Master SHARE : NetworkUPS UPSNAME : UPS_IDEN STATUS : ONLINE LINEV : 243.3 Volts LOADPCT : 41.6 Percent Load Capacity BCHARGE : 100.0 Percent TIMELEFT : 12.0 Minutes MBATTCHG : 5 Percent MINTIMEL : 6 Minutes MAXTIME : 0 Seconds MAXLINEV : 246.2 Volts MINLINEV : 243.3 Volts OUTPUTV : 243.3 Volts SENSE : High DWAKE : 060 Seconds DSHUTD : 180 Seconds DLOWBATT : 02 Minutes LOTRANS : 208.0 Volts HITRANS : 253.0 Volts RETPCT : 050.0 Percent ITEMP : N/A ALARMDEL : Low Battery BATTV : 13.9 Volts LINEFREQ : 50.0 Hz LASTXFER : No transfers since turnon SELFTEST : NO STESTI : OFF STATFLAG : 0x08 Status Flag DIPSW : N/A REG1 : 0x00 Register 1 REG2 : 0x00 Register 2 REG3 : 0x00 Register 3 MANDATE : 07/25/98 SERIALNO : GB1234123412 BATTDATE : 07/25/98 NOMOUTV : 230 NOMBATTV : 12.0 HUMIDITY : N/A AMBTEMP : N/A EXTBATTS : N/A BADBATTS : N/A FIRMWARE : 11.2.I APCMODEL : DWI END APC : Thu Sep 21 15:20:47 BST 2000 apcupsd-3.14.14/examples/upsapm.c000066400000000000000000000131451274230402600166160ustar00rootroot00000000000000/* * Client test program for apcnisd to be used * as a base for the new master/slave code. * * Build it with: cc upsapm.c ../lib/libapc.a -o newclient * * Execute: ./upsapm [host[:port]] * * The two commands currently (Apr 2001) accepted by the * server are "status" and "events". * * Format of /proc/apm is when online and no apm: * 1.14 1.2 0x03 0x01 0xff 0x80 -1% -1 ? * * 1.14 = kernel driver version * 1.2 = apm_major_version.apm_minor_version * 0x03 = apm_flags * 0x01 = on_line_status * 0 = off line * 1 = on line * 2 = on back * 0xff = battery status * ff = (none?) * 0 = high * 1 = low * 2 = crit * 3 = charg * 0x80 = battery_flags * -1% = battery percentage * -1 = battery time * ? = (if min battery minutes otherwise seconds) * * */ #include "apc.h" #ifdef HAVE_NISLIB /* Default values, can be changed on command line */ #define SERV_TCP_PORT 3551 #define SERV_HOST_ADDR "127.0.0.1" #define BIGBUF 4096 char statbuf[BIGBUF]; int statlen = BIGBUF; /* List of variables that can be read by getupsvar() * First field is that name given to getupsvar(), * Second field is our internal name as produced by the STATUS * output from apcupsd. * Third field, if 0 returns everything to the end of the * line, and if 1 returns only to first space (e.g. integers, * and floating point values. */ static struct { const char *request; const char *upskeyword; int nfields; } cmdtrans[] = { {"date", "DATE", 0}, {"battcap", "BCHARGE", 1}, {"mbattchg", "MBATTCHG", 1}, {"status", "STATFLAG", 1}, {"runtime", "TIMELEFT", 1}, {"battpct", "BCHARGE", 1}, {NULL, NULL} }; int fetch_data(char *host, int port); int getupsvar(char *host, int port, const char *request, char *answer, int anslen); int fill_buffer(int sockfd); extern int net_errno; void error_abort(const char *msg) { fprintf(stderr, msg); exit(1); } int main(int argc, char *argv[]) { int port; char host[200]; char msg[200], *p; long stat_flag; int battchg; int runtime; strcpy(host, SERV_HOST_ADDR); port = SERV_TCP_PORT; if (argc > 1) { strcpy(host, argv[1]); /* get host from command line */ p = strchr(host, ':'); if (p) { *p++ = 0; port = atoi(p); } } /* make sure we are communicating */ if (getupsvar(host, port, "date", msg, sizeof(msg)) <= 0) { printf("1.14 1.2 0x03 0x01 0xff 0x80 -1%% -1 ? : Cannot get date\n"); exit(1); } if (getupsvar(host, port, "status", msg, sizeof(msg)) <= 0) { printf("1.14 1.2 0x03 0x01 0xff 0x80 -1%% -1 ? : Cannot get status\n"); exit(1); } stat_flag = strtol(msg, NULL, 16); if (getupsvar(host, port, "battcap", msg, sizeof(msg)) <= 0) { printf("1.14 1.2 0x03 0x01 0xff 0x80 -1%% -1 ? : Cannot get battcap\n"); exit(1); } battchg = (int)strtod(msg, NULL); if (getupsvar(host, port, "runtime", msg, sizeof(msg)) <= 0) { printf("1.14 1.2 0x03 0x01 0xff 0x80 -1%% -1 ? : Cannot get runtime\n"); exit(1); } runtime = (int)strtod(msg, NULL); if (stat_flag & 0x8) { printf("1.14 1.2 0x03 0x01 0x03 0x09 %d%% -1 ?\n", battchg); } else { printf("1.14 1.2 0x03 0x00 0x00 0x01 %d%% %d min\n", battchg, runtime); } exit(0); } /* * Read data into memory buffer to be used by getupsvar() * Returns 0 on error * Returns 1 if data fetched */ int fetch_data(char *host, int port) { int sockfd; int stat; if ((sockfd = net_open(host, NULL, port)) < 0) { printf("fetch_data: tcp_open failed for %s port %d", host, port); return 0; } stat = fill_buffer(sockfd); /* fill statbuf */ net_close(sockfd); return stat; } /* * * Returns 1 if var found * answer has var * Returns 0 if variable name not found * answer has "Not found" is variable name not found * answer may have "N/A" if the UPS does not support this * feature * Returns -1 if network problem * answer has "N/A" if host is not available or network error */ int getupsvar(char *host, int port, const char *request, char *answer, int anslen) { int i; const char *stat_match = NULL; char *find; int nfields = 0; if (!fetch_data(host, port)) { strcpy(answer, "N/A"); return -1; } for (i=0; cmdtrans[i].request; i++) if (!(strcmp(cmdtrans[i].request, request))) { stat_match = cmdtrans[i].upskeyword; nfields = cmdtrans[i].nfields; } if (stat_match != NULL) { if ((find=strstr(statbuf, stat_match)) != NULL) { if (nfields == 1) /* get one field */ sscanf (find, "%*s %*s %s", answer); else { /* get everything to eol */ i = 0; find += 11; /* skip label */ while (*find != '\n') answer[i++] = *find++; answer[i] = 0; } if (strcmp(answer, "N/A") == 0) return 0; return 1; } } strcpy(answer, "Not found"); return 0; } #define MAXLINE 512 /* Fill buffer with data from UPS network daemon * Returns 0 on error * Returns 1 if OK */ int fill_buffer(int sockfd) { int n, stat = 1; char buf[1000]; statbuf[0] = 0; statlen = 0; if (net_send(sockfd, "status", 6) != 6) { printf("fill_buffer: write error on socket\n"); return 0; } while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) { buf[n] = 0; strcat(statbuf, buf); } if (n < 0) stat = 0; statlen = strlen(statbuf); return stat; } #else /* HAVE_NISLIB */ int main(int argc, char *argv[]) { printf("Sorry, NIS code is not compiled in apcupsd.\n"); return 1; } #endif /* HAVE_NISLIB */ apcupsd-3.14.14/examples/usb_hid_usages000066400000000000000000000527271274230402600200650ustar00rootroot00000000000000# $NetBSD: usb_hid_usages,v 1.3 1999/07/02 15:46:53 simonb Exp $ # $FreeBSD: src/share/misc/usb_hid_usages,v 1.1.2.1 2000/07/02 13:13:55 n_hibma Exp $ # # USB HID usage table # Syntax: # - lines that do not start with a white space give the number and name of # a usage page. # - lines that start with a white space give the number and name of # a usage with the last given page. # If the number is * then the line matches all usages and the name # is a printf formatting string that will be given the usage number. # 1 Generic Desktop 0x00 Undefined 0x01 Pointer 0x02 Mouse 0x03 Reserved 0x04 Joystick 0x05 Game Pad 0x06 Keyboard 0x07 Keypad 0x08 Multi-axis Controller 0x30 X 0x31 Y 0x32 Z 0x33 Rx 0x34 Ry 0x35 Rz 0x36 Slider 0x37 Dial 0x38 Wheel 0x39 Hat Switch 0x3A Counted Buffer 0x3B Byte Count 0x3C Motion Wakeup 0x40 Vx 0x41 Vy 0x42 Vz 0x43 Vbrx 0x44 Vbry 0x45 Vbrx 0x46 Vno 0x80 System Control 0x81 System Power Down 0x82 System Sleep 0x83 System Wake Up 0x84 System Context Menu 0x85 System Main Menu 0x86 System App Menu 0x87 System Menu Help 0x88 System Menu Exit 0x89 System Menu Select 0x8A System Menu Right 0x8B System Menu Left 0x8C System Menu Up 0x8D System Menu Down 0x90 D-pad Up 0x91 D-pad Down 0x92 D-pad Right 0x93 D-pad Left 2 Simulation Controls 0x00 Undefined 0x01 Flight Simulation Device 0x02 Automobile Simulation Device 0x03 Tank Simulation Device 0x04 Spaceship Simulation Device 0x05 Submarine Simulation Device 0x06 Sailing Simulation Device 0x07 Motorcycle Simulation Device 0x08 Sports Simulation Device 0x09 Airplane Simulation Device 0x0A Helicopter Simulation Device 0x0B Magic Carpet Simulation Device 0x0C Bicycle 0x20 Flight Control Stick 0x21 Flight Stick 0x22 Cyclic Control 0x23 Cyclic Trim 0x24 Flight Yoke 0x25 Track Control 0x26 Driving Control 0xB0 Aileron 0xB1 Aileron Trim 0xB2 Anti-Torque Control 0xB3 Auto-pilot Enable 0xB4 Chaff Release 0xB5 Collective Control 0xB6 Dive Brake 0xB7 Electronic Counter Measures 0xB8 Elevator 0xB9 Elevator Trim 0xBA Rudder 0xBB Throttle 0xBC Flight Communication 0xBD Flare Release 0xBE Landing Gear 0xBF Toe Brake 0xC0 Trigger 0xC1 Weapons Arm 0xC2 Weapons Select 0xC3 Wing Flaps 0xC4 Accelerator 0xC5 Brake 0xC6 Clutch 0xC7 Shifter 0xC8 Steering 0xC9 Turret Direction 0xCA Barrel Elevation 0xCB Dive Plane 0xCC Ballast 0xCD Bicycle Crank 0xCE Handle Bars 0xCF Front Brake 0xD0 Rear Brake 3 VR Controls 0x00 Unidentified 0x01 Belt 0x02 Body Suit 0x03 Flexor 0x04 Glove 0x05 Head Tracker 0x06 Head Mounted Display 0x07 Hand Tracker 0x08 Oculometer 0x09 Vest 0x0A Animatronic Device 0x20 Stereo Enable 0x21 Display Enable 4 Sports Controls 0x00 Unidentified 0x01 Baseball Bat 0x02 Golf Club 0x03 Rowing Machine 0x04 Treadmill 0x30 Oar 0x31 Slope 0x32 Rate 0x33 Stick Speed 0x34 Stick Face Angle 0x35 Stick Heel/Toe 0x36 Stick Follow Through 0x37 Stick Tempo 0x38 Stick Type 0x39 Stick Height 0x50 Putter 0x51 1 Iron 0x52 2 Iron 0x53 3 Iron 0x54 4 Iron 0x55 5 Iron 0x56 6 Iron 0x57 7 Iron 0x58 8 Iron 0x59 9 Iron 0x5A 10 Iron 0x5B 11 Iron 0x5C Sand Wedge 0x5D Loft Wedge 0x5E Power Wedge 0x5F 1 Wood 0x60 3 Wood 0x61 5 Wood 0x62 7 Wood 0x63 9 Wood 5 Game Controls 0x00 Undefined 0x01 3D Game Controller 0x02 Pinball Device 0x03 Gun Device 0x20 Point of View 0x21 Turn Right/Left 0x22 Pitch Right/Left 0x23 Roll Forward/Backward 0x24 Move Right/Left 0x25 Move Forward/Backward 0x26 Move Up/Down 0x27 Lean Right/Left 0x28 Lean Forward/Backward 0x29 Height of POV 0x2A Flipper 0x2B Secondary Flipper 0x2C Bump 0x2D New Game 0x2E Shoot Ball 0x2F Player 0x30 Gun Bolt 0x31 Gun Clip 0x32 Gun Selector 0x33 Gun Single Shot 0x34 Gun Burst 0x35 Gun Automatic 0x36 Gun Safety 0x37 Gamepad Fire/Jump 0x39 Gamepad Trigger 7 Keyboard 0x00 Reserved (no event indicated) 0x01 Keyboard ErrorRollOver 0x02 Keyboard POSTFail 0x03 Keyboard ErrorUndefined 0x04 Keyboard a and A 0x05 Keyboard b and B 0x06 Keyboard c and C 0x07 Keyboard d and D 0x08 Keyboard e and E 0x09 Keyboard f and F 0x0A Keyboard g and G 0x0B Keyboard h and H 0x0C Keyboard i and I 0x0D Keyboard j and J 0x0E Keyboard k and K 0x0F Keyboard l and L 0x10 Keyboard m and M 0x11 Keyboard n and N 0x12 Keyboard o and O 0x13 Keyboard p and P 0x14 Keyboard q and Q 0x15 Keyboard r and R 0x16 Keyboard s and S 0x17 Keyboard t and T 0x18 Keyboard u and U 0x19 Keyboard v and V 0x1A Keyboard w and W 0x1B Keyboard x and X 0x1C Keyboard y and Y 0x1D Keyboard z and Z 0x1E Keyboard 1 and ! 0x1F Keyboard 2 and @ 0x20 Keyboard 3 and # 0x21 Keyboard 4 and $ 0x22 Keyboard 5 and % 0x23 Keyboard 6 and ^ 0x24 Keyboard 7 and & 0x25 Keyboard 8 and * 0x26 Keyboard 9 and ( 0x27 Keyboard 0 and ) 0x28 Keyboard Return (ENTER) 0x29 Keyboard ESCAPE 0x2A Keyboard DELETE (Backspace) 0x2B Keyboard Tab 0x2C Keyboard Spacebar 0x2D Keyboard - and (underscore) 0x2E Keyboard = and + 0x2F Keyboard [ and { 0x30 Keyboard ] and } 0x31 Keyboard \ and | 0x32 Keyboard Non-US # and ~ 0x33 Keyboard ; and : 0x34 Keyboard ' and " 0x35 Keyboard Grave Accent and Tilde 0x36 Keyboard, and < 0x37 Keyboard . and > 0x38 Keyboard / and ? 0x39 Keyboard Caps Lock 0x3A Keyboard F1 0x3B Keyboard F2 0x3C Keyboard F3 0x3D Keyboard F4 0x3E Keyboard F5 0x3F Keyboard F6 0x40 Keyboard F7 0x41 Keyboard F8 0x42 Keyboard F9 0x43 Keyboard F10 0x44 Keyboard F11 0x45 Keyboard F12 0x46 Keyboard PrintScreen 0x47 Keyboard Scroll Lock 0x48 Keyboard Pause 0x49 Keyboard Insert 0x4A Keyboard Home 0x4B Keyboard PageUp 0x4C Keyboard Delete Forward 0x4D Keyboard End 0x4E Keyboard PageDown 0x4F Keyboard RightArrow 0x50 Keyboard LeftArrow 0x51 Keyboard DownArrow 0x52 Keyboard UpArrow 0x53 Keypad Num Lock and Clear 0x54 Keypad / 0x55 Keypad * 0x56 Keypad - 0x57 Keypad + 0x58 Keypad ENTER 0x59 Keypad 1 and End 0x5A Keypad 2 and Down Arrow 0x5B Keypad 3 and PageDn 0x5C Keypad 4 and Left Arrow 0x5D Keypad 5 0x5E Keypad 6 and Right Arrow 0x5F Keypad 7 and Home 0x60 Keypad 8 and Up Arrow 0x61 Keypad 9 and PageUp 0x62 Keypad 0 and Insert 0x63 Keypad . and Delete 0x64 Keyboard Non-US \ and | 0x65 Keyboard Application 0x66 Keyboard Power 0x67 Keypad = 0x68 Keyboard F13 0x69 Keyboard F14 0x6A Keyboard F15 0x6B Keyboard F16 0x6C Keyboard F17 0x6D Keyboard F18 0x6E Keyboard F19 0x6F Keyboard F20 0x70 Keyboard F21 0x71 Keyboard F22 0x72 Keyboard F23 0x73 Keyboard F24 0x74 Keyboard Execute 0x75 Keyboard Help 0x76 Keyboard Menu 0x77 Keyboard Select 0x78 Keyboard Stop 0x79 Keyboard Again 0x7A Keyboard Undo 0x7B Keyboard Cut 0x7C Keyboard Copy 0x7D Keyboard Paste 0x7E Keyboard Find 0x7F Keyboard Mute 0x80 Keyboard Volume Up 0x81 Keyboard Volume Down 0x82 Keyboard Locking Caps Lock 0x83 Keyboard Locking Num Lock 0x84 Keyboard Locking Scroll Lock 0x85 Keypad Comma 0x86 Keypad Equal Sign 0x87 Keyboard International1 0x88 Keyboard International2 0x89 Keyboard International3 0x8A Keyboard International4 0x8B Keyboard International5 0x8C Keyboard International6 0x8D Keyboard International7 0x8E Keyboard International8 0x8F Keyboard International9 0x90 Keyboard LANG1 0x91 Keyboard LANG2 0x92 Keyboard LANG3 0x93 Keyboard LANG4 0x94 Keyboard LANG5 0x95 Keyboard LANG6 0x96 Keyboard LANG7 0x97 Keyboard LANG8 0x98 Keyboard LANG9 0x99 Keyboard Alternate Erase 0x9A Keyboard SysReq/Attention 0x9B Keyboard Cancel 0x9C Keyboard Clear 0x9D Keyboard Prior 0x9E Keyboard Return 0x9F Keyboard Separator 0xA0 Keyboard Out 0xA1 Keyboard Oper 0xA2 Keyboard Clear/Again 0xA3 Keyboard CrSel/Props 0xA4 Keyboard ExSel 0xE0 Keyboard LeftControl 0xE1 Keyboard LeftShift 0xE2 Keyboard LeftAlt 0xE3 Keyboard Left GUI 0xE4 Keyboard RightControl 0xE5 Keyboard RightShift 0xE6 Keyboard RightAlt 0xE7 Keyboard Right GUI 8 LEDs 0x00 Undefined 0x01 Num Lock 0x02 Caps Lock 0x03 Scroll Lock 0x04 Compose 0x05 Kana 0x06 Power 0x07 Shift 0x08 Do Not Disturb 0x09 Mute 0x0A Tone Enable 0x0B High Cut Filter 0x0C Low Cut Filter 0x0D Equalizer Enable 0x0E Sound Field On 0x0F Surround Field On 0x10 Repeat 0x11 Stereo 0x12 Sampling Rate Detect 0x13 Spinning 0x14 CAV 0x15 CLV 0x16 Recording Format Detect 0x17 Off-Hook 0x18 Ring 0x19 Message Waiting 0x1A Data Mode 0x1B Battery Operation 0x1C Battery OK 0x1D Battery Low 0x1E Speaker 0x1F Head Set 0x20 Hold 0x21 Microphone 0x22 Coverage 0x23 Night Mode 0x24 Send Calls 0x25 Call Pickup 0x26 Conference 0x27 Stand-by 0x28 Camera On 0x29 Camera Off 0x2A On-Line 0x2B Off-Line 0x2C Busy 0x2D Ready 0x2E Paper-Out 0x2F Paper-Jam 0x30 Remote 0x31 Forward 0x32 Reverse 0x33 Stop 0x34 Rewind 0x35 Fast Forward 0x36 Play 0x37 Pause 0x38 Record 0x39 Error 0x3A Usage Selected Indicator 0x3B Usage In Use Indicator 0x3C Usage Multi Mode Indicator 0x3D Indicator On 0x3E Indicator Flash 0x3F Indicator Slow Blink 0x40 Indicator Fast Blink 0x41 Indicator Off 0x42 Flash On Time 0x43 Slow Blink On Time 0x44 Slow Blink Off Time 0x45 Fast Blink On Time 0x46 Fast Blink Off Time 0x47 Usage Indicator Color 0x48 Red 0x49 Green 0x4A Amber 0x4B Generic Indicator 0x4C System Suspend 0x4D External Power Connected 0x4C-FFFF Reserved 9 Button 0x00 No Button Pressed * Button %d 10 Ordinal 0x00 Unused * Instance %d 11 Telephony 0x00 Unassigned 0x01 Phone 0x02 Answering Machine 0x03 Message Controls 0x04 Handset 0x05 Headset 0x06 Telephony Key Pad 0x07 Programmable Button 0x20 Hook Switch 0x21 Flash 0x22 Feature 0x23 Hold 0x24 Redial 0x25 Transfer 0x26 Drop 0x27 Park 0x28 Forward Calls 0x29 Alternate Function 0x2A Line 0x2B Speaker Phone 0x2C Conference 0x2D Ring Enable 0x2E Ring Select 0x2F Phone Mute 0x30 Caller ID 0x50 Speed Dial 0x51 Store Number 0x52 Recall Number 0x53 Phone Directory 0x70 Voice Mail 0x71 Screen Calls 0x72 Do Not Disturb 0x73 Message 0x74 Answer On/Off 0x90 Inside Dial Tone 0x91 Outside Dial Tone 0x92 Inside Ring Tone 0x93 Outside Ring Tone 0x94 Priority Ring Tone 0x95 Inside Ringback 0x96 Priority Ringback 0x97 Line Busy Tone 0x98 Reorder Tone 0x99 Call Waiting Tone 0x9A Confirmation Tone 1 0x9B Confirmation Tone 2 0x9C Tones Off 0xB0 Phone Key 0 0xB1 Phone Key 1 0xB2 Phone Key 2 0xB3 Phone Key 3 0xB4 Phone Key 4 0xB5 Phone Key 5 0xB6 Phone Key 6 0xB7 Phone Key 7 0xB8 Phone Key 8 0xB9 Phone Key 9 0xBA Phone Key Star 0xBB Phone Key Pound 0xBC Phone Key A 0xBD Phone Key B 0xBE Phone Key C 0xBF Phone Key D 12 Consumer 0x00 Unassigned 0x01 Consumer Control 0x02 Numeric Key Pad 0x03 Programmable Buttons 0x20 +10 0x21 +100 0x22 AM/PM 0x30 Power 0x31 Reset 0x32 Sleep 0x33 Sleep After 0x34 Sleep Mode 0x35 Illumination 0x36 Function Buttons 0x40 Menu 0x41 Menu Pick 0x42 Menu Up 0x43 Menu Down 0x44 Menu Left 0x45 Menu Right 0x46 Menu Escape 0x47 Menu Value Increase 0x48 Menu Value Decrease 0x60 Data On Screen 0x61 Closed Caption 0x62 Closed Caption Select 0x63 VCR/TV 0x64 Broadcast Mode 0x65 Snapshot 0x66 Still 0x80 Selection 0x81 Assign Selection 0x82 Mode Step 0x83 Recall Last 0x84 Enter Channel 0x85 Order Movie 0x86 Channel 0x87 Media Selection 0x88 Media Select Computer 0x89 Media Select TV 0x8A Media Select WWW 0x8B Media Select DVD 0x8C Media Select Telephone 0x8D Media Select Program Guide 0x8E Media Select Video Phone 0x8F Media Select Games 0x90 Media Select Messages 0x91 Media Select CD 0x92 Media Select VCR 0x93 Media Select Tuner 0x94 Quit 0x95 Help 0x96 Media Select Tape 0x97 Media Select Cable 0x98 Media Select Satellite 0x99 Media Select Security 0x9A Media Select Home 0x9B Media Select Call 0x9C Channel Increment 0x9D Channel Decrement 0x9E Media Select SAP 0xA0 VCR Plus 0xA1 Once 0xA2 Daily 0xA3 Weekly 0xA4 Monthly 0xB0 Play 0xB1 Pause 0xB2 Record 0xB3 Fast Forward 0xB4 Rewind 0xB5 Scan Next Track 0xB6 Scan Previous Track 0xB7 Stop 0xB8 Eject 0xB9 Random Play 0xBA Select DisC 0xBB Enter Disc 0xBC Repeat 0xBD Tracking 0xBE Track Normal 0xBF Slow Tracking 0xC0 Frame Forward 0xC1 Frame Back 0xC2 Mark 0xC3 Clear Mark 0xC4 Repeat From Mark 0xC5 Return To Mark 0xC6 Search Mark Forward 0xC7 Search Mark Backwards 0xC8 Counter Reset 0xC9 Show Counter 0xCA Tracking Increment 0xCB Tracking Decrement 0xE0 Volume 0xE1 Balance 0xE2 Mute 0xE3 Bass 0xE4 Treble 0xE5 Bass Boost 0xE6 Surround Mode 0xE7 Loudness 0xE8 MPX 0xE9 Volume Up 0xEA Volume Down 0xF0 Speed Select 0xF1 Playback Speed 0xF2 Standard Play 0xF3 Long Play 0xF4 Extended Play 0xF5 Slow 0x100 Fan Enable 0x101 Fan Speed 0x102 Light 0x103 Light Illumination Level 0x104 Climate Control Enable 0x105 Room Temperature 0x106 Security Enable 0x107 Fire Alarm 0x108 Police Alarm 0x150 Balance Right 0x151 Balance Left 0x152 Bass Increment 0x153 Bass Decrement 0x154 Treble Increment 0x155 Treble Decrement 0x160 Speaker System 0x161 Channel Left 0x162 Channel Right 0x163 Channel Center 0x164 Channel Front 0x165 Channel Center Front 0x166 Channel Side 0x167 Channel Surround 0x168 Channel Low Frequency Enhancement 0x169 Channel Top 0x16A Channel Unknown 0x170 Sub-channel 0x171 Sub-channel Increment 0x172 Sub-channel Decrement 0x173 Alternate Audio Increment 0x174 Alternate Audio Decrement 0x180 Application Launch Buttons 0x181 AL Launch Button Configuration Tool 0x182 AL Programmable Button Configuration 0x183 AL Consumer Control Configuration 0x184 AL Word Processor 0x185 AL Text Editor 0x186 AL Spreadsheet 0x187 AL Graphics Editor 0x188 AL Presentation App 0x189 AL Database App 0x18A AL Email Reader 0x18B AL Newsreader 0x18C AL Voicemail 0x18D AL Contacts/Address Book 0x18E AL Calendar/Schedule 0x18F AL Task/Project Manager 0x190 AL Log/Journal/Timecard 0x191 AL Checkbook/Finance 0x192 AL Calculator 0x193 AL A/V Capture/Playback 0x194 AL Local Machine Browser 0x195 AL LAN/WAN Browser 0x196 AL Internet Browser 0x197 AL Remote Networking/ISP Connect 0x198 AL Network Conference 0x199 AL Network Chat 0x19A AL Telephony/Dialer 0x19B AL Logon 0x19C AL Logoff 0x19D AL Logon/Logoff 0x19E AL Terminal Lock/Screensaver 0x19F AL Control Panel 0x1A0 AL Command Line Processor/Run 0x1A1 AL Process/Task Manager 0x1A2 AL Select Tast/Application 0x1A3 AL Next Task/Application 0x1A4 AL Previous Task/Application 0x1A5 AL Preemptive Halt Task/Application 0x200 Generic GUI Application Controls 0x201 AC New 0x202 AC Open 0x203 AC Close 0x204 AC Exit 0x205 AC Maximize 0x206 AC Minimize 0x207 AC Save 0x208 AC Print 0x209 AC Properties 0x21A AC Undo 0x21B AC Copy 0x21C AC Cut 0x21D AC Paste 0x21E AC Select All 0x21F AC Find 0x220 AC Find and Replace 0x221 AC Search 0x222 AC Go To 0x223 AC Home 0x224 AC Back 0x225 AC Forward 0x226 AC Stop 0x227 AC Refresh 0x228 AC Previous Link 0x229 AC Next Link 0x22A AC Bookmarks 0x22B AC History 0x22C AC Subscriptions 0x22D AC Zoom In 0x22E AC Zoom Out 0x22F AC Zoom 0x230 AC Full Screen View 0x231 AC Normal View 0x232 AC View Toggle 0x233 AC Scroll Up 0x234 AC Scroll Down 0x235 AC Scroll 0x236 AC Pan Left 0x237 AC Pan Right 0x238 AC Pan 0x239 AC New Window 0x23A AC Tile Horizontally 0x23B AC Tile Vertically 0x23C AC Format 13 Digitizer 0x00 Undefined 0x01 Digitizer 0x02 Pen 0x03 Light Pen 0x04 Touch Screen 0x05 Touch Pad 0x06 White Board 0x07 Coordinate Measuring Machine 0x08 3-D Digitizer 0x09 Stereo Plotter 0x0A Articulated Arm 0x0B Armature 0x0C Multiple Point Digitizer 0x0D Free Space Wand 0x20 Stylus 0x21 Puck 0x22 Finger 0x30 Tip Pressure 0x31 Barrel Pressure 0x32 In Range 0x33 Touch 0x34 Untouch 0x35 Tap 0x36 Quality 0x37 Data Valid 0x38 Transducer Index 0x39 Tablet Function Keys 0x3A Program Change Keys 0x3B Battery Strength 0x3C Invert 0x3D X Tilt 0x3E Y Tilt 0x3F Azimuth 0x40 Altitude 0x41 Twist 0x42 Tip Switch 0x43 Secondary Tip Switch 0x44 Barrel Switch 0x45 Eraser 0x46 Tablet Pick 15 Physical Interface Device 16 Unicode * Unicode Char u%04x 20 Alphnumeric Display 0x00 Undefined 0x01 Alphanumeric Display 0x20 Display Attributes Report 0x21 ASCII Character Set 0x22 Data Read Back 0x23 Font Read Back 0x24 Display Control Report 0x25 Clear Display 0x26 Display Enable 0x27 Screen Saver Delay 0x28 Screen Saver Enable 0x29 Vertical Scroll 0x2A Horizontal Scroll 0x2B Character Report 0x2C Display Data 0x2D Display Status 0x2E Stat Not Ready 0x2F Stat Ready 0x30 Err Not a loadable character 0x31 Err Font data cannot be read 0x32 Cursor Position Report 0x33 Row 0x34 Column 0x35 Rows 0x36 Columns 0x37 Cursor Pixel Positioning 0x38 Cursor Mode 0x39 Cursor Enable 0x3A Cursor Blink 0x3B Font Report 0x3C Font Data 0x3D Character Width 0x3E Character Height 0x3F Character Spacing Horizontal 0x40 Character Spacing Vertical 0x41 Unicode Character Set 128 Monitor 0x00 Undefined 0x01 Monitor Control 0x02 EDID Information 0x03 VDIF Information 0x04 VESA Version 0x05 On Screen Display 0x06 Auto Size Center 0x07 Polarity Horz Synch 0x08 Polarity Vert Synch 0x09 Sync Type 0x0A Screen Position 0x0B Horizontal Frequency 0x0C Vertical Frequency 129 Monitor Enumerated Values 0x00 unassigned * ENUM %d 130 VESA Virtual Controls 0x10 Brightness 0x12 Contrast 0x16 Video Gain Red 0x18 Video Gain Green 0x1A Video Gain Blue 0x1C Focus 0x20 Horizontal Position 0x22 Horizontal Size 0x24 Horizontal Pincushion 0x26 Horizontal Pincushion Balance 0x28 Horizontal Misconvergence 0x2A Horizontal Linearity 0x2C Horizontal Linearity Balance 0x30 Vertical Position 0x32 Vertical Size 0x34 Vertical Pincushion 0x36 Vertical Pincushion Balance 0x38 Vertical Misconvergence 0x3A Vertical Linearity 0x3C Vertical Linearity Balance 0x40 Parallelogram Distortion 0x42 Trapezoidal Distortion 0x44 Tilt 0x46 Top Corner Distortion Control 0x48 Top Corner Distortion Balance 0x4A Bottom Corner Distortion Control 0x4C Bottom Corner Distortion Balance 0x56 Moir Horizontal 0x58 Moir Vertical 0x5E Input Level Select 0x60 Input Source Select 0x62 Stereo Mode 0x6C Video Black Level Red 0x6E Video Black Level Green 0x70 Video Black Level Blue 131 VESA Command 0x00 Undefined 0x01 Settings 0x02 Degauss 132 Power Device 0x00 Undefined 0x01 iName 0x02 PresentStatus 0x03 ChangedStatus 0x04 UPS 0x05 PowerSupply 0x10 BatterySystem 0x11 BatterySystemID 0x12 Battery 0x13 BatteryID 0x14 Charger 0x15 ChargerID 0x16 PowerConverter 0x17 PowerConverterID 0x18 OutletSystem 0x19 OutletSystemID 0x1A Input 0x1B InputID 0x1C Output 0x1D OutputID 0x1E Flow 0x1F FlowID 0x20 Outlet 0x21 OutletID 0x22 Gang 0x23 GangID 0x24 Sink 0x25 SinkID 0x30 Voltage 0x31 Current 0x32 Frequency 0x33 ApparentPower 0x34 ActivePower 0x35 PercentLoad 0x36 Temperature 0x37 Humidity 0x40 ConfigVoltage 0x41 ConfigCurrent 0x42 ConfigFrequency 0x43 ConfigApparentPower 0x44 ConfigActivePower 0x45 ConfigPercentLoad 0x46 ConfigTemperature 0x47 ConfigHumidity 0x50 SwitchOnControl 0x51 SwitchOffControl 0x52 ToggleControl 0x53 LowVoltageTransfer 0x54 HighVoltageTransfer 0x55 DelayBeforeReboot 0x56 DelayBeforeStartup 0x57 DelayBeforeShutdown 0x58 Test 0x59 Vendorspecificcommand 0x60 Present 0x61 Good 0x62 InternalFailure 0x63 VoltageOutOfRange 0x64 FrequencyOutOfRange 0x65 Overload 0x66 OverCharged 0x67 OverTemperature 0x68 ShutdownRequested 0x69 ShutdownImminent 0x6A VendorSpecificAnswerValid 0x6B SwitchOn/Off 0x6C Switcheble 0x6D Used 0x6E Boost 0x6F Buck 0x70 Initialized 0x71 Tested 133 Battery System 0x00 Undefined 0x01 SMBBatteryMode 0x02 SMBBatteryStatus 0x03 SMBAlarmWarning 0x04 SMBChargerMode 0x05 SMBChargerStatus 0x06 SMBChargerSpecInfo 0x07 SMBSelectorState 0x08 SMBSelectorPreset 0x09 SMBSelectorInfo 0x10 OptionalMfgFunction1 0x11 OptionalMfgFunction2 0x12 OptionalMfgFunction3 0x13 OptionalMfgFunction4 0x14 OptionalMfgFunction5 0x15 ConnectionToSMBus 0x16 OutputConnection 0x17 ChargerConnection 0x18 BatteryInsertion 0x19 Usenext 0x1A OKToUse 0x28 ManufacturerAccess 0x29 RemainingCapacityLimit 0x2A RemainingTimeLimit 0x2B AtRate 0x2C CapacityMode 0x2D BroadcastToCharger 0x2E PrimaryBattery 0x2F ChargeController 0x40 TerminateCharge 0x41 TermminateDischarge 0x42 BelowRemainingCapacityLimit 0x43 RemainingTimeLimitExpired 0x44 Charging 0x45 Discharging 0x46 FullyCharged 0x47 FullyDischarged 0x48 ConditionningFlag 0x49 AtRateOK 0x4A SMBErrorCode 0x4B NeedReplacement 0x60 AtRateTimeToFull 0x61 AtRateTimeToEmpty 0x62 AverageCurrent 0x63 Maxerror 0x64 RelativeStateOfCharge 0x65 AbsoluteStateOfCharge 0x66 RemainingCapacity 0x67 FullChargeCapacity 0x68 RunTimeToEmpty 0x69 AverageTimeToEmpty 0x6A AverageTimeToFull 0x6B CycleCount 0x80 BattPackModelLevel 0x81 InternalChargeController 0x82 PrimaryBatterySupport 0x83 DesignCapacity 0x84 SpecificationInfo 0x85 ManufacturerDate 0x86 SerialNumber 0x87 iManufacturerName 0x88 iDevicename 0x89 iDeviceChemistery 0x8A iManufacturerData 0x8B Rechargeable 0x8C WarningCapacityLimit 0x8D CapacityGranularity1 0x8E CapacityGranularity2 0xC0 InhibitCharge 0xC1 EnablePolling 0xC2 ResetToZero 0xD0 ACPresent 0xD1 BatteryPresent 0xD2 PowerFail 0xD3 AlarmInhibited 0xD4 ThermistorUnderRange 0xD5 ThermistorHot 0xD6 ThermistorCold 0xD7 ThermistorOverRange 0xD8 VoltageOutOfRange 0xD9 CurrentOutOfRange 0xDA CurrentNotRegulated 0xDB VoltageNotRegulated 0xDC MasterMode 0xDD ChargerBattery/HostControlled 0xF0 ChargerSpecInfo 0xF1 ChargerSpecRef 0xF2 Level2 0xF3 Level3 140 Bar Code Scanner 141 Scale Device 144 Camera Control 145 Arcade Device # Some Micro$oft non-standard extensions 0xff00 Microsoft 0xe9 Base Up 0xea Base Down apcupsd-3.14.14/examples/usbsnoop.txt000066400000000000000000000160141274230402600175540ustar00rootroot00000000000000From: "Adam Kropelin" To: "Kern Sibbald" Cc: "Apcupsd-users" Subject: Reading a usbsnoop trace Date: Mon, 23 Aug 2004 21:51:50 -0400 Some users have had good luck using the 'usbsnoop' tool (http://benoit.papillault.free.fr/usbsnoop/index.php) to capture USB traces of PowerChute on Windows. The output from usbsnoop is a text file containing a transcript of all the USB communication with a particular device. The format is a bit wonky, but it generally contains enough information to see how PowerChute sets various UPS parameters and how the UPS responds. The traces consist of a series of request/response pairs (called "URBs" in USB lingo). First a request from the host to the device and then a response from the device to the host. The request URB is always sent first and is followed by the response. Note that more than one request may be outstanding at a time so the response is not always the very next URB in the trace, although it usually is. The URB number can be used to match responses with requests. Here is an example URB, number 108: [4945 ms] UsbSnoop - DispatchAny(f7c08610) : IRP_MJ_INTERNAL_DEVICE_CONTROL [4945 ms] UsbSnoop - MyDispatchInternalIOCTL(f7c09e80) : fdo=8602b460, Irp=85e84cb0, IRQL=0 [4945 ms] >>> URB 108 going down >>> -- URB_FUNCTION_CLASS_INTERFACE: TransferFlags = 00000001 (USBD_TRANSFER_DIRECTION_IN, ~USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000005 TransferBuffer = f7f1efd0 TransferBufferMDL = 00000000 UrbLink = 00000000 RequestTypeReservedBits = 00000022 Request = 00000001 Value = 00000323 Index = 00000000 [4950 ms] UsbSnoop - MyInternalIOCTLCompletion(f7c09db0) : fido=863b9030, Irp=85e84cb0, Context=86001650, IRQL=2 [4950 ms] <<< URB 108 coming back <<< -- URB_FUNCTION_CONTROL_TRANSFER: PipeHandle = 86109ac8 TransferFlags = 0000000b (USBD_TRANSFER_DIRECTION_IN, USBD_SHORT_TRANSFER_OK) TransferBufferLength = 00000003 TransferBuffer = f7f1efd0 TransferBufferMDL = 860ba270 00000000: 23 7f 00 UrbLink = 00000000 SetupPacket = 00000000: a1 01 23 03 00 00 05 00 usbsnoop uses the term "going down" to refer to the host->device request and "coming back" to refer to the device->host response. The request and response are both timestamped with an offset in msec since usbsnoop started up. Several lines can be safely ignored. Lines starting with a timestamp and "UsbSnoop - ..." generally contain Windows-specific usbsnoop debugging info and are of no use to us. Also, PipeHandle, TransferBuffer, TransferBufferMDL, UrbLink, and SetupPacket fields are not particularly useful, either. Also, keep in mind that usbsnoop will not display fields that it considers "uninteresting" and it will display additional fields sometimes if it thinks they are interesting. For example, some packets will not show the RequestTypeReservedBits field if the bits are set to indicate a standard USB transaction. This fluctuation of displayed fields can be really aggravating since it makes comparison and trend-spotting harder. The URBs can be of different transfer types and often the request and response are not the same type. I'm going to vastly over-simplify and talk about what we care about for apcupsd. Generally speaking, all the interesting data for apcupsd is in one of two pairs. Either URB_FUNCTION_CLASS_INTERFACE (request) -> URB_FUNCTION_CONTROL_TRANSFER (response) or URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER (both request & response) URBs. The CONTROL_TRANSFERs are when a specific data item is read from or written to the UPS by the host. The INTERRUPT_TRANSFERs are when the UPS spontaneously sends the host some information. Note that even INTERRUPT_TRANSFERs have both a request and a response; the request is basically empty and the response comes back filled in. CONTROL_TRANSFER: The CONTROL_TRANSFER URBs begin with a CLASS_INTERFACE request in which the host identifies what report it wants to access from the ups. The reports consist of a one byte tag which identifies the report in question and a multi-byte (generally 1, 2, or 3 byte) data section. For us, the CLASS_INTERFACE transfers of interest have RequestTypeReservedBits=00000022 (this indicates a class-specific command and all UPS commands are specific to the HID class) and have a Request=00000001 (read) or Request=0000000a (write). The example above shows a read request. The actual report tag number is the last byte in the Value line (0x23 in the example above). Down in the response packet the line after "TransferBufferMDL" contains the data sent back by the UPS: "23 7f 00". The 0x23 is the report tag again and 0x007f is the value (little endian). From hid-ups we can look up report 0x23 (decimal 35): FeatureReport 35 Field 0, app UPS, phys Output Usage 0, HighVoltageTransfer = XYZ Volts So we can see that in the example packet the UPS is reporting a HighVoltageTransfer of 127 V (0x007f). Note that the report tags differ between UPS models so you need to look at hid-ups output for the same basic model as you're tracing. A write looks about the same except the request packet says "Request=0000000a" and the data line containing the report tag and value is in the request packet instead of the response packet. INTERRUPT_TRANSFER: Interrupt transfers in our case are all reads. You can basically ignore the request part of the URB because it contains no useful data. The response will have a data line just like a CONTROL_TRANSFER response and you can decode the report tag and value from that. THE EASY WAY: Ok, so now that I've dragged you through the hard way I'll tell you how to cheat. I wrote a tool that parses the trace and produces output showing one URB per line and clearly stating the report tag, value, and whether it's a read or a write. It also suppresses all reads that don't show a change in state, so the trace isn't cluttered with repetitive reads of the same value. The output looks like this: [0001 s] 00058 READ 0x23 007f (127) [0001 s] 00060 READ 0x24 006a (106) [0001 s] 00052 * READ 0x1c 00 (0) [0002 s] 00061 READ 0x40 0000 (0) [0002 s] 00063 READ 0x41 0000 (0) The columns are: timestamp (in seconds), URB number (so you can correlate it to the full trace), READ/WRITE, report tag, and value in hex and (decimal). A * between the URB number and transaction type indicates an interrupt transfer as opposed to polling. I've attached the code for the parsing tool "snoopdecode". It reads from stdin and writes to stdout so you can do things like "cat mytrace.log | snoopdecode | grep 0x23" and watch how a particular value changed over time. Builds with plain old 'gcc -o snoopdecode snoopdecode.c'. It leaks memory. It has no error checking. There are probably more than a few snoop traces that will crash it terribly. But it's still easier than reading snoop output by hand. Hope this was useful; Feel free to ask questions... --Adam apcupsd-3.14.14/include/000077500000000000000000000000001274230402600147465ustar00rootroot00000000000000apcupsd-3.14.14/include/HidUps.h000066400000000000000000000076001274230402600163160ustar00rootroot00000000000000/* * HidUps.h * * Utility class for interfacing with a HID based UPS using libusb and the * libusbhid userspace HID parsing library. */ /* * Copyright (C) 2004-2014 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _HIDUPS_H #define _HIDUPS_H #include "usbhid.h" #include "libusb.h" /* Forward-declaration */ struct usb_dev_handle; #define HID_KIND_INPUT (1 << hid_input) #define HID_KIND_OUTPUT (1 << hid_output) #define HID_KIND_FEATURE (1 << hid_feature) #define HID_KIND_COLLECTION (1 << hid_collection) #define HID_KIND_ENDCOLLECTION (1 << hid_endcollection) #define HID_KIND_ALL (HID_KIND_INPUT | \ HID_KIND_OUTPUT | \ HID_KIND_FEATURE | \ HID_KIND_COLLECTION | \ HID_KIND_ENDCOLLECTION) class HidUps { public: HidUps(); ~HidUps(); bool Open(const char *serno = NULL); void Close(); /* * Locate an item matching the given parameters. If found, the * item is copied to the supplied buffer. Returns true on success, * false on failure. Any of usage, app, phys, logical, and kind * may be set to -1 for "don't care". */ int LocateItem(int usage, int app, int phys, int logical, int kind, hid_item_t *outitem); /* * Fetch a report from a device given an fd for the device's control * endpoint, the populated item structure describing the report, a * data buffer in which to store the result, and the report length. * Returns actual report length (in bytes) on success and -1 on failure. */ int GetReport(hid_item_t *item, unsigned char *data, int len); /* * Send a report to the device given an fd for the device's control * endpoint, the populated item structure, the data to send, and the * report length. Returns true on success, false on failure. */ int SetReport(hid_item_t *item, unsigned char *data, int len); /* * Fetch a string descriptor from the device given an fd for the * device's control endpoint and the string index. Returns a pointer * to a static buffer containing the NUL-terminated string or NULL * on failure. */ const char *GetString(int index); int GetReportSize(enum hid_kind k, int id) { return hid_report_size(_rdesc, k, id); } int InterruptWrite(int ep, const void *bytes, int size, int timeout) { return usb_interrupt_write(_fd, ep, (char*)bytes, size, timeout); } int InterruptRead(int ep, const void *bytes, int size, int timeout) { return usb_interrupt_read(_fd, ep, (char*)bytes, size, timeout); } private: /* * Fetch the report descriptor from the device given an fd for the * device's control endpoint. Descriptor length is written to the * rlen out paramter and a pointer to a malloc'ed buffer containing * the descriptor is returned. Returns NULL on failure. */ unsigned char *FetchReportDescr(int *rlen); /* Fetch a descriptor from an interface (as opposed to from the device) */ int GetIntfDescr( unsigned char type, unsigned char index, void *buf, int size); bool init_device(struct usb_device *dev, const char *serno); usb_dev_handle *_fd; report_desc_t _rdesc; }; #endif apcupsd-3.14.14/include/aarray.h000066400000000000000000000034211274230402600163760ustar00rootroot00000000000000/* * aarray.h * * Simple dynamic array template class. */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __AARRAY_H #define __AARRAY_H template class aarray { public: aarray() : _data(NULL), _size(0) {} aarray(const aarray &rhs) : _data(NULL), _size(0) { *this = rhs; } ~aarray() { delete [] _data; } aarray &operator=(const aarray &rhs) { if (this != &rhs) { delete [] _data; _size = 0; if (rhs._size) { _size = rhs._size; _data = new T[_size]; for (unsigned int i = 0; i < _size; i++) _data[i] = rhs._data[i]; } } return *this; } void append(const T& t) { T *tmp = new T[_size+1]; for (unsigned int i = 0; i < _size; i++) tmp[i] = _data[i]; delete [] _data; _data = tmp; _data[_size++] = t; } unsigned int size() const { return _size; } T& operator[](unsigned int idx) { return _data[idx]; } const T& operator[](unsigned int idx) const { return _data[idx]; } private: T *_data; unsigned int _size; }; #endif apcupsd-3.14.14/include/aiter.h000066400000000000000000000036001274230402600162220ustar00rootroot00000000000000/* * aiter.h * * Iterator functions for aXXX classes. */ /* * Copyright (C) 2008 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __AITER_H #define __AITER_H template class const_iterator { public: const_iterator() {} const_iterator(const const_iterator &rhs) : _iter(rhs._iter) {} const_iterator(const I &rhs) : _iter(rhs) {} const_iterator &operator++() { ++_iter; return *this; } const_iterator operator++(int) { const_iterator tmp(_iter); ++_iter; return tmp; } const_iterator &operator--() { --_iter; return *this; } const_iterator operator--(int) { const_iterator tmp(_iter); --_iter; return tmp; } const T& operator*() const { return *_iter; } bool operator==(const const_iterator &rhs) const { return _iter == rhs._iter; } bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); } bool operator==(const I &rhs) const { return _iter == rhs; } bool operator!=(const I &rhs) const { return !(*this == rhs); } const_iterator &operator=(const const_iterator &rhs) { if (&rhs != this) _iter = rhs._iter; return *this; } const_iterator &operator=(const I &rhs) { if (&rhs != &_iter) _iter = rhs; return *this; } private: I _iter; }; #endif // __AITER_H apcupsd-3.14.14/include/alist.h000066400000000000000000000123411274230402600162340ustar00rootroot00000000000000/* * alist.h * * Simple double linked list template class. */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __ALIST_H #define __ALIST_H #include #include "aiter.h" template class alist { private: class node { public: node(const T& elem) : _next(NULL), _prev(NULL), _elem(elem) {} ~node() { if (_prev) _prev->_next = _next; if (_next) _next->_prev = _prev; } operator T&() { return _elem; } T& operator*() { return _elem; } void next(node *link) { link->_next = _next; link->_prev = this; if (_next) _next->_prev = link; _next = link; } void prev(node *link) { link->_next = this; link->_prev = _prev; if (_prev) _prev->_next = link; _prev = link; } node *next() { return _next; } node *prev() { return _prev; } bool operator==(const node &rhs) const { return _next == rhs._next && _prev == rhs._prev; } private: node *_next, *_prev; T _elem; }; public: alist() : _head(NULL), _tail(NULL), _size(0) {} alist(const alist &rhs) : _head(NULL), _tail(NULL), _size(0) { append(rhs); } virtual ~alist() { while (!empty()) remove(begin()); _size = 0; } T& first() { return *_head; } T& last() { return *_tail; } bool empty() const { return _size <= 0; } unsigned int size() const { return _size; } T& append(const T& elem) { node *nd = new node(elem); if (_tail) _tail->next(nd); else _head = nd; _tail = nd; _size++; return *_tail; } T& prepend(const T& elem) { node *nd = new node(elem); if (_head) _head->prev(nd); else _tail = nd; _head = nd; _size++; return *_head; } T& append(const alist& rhs) { if (&rhs != this) { for(const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) { append(*iter); } } return *_tail; } alist& operator+=(const alist& rhs) { append(rhs); return *this; } alist& operator=(const alist& rhs) { if (&rhs != this) { clear(); append(rhs); } return *this; } void remove_first() { if (!empty()) remove(_head); } void remove_last() { if (!empty()) remove(_tail); } void clear() { while (!empty()) remove(_head); } class iterator { public: iterator() : _node(NULL) {} iterator(const iterator &rhs) : _node(rhs._node) {} iterator &operator++() { _node = _node->next(); return *this; } iterator operator++(int) { iterator tmp(_node); ++(*this); return tmp; } iterator &operator--() { _node = _node->prev(); return *this; } iterator operator--(int) { iterator tmp(_node); --(*this); return tmp; } T& operator*() { return *_node; } const T& operator*() const { return *_node; } T* operator->() { return &(**_node); } const T* operator->() const { return &(**_node); } bool operator==(const iterator &rhs) const { return _node == rhs._node; } bool operator!=(const iterator &rhs) const { return !(*this == rhs); } iterator &operator=(const iterator &rhs) { if (&rhs != this) _node = rhs._node; return *this; } private: friend class alist; iterator(node *node) : _node(node) {} node *_node; }; typedef ::const_iterator const_iterator; iterator begin() { return iterator(_head); } iterator end() { return iterator(NULL); } const_iterator begin() const { return iterator(_head); } const_iterator end() const { return iterator(NULL); } iterator remove(iterator iter) { if (iter == _head) _head = iter._node->next(); if (iter == _tail) _tail = iter._node->prev(); iterator newiter(iter._node->next()); delete iter._node; _size--; return newiter; } iterator find(const T& needle) { iterator iter; for (iter = begin(); iter != end(); ++iter) if (*iter == needle) break; return iter; } const_iterator find(const T& needle) const { const_iterator iter; for (iter = begin(); iter != end(); ++iter) if (*iter == needle) break; return iter; } T &front() { return *_head; } const T &front() const { return *_head; } private: node *_head, *_tail; unsigned int _size; }; #endif apcupsd-3.14.14/include/amap.h000066400000000000000000000100051274230402600160310ustar00rootroot00000000000000/* * amap.h * * Simple map template class build on alist. */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __AMAP_H #define __AMAP_H #include "alist.h" #include "aiter.h" template class amap { private: struct keyval { keyval() {} keyval(const K& key) : _key(key) {} bool operator==(const keyval &rhs) const { return _key == rhs._key; } K _key; V _val; }; public: amap() {} ~amap() {} V& operator[](const K& key) { typename alist::iterator iter = _map.find(key); return (iter == _map.end()) ? _map.append(key)._val : (*iter)._val; } bool contains(const K& key) const { return _map.find(key) != _map.end(); } bool empty() const { return _map.empty(); } class iterator { public: iterator() {} iterator(const iterator &rhs) : _iter(rhs._iter) {} iterator &operator++() { ++_iter; return *this; } iterator operator++(int) { iterator tmp(_iter); ++(*this); return tmp; } iterator &operator--() { --_iter; return *this; } iterator operator--(int) { iterator tmp(_iter); --(*this); return tmp; } V& value() { return (*_iter)._val; } K& key() { return (*_iter)._key; } V& operator*() { return value(); } bool operator==(const iterator &rhs) const { return _iter == rhs._iter; } bool operator!=(const iterator &rhs) const { return !(*this == rhs); } iterator &operator=(const iterator &rhs) { if (&rhs != this) _iter = rhs._iter; return *this;} protected: friend class amap; iterator(const typename alist::iterator &iter) : _iter(iter) {} typename alist::iterator _iter; }; class const_iterator { public: const_iterator() {} const_iterator(const const_iterator &rhs) : _iter(rhs._iter) {} const_iterator &operator++() { ++_iter; return *this; } const_iterator operator++(int) { const_iterator tmp(_iter); ++(*this); return tmp; } const_iterator &operator--() { --_iter; return *this; } const_iterator operator--(int) { const_iterator tmp(_iter); --(*this); return tmp; } const V& value() const { return (*_iter)._val; } const K& key() const { return (*_iter)._key; } const V& operator*() const { return value(); } bool operator==(const const_iterator &rhs) const { return _iter == rhs._iter; } bool operator!=(const const_iterator &rhs) const { return !(*this == rhs); } const_iterator &operator=(const const_iterator &rhs) { if (&rhs != this) _iter = rhs._iter; return *this;} protected: friend class amap; const_iterator(const typename alist::const_iterator &iter) : _iter(iter) {} typename alist::const_iterator _iter; }; iterator end() { return iterator(_map.end()); } iterator begin() { return iterator(_map.begin()); } const_iterator end() const { return _map.end(); } const_iterator begin() const { return _map.begin(); } iterator find(const K& key) { return iterator(_map.find(key)); } const_iterator find(const K& key) const { return _map.find(key); } private: // Should really use a hash table for efficient random lookups, // but for now we'll take the easy route and use alist. alist _map; // Prevent use amap(const amap &rhs); amap &operator=(const amap &rhs); }; #endif // __AMAP_H apcupsd-3.14.14/include/amutex.h000066400000000000000000000036271274230402600164320ustar00rootroot00000000000000/* * amutex.h * * Simple mutex wrapper class. */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __AMUTEX_H #define __AMUTEX_H #include #include "astring.h" // Wrappers for debug trace #define LOCK(m) \ do { \ Dmsg(500, "lock 0x%p @ %s:%d\n", &m, __FILE__, __LINE__); \ m.lock(); \ } while(0) #define UNLOCK(m) \ do { \ Dmsg(500, "unlock 0x%p @ %s:%d\n", &m, __FILE__, __LINE__); \ m.unlock(); \ } while(0) class amutex { public: amutex(const char *name = DEFAULT_NAME, bool recursive = false); ~amutex(); // Basic lock/unlock are inlined for efficiency inline void lock() const { pthread_mutex_lock(&_mutex); } inline void unlock() const { pthread_mutex_unlock(&_mutex); } protected: mutable pthread_mutex_t _mutex; astring _name; private: static const char *DEFAULT_NAME; // Prevent use amutex(const amutex &rhs); amutex &operator=(const amutex &rhs); }; #endif apcupsd-3.14.14/include/apc.h000066400000000000000000000060451274230402600156670ustar00rootroot00000000000000/* * apc.h * * Main header file for apcupsd package */ /* * Copyright (C) 1999-2005 Kern Sibbald * Copyright (C) 1999 Brian Schau * Copyright (C) 1996-99 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef APC_H #define APC_H 1 # include "apcconfig.h" /* * Solaris needs BSD_COMP set in order to get FIONBIO * For simplicity, we set it across the board. */ #define BSD_COMP /* * Note, on the Alpha, we must include stdarg to get * the GNU version before stdio or we get multiple * definitions. This order could probably be used * on all systems, but is untested so I #ifdef it. * KES 9/2000 */ #ifdef HAVE_OSF1_OS # include # include # include #else # include # include # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_GETOPTLONG # include #else # include "getopt.h" #endif #define _THREAD_SAFE 1 #define _REENTRANT 1 #include #ifdef HAVE_SUN_OS # include # define set_thread_concurrency() thr_setconcurrency(4) #else # define set_thread_concurrency() #endif #include #include #include #include #include #include #include #include #include #include #include #include #include # ifdef HAVE_SYS_IPC_H # include # endif # ifdef HAVE_SYS_SEM_H # include # endif # ifdef HAVE_SYS_SHM_H # include # endif #ifdef HAVE_SYS_SOCKET_H # include #endif #include #ifdef HAVE_UNISTD_H # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef HAVE_SYS_WAIT_H # include #endif #ifdef HAVE_HPUX_OS # include #endif #ifdef HAVE_QNX_OS # include # include #endif #include #include #ifdef HAVE_MINGW #include #endif /* Include apcupsd stuff */ #include "version.h" #include "defines.h" #include "struct.h" #include "drivers.h" #include "nis.h" #include "extern.h" /* System includes conditionally included */ #ifdef HAVE_LIBWRAP # ifdef __cplusplus extern "C" { # endif # include # ifdef __cplusplus }; # endif #endif #endif apcupsd-3.14.14/include/aqueue.h000066400000000000000000000053361274230402600164130ustar00rootroot00000000000000/* * aqueue.h * * Simple thread-safe blocking queue */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __AQUEUE_H #define __AQUEUE_H #include #include #include "alist.h" #include "autil.h" template class aqueue { public: aqueue() { pthread_mutex_init(&_mutex, NULL); pthread_cond_init(&_condvar, NULL); } ~aqueue() { pthread_cond_destroy(&_condvar); pthread_mutex_destroy(&_mutex); } void enqueue(const T &elem) { pthread_mutex_lock(&_mutex); _queue.append(elem); pthread_mutex_unlock(&_mutex); pthread_cond_signal(&_condvar); } bool dequeue(T& elem, int msec = TIMEOUT_FOREVER) { int rc = 0; pthread_mutex_lock(&_mutex); if (msec != TIMEOUT_FOREVER) { struct timespec abstime; calc_abstimeout(msec, &abstime); while (rc == 0 && _queue.empty()) rc = pthread_cond_timedwait(&_condvar, &_mutex, &abstime); } else { while (rc == 0 && _queue.empty()) rc = pthread_cond_wait(&_condvar, &_mutex); } if (rc) { pthread_mutex_unlock(&_mutex); return false; } elem = _queue.first(); _queue.remove_first(); pthread_mutex_unlock(&_mutex); return true; } T dequeue() { pthread_mutex_lock(&_mutex); int rc = 0; while (rc == 0 && _queue.empty()) rc = pthread_cond_wait(&_condvar, &_mutex); T elem = _queue.first(); _queue.remove_first(); pthread_mutex_unlock(&_mutex); return elem; } bool empty() { pthread_mutex_lock(&_mutex); bool tmp = _queue.empty(); pthread_mutex_unlock(&_mutex); return tmp; } void clear() { pthread_mutex_lock(&_mutex); _queue.clear(); pthread_mutex_unlock(&_mutex); } private: static const int TIMEOUT_FOREVER = -1; pthread_mutex_t _mutex; pthread_cond_t _condvar; alist _queue; // Prevent use aqueue(const aqueue &rhs); aqueue &operator=(const aqueue &rhs); }; #endif apcupsd-3.14.14/include/astring.h000066400000000000000000000051651274230402600165750ustar00rootroot00000000000000/* * astring.h * * Simple string management class. Like STL, but lighter. */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __ASTRING_H #define __ASTRING_H #include #include class astring { public: astring() : _data(NULL) { assign(""); } astring(const char *str) : _data(NULL) { assign(str); } astring(const astring &str) : _data(NULL) { assign(str._data); } ~astring() { delete [] _data; } int len() const { return _len; } int format(const char *format, ...); int vformat(const char *format, va_list args); astring &operator=(const astring &rhs); astring &operator=(const char *rhs); astring &operator=(const char rhs); const char &operator[](int index) const; char &operator[](int index); astring &operator+(const char *rhs); astring &operator+=(const char *rhs) { return *this + rhs; } astring &operator+(const astring &rhs); astring &operator+=(const astring &rhs) { return *this + rhs; } astring &operator+(const char rhs); astring &operator+=(const char rhs) { return *this + rhs; } bool operator==(const char *rhs) const { return !strcmp(_data, rhs); } bool operator==(const astring &rhs) const { return *this == rhs._data; } bool operator!=(const char *rhs) const { return !(*this == rhs); } bool operator!=(const astring &rhs) const { return !(*this == rhs); } astring substr(int start, int len = -1) const; int strchr(char ch) const; operator const char *() const { return _data; } const char *str() const { return _data; } astring &rtrim(); astring <rim(); astring &trim() { ltrim(); return rtrim(); } bool empty() const { return _len == 0; } int compare(const char *rhs) const { return strcmp(_data, rhs); } private: void realloc(unsigned int newlen); void assign(const char *str, int len = -1); char *_data; int _len; }; inline astring operator+(const char *lhs, const astring &rhs) { return astring(lhs) + rhs; } #endif apcupsd-3.14.14/include/athread.h000066400000000000000000000022571274230402600165350ustar00rootroot00000000000000/* * athread.h * * Simple POSIX based thread class */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __ATHREAD_H #define __ATHREAD_H #include class athread { public: athread(int prio = PRIORITY_INHERIT) : _prio(prio), _running(false) {} virtual ~athread() {} virtual bool run(); virtual bool join(); protected: virtual void body() = 0; static void *springboard(void *arg); static const int PRIORITY_INHERIT; pthread_t _tid; int _prio; bool _running; }; #endif apcupsd-3.14.14/include/atimer.h000066400000000000000000000026121274230402600164010ustar00rootroot00000000000000/* * atimer.h * * Simple POSIX based timer class */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __ATIMER_H #define __ATIMER_H #include #include "athread.h" class atimer: public athread { public: class client { public: virtual void HandleTimeout(int id) = 0; protected: client() {} virtual ~client() {} }; atimer(client &cli, int id = 0); ~atimer(); void start(unsigned long msec); void stop(); private: virtual void body(); client &_client; int _id; pthread_mutex_t _mutex; pthread_cond_t _condvar; bool _started; struct timespec _abstimeout; // Prevent use atimer(const atimer &rhs); atimer &operator=(const atimer &rhs); }; #endif // __ATIMER_H apcupsd-3.14.14/include/autil.h000066400000000000000000000015731274230402600162430ustar00rootroot00000000000000/* * autil.h * * Common helper routines for a* classes. */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __AUTIL_H #define __AUTIL_H #include void calc_abstimeout(int msec, struct timespec *abstime); #endif apcupsd-3.14.14/include/defines.h000066400000000000000000000437471274230402600165530ustar00rootroot00000000000000/* * defines.h * * Public definitions used throughout apcupsd */ /* * Copyright (C) 1999-2005 Kern Sibbald * Copyright (C) 1996-1999 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _DEFINES_H #define _DEFINES_H #ifndef APCCONTROL_FILE # define APCCONTROL_FILE "/apccontrol" #endif #ifndef APCCONF_FILE # define APCCONF_FILE "/apcupsd.conf" #endif #ifndef PWRFAIL_FILE # define PWRFAIL_FILE "/powerfail" #endif #ifndef NOLOGIN_FILE # define NOLOGIN_FILE "/nologin" #endif #define APCPID PIDDIR "/apcupsd.pid" /* * These two are not to be touched: we can not be sure how the user will * insert the locks directory path so we have to prepend the '/' just to be * sure: is better have /blah//LCK.. than /blahLCK.. */ #define APC_LOCK_PREFIX "/LCK.." #define LOCK_DEFAULT "/var/lock" /* * This string should be the first line of the configuration file. * Then if we change the format later, we can just change this string. * Also, we could write code to use/convert out-of-date config files. */ #define APC_CONFIG_MAGIC "## apcupsd.conf v1.1 ##" #define POWERFAIL "POWER FAILURE\n" /* put in nologin file */ #define MAXSTRING 256 #define MESSAGELEN 256 #define MAXTOKENLEN 100 #define UPSNAMELEN 100 #define DEFAULT_SPEED B2400 /* bit values for APC UPS Status Byte (ups->Status) */ #define UPS_calibration 0x00000001 #define UPS_trim 0x00000002 #define UPS_boost 0x00000004 #define UPS_online 0x00000008 #define UPS_onbatt 0x00000010 #define UPS_overload 0x00000020 #define UPS_battlow 0x00000040 #define UPS_replacebatt 0x00000080 /* Extended bit values added by apcupsd */ #define UPS_commlost 0x00000100 /* Communications with UPS lost */ #define UPS_shutdown 0x00000200 /* Shutdown in progress */ #define UPS_slave 0x00000400 /* Set if this is a slave */ #define UPS_slavedown 0x00000800 /* Slave not responding */ #define UPS_onbatt_msg 0x00020000 /* Set when UPS_ONBATT message is sent */ #define UPS_fastpoll 0x00040000 /* Set on power failure to poll faster */ #define UPS_shut_load 0x00080000 /* Set when BatLoad <= percent */ #define UPS_shut_btime 0x00100000 /* Set when time on batts > maxtime */ #define UPS_shut_ltime 0x00200000 /* Set when TimeLeft <= runtime */ #define UPS_shut_emerg 0x00400000 /* Set when battery power has failed */ #define UPS_shut_remote 0x00800000 /* Set when remote shutdown */ #define UPS_plugged 0x01000000 /* Set if computer is plugged into UPS */ #define UPS_battpresent 0x04000000 /* Indicates if battery is connected */ #define UPS_LOCAL_BITS (UPS_commlost|UPS_shutdown|UPS_slave|UPS_slavedown| \ UPS_onbatt_msg|UPS_fastpoll|UPS_plugged| \ UPS_shut_load|UPS_shut_btime|UPS_shut_ltime|UPS_shut_emerg) /* * CI_ is Capability or command index * * If the command is valid for this UPS, UPS_Cap[CI_xxx] * will be true. */ enum { CI_UPSMODEL = 0, /* Model number */ CI_STATUS, /* status function */ CI_LQUAL, /* line quality status */ CI_WHY_BATT, /* why transferred to battery */ CI_ST_STAT, /* self test stat */ CI_VLINE, /* line voltage */ CI_VMAX, /* max voltage */ CI_VMIN, /* min line voltage */ CI_VOUT, /* Output voltage */ CI_BATTLEV, /* Battery level percentage */ CI_VBATT, /* Battery voltage */ CI_LOAD, /* UPS Load */ CI_FREQ, /* Line Frequency */ CI_RUNTIM, /* Est. Runtime left */ CI_ITEMP, /* Internal UPS temperature */ CI_DIPSW, /* Dip switch settings */ CI_SENS, /* Sensitivity */ CI_DWAKE, /* Wakeup delay */ CI_DSHUTD, /* Shutdown delay */ CI_LTRANS, /* Low transfer voltage */ CI_HTRANS, /* High transfer voltage */ CI_RETPCT, /* Return percent threshhold */ CI_DALARM, /* Alarm delay */ CI_DLBATT, /* low battery warning, mins */ CI_IDEN, /* UPS Identification (name) */ CI_STESTI, /* Self test interval */ CI_MANDAT, /* Manufacture date */ CI_SERNO, /* serial number */ CI_BATTDAT, /* Last battery change */ CI_NOMBATTV, /* Nominal battery voltage */ CI_HUMID, /* UPS Humidity percentage */ CI_REVNO, /* Firmware revision */ CI_REG1, /* Register 1 */ CI_REG2, /* Register 2 */ CI_REG3, /* Register 3 */ CI_EXTBATTS, /* Number of external batteries */ CI_ATEMP, /* Ambient temp */ CI_NOMOUTV, /* Nominal output voltage */ CI_BADBATTS, /* Number of bad battery packs */ CI_EPROM, /* Valid eprom values */ CI_ST_TIME, /* hours since last self test */ CI_TESTALARM, /* Test alarm */ CI_Manufacturer, CI_ShutdownRequested, CI_ShutdownImminent, CI_DelayBeforeReboot, CI_BelowRemCapLimit, CI_RemTimeLimitExpired, CI_Charging, CI_Discharging, CI_RemCapLimit, CI_RemTimeLimit, CI_WarningCapacityLimit, CI_CapacityMode, CI_BattPackLevel, CI_CycleCount, CI_ACPresent, CI_Boost, CI_Trim, CI_Overload, CI_NeedReplacement, CI_BattReplaceDate, CI_APCForceShutdown, CI_DelayBeforeShutdown, CI_APCDelayBeforeStartup, CI_APCDelayBeforeShutdown, CI_APCLineFailCause, CI_NOMINV, CI_NOMPOWER, CI_LowBattery, CI_Calibration, CI_AlarmTimer, CI_OutputCurrent, CI_LoadApparent, CI_NomApparent, /* Only seen on the BackUPS Pro USB (so far) */ CI_BUPBattCapBeforeStartup, CI_BUPDelayBeforeStartup, CI_BUPSelfTest, CI_BUPHibernate, /* * We don't actually handle these, but use them as a signal * to re-examine the other UPS data items. (USB only) */ CI_IFailure, /* Internal failure */ CI_PWVoltageOOR, /* Power sys voltage out of range */ CI_PWFrequencyOOR, /* Power sys frequency out of range */ CI_OverCharged, /* Battery overcharged */ CI_OverTemp, /* Over temperature */ CI_CommunicationLost, /* USB comms with subsystem lost */ CI_ChargerVoltageOOR, /* Charger voltage our of range */ CI_ChargerCurrentOOR, /* Charger current our of range */ CI_CurrentNotRegulated, /* Charger current not regulated */ CI_VoltageNotRegulated, /* Charger voltage not regulated */ CI_BatteryPresent, /* Battery is present */ CI_LAST_PROBE, /* MUST BE LAST IN SECTION */ /* Items below this line are not "probed" for */ CI_CYCLE_EPROM, /* Cycle programmable EPROM values */ CI_UPS_CAPS, /* Get UPS capabilities (command) string */ CI_LAST /* MUST BE LAST */ }; #define CI_MAXCI (CI_LAST-1) /* maximum UPS commands we handle */ #define CI_MAX_CAPS (CI_LAST_PROBE-1) #define CI_RemainingCapacity CI_BATTLEV #define CI_RunTimeToEmpty CI_RUNTIM /* * APC_CMD_ is the command code sent to UPS for APC Smart UPSes * * NOTE: the APC_CMD_s are never used in the actual code, * except to initialize the UPS_Cmd[] structure. This way, * we will be able to support other UPSes later. The actual * command is obtained by reference to UPS_Cmd[CI_xxx] */ #define APC_CMD_UPSMODEL 0x1 #define APC_CMD_OLDFWREV 'V' #define APC_CMD_STATUS 'Q' #define APC_CMD_LQUAL '9' #define APC_CMD_WHY_BATT 'G' #define APC_CMD_ST_STAT 'X' #define APC_CMD_VLINE 'L' #define APC_CMD_VMAX 'M' #define APC_CMD_VMIN 'N' #define APC_CMD_VOUT 'O' #define APC_CMD_BATTLEV 'f' #define APC_CMD_VBATT 'B' #define APC_CMD_LOAD 'P' #define APC_CMD_FREQ 'F' #define APC_CMD_RUNTIM 'j' #define APC_CMD_ITEMP 'C' #define APC_CMD_DIPSW '7' #define APC_CMD_SENS 's' #define APC_CMD_DWAKE 'r' #define APC_CMD_DSHUTD 'p' #define APC_CMD_LTRANS 'l' #define APC_CMD_HTRANS 'u' #define APC_CMD_RETPCT 'e' #define APC_CMD_DALARM 'k' #define APC_CMD_DLBATT 'q' #define APC_CMD_IDEN 'c' #define APC_CMD_STESTI 'E' #define APC_CMD_MANDAT 'm' #define APC_CMD_SERNO 'n' #define APC_CMD_BATTDAT 'x' #define APC_CMD_NOMBATTV 'g' #define APC_CMD_HUMID 'h' #define APC_CMD_REVNO 'b' #define APC_CMD_REG1 '~' #define APC_CMD_REG2 '\'' #define APC_CMD_REG3 '8' #define APC_CMD_EXTBATTS '>' #define APC_CMD_ATEMP 't' #define APC_CMD_NOMOUTV 'o' #define APC_CMD_BADBATTS '<' #define APC_CMD_EPROM 0x1a #define APC_CMD_ST_TIME 'd' #define APC_CMD_CYCLE_EPROM '-' #define APC_CMD_UPS_CAPS 'a' #define GO_ON_BATT 'W' #define GO_ON_LINE 'X' #define LIGHTS_TEST 'A' #define FAILURE_TEST 'U' /* * Future additions for contolled discharing of batteries * extend lifetimes. */ #define DISCHARGE 'D' #define CHARGE_LIM 25 #define UPS_ENABLED '?' #define UPS_ON_BATT '!' #define UPS_ON_LINE '$' #define UPS_REPLACE_BATTERY '#' #define BATT_LOW '%' #define BATT_OK '+' #define UPS_EPROM_CHANGE '|' #define UPS_TRAILOR ':' #define UPS_LF '\n' #define UPS_CR '\r' /* For apclock.c functions */ #define LCKSUCCESS 0 /* lock file does not exist so go */ #define LCKERROR 1 /* lock file not our own and error encountered */ #define LCKEXIST 2 /* lock file is our own lock file */ #define LCKNOLOCK 3 /* lock file not needed: APC_NET */ /* Generic defines for boolean return values. */ #define SUCCESS 0 /* Function successfull */ #define FAILURE 1 /* Function failure */ /* These seem unavoidable :-( */ #ifndef TRUE # define TRUE 1 #endif #ifndef FALSE # define FALSE 0 #endif /* * We have a timer for the read() for Win32. * We have a timer for the select when nothing is expected, * i.e. we prefer waiting for an state change. * We have a fast timer, when we are on batteries or when * we expect a response (i.e. we sent a character). * And we have a timer for dumb UPSes for doing the sleep(). */ #define TIMER_READ 10 /* read() timeout, max 25 sec */ #define TIMER_SELECT 60 /* Select when not expecting anything */ #define TIMER_FAST 1 /* Value for fast poll */ #define TIMER_DUMB 5 /* for Dumb (ioctl) UPSes -- keep short */ /* Make the size of these strings the next multiple of 4 */ #define APC_MAGIC "apcupsd-linux-6.0" #define APC_MAGIC_SIZE 4 * ((sizeof(APC_MAGIC) + 3) / 4) #define ACCESS_MAGIC "apcaccess-linux-4.0" #define ACCESS_MAGIC_SIZE 4 * ((sizeof(APC_MAGIC) + 3) / 4) #define MAX_THREADS 7 /* Find members position in the UPSINFO and GLOBALCFG structures. */ #define WHERE(MEMBER) ((size_t) &((UPSINFO *)0)->MEMBER) #define AT(UPS,OFFSET) ((size_t)UPS + OFFSET) #define SIZE(MEMBER) ((GENINFO *)sizeof(((UPSINFO *)0)->MEMBER)) /* * These are the commands understood by the apccontrol shell script. * You _must_ keep the #defines in sync with the commands[] array in * action.c */ enum { CMDPOWEROUT = 0, CMDONBATTERY, CMDFAILING, CMDTIMEOUT, CMDLOADLIMIT, CMDRUNLIMIT, CMDDOSHUTDOWN, CMDMAINSBACK, CMDANNOYME, CMDEMERGENCY, CMDCHANGEME, CMDREMOTEDOWN, CMDCOMMFAILURE, CMDCOMMOK, CMDSTARTSELFTEST, CMDENDSELFTEST, CMDOFFBATTERY, /* off battery power */ CMDBATTDETACH, /* Battery disconnected */ CMDBATTATTACH /* Battery reconnected */ }; #define Error_abort(fmd, args...) error_out_wrapper(__FILE__, __LINE__, fmd, ##args) /* Debug Messages that are printed */ #ifdef DEBUG #define Dmsg(lvl, msg, args...) d_msg(__FILE__, __LINE__, lvl, msg, ##args) void d_msg(const char *file, int line, int level, const char *fmt, ...); #define hex_dump(lvl, data, len) h_dump(__FILE__, __LINE__, (lvl), (data), (len)) void h_dump(const char *file, int line, int level, const void *data, unsigned int len); #else #define Dmsg(lvl, msg, args...) do { } while(0) #define hex_dump(lvl, data, len) do { } while(0) #endif /* These probably should be subroutines */ #define P(x) \ do { \ int errstat; \ if ((errstat=pthread_mutex_lock(&(x)))) \ error_out_wrapper(__FILE__, __LINE__, "Mutex lock failure. ERR=%s\n", strerror(errstat)); \ } while(0) #define V(x) \ do { \ int errstat; \ if ((errstat=pthread_mutex_unlock(&(x)))) \ error_out_wrapper(__FILE__, __LINE__, "Mutex unlock failure. ERR=%s\n", strerror(errstat)); \ } while(0) /* Send terminate signal to itself. */ #define sendsig_terminate() \ { \ kill(getpid(), SIGTERM); \ exit(0); \ } /* Determine the difference, in milliseconds, between two struct timevals. */ #define TV_DIFF_MS(a, b) \ (((b).tv_sec - (a).tv_sec) * 1000 + ((b).tv_usec - (a).tv_usec) / 1000) /* * Some platforms, like Solaris, hide MIN/MAX in an obscure header. * It's easiest just to define them ourselves instead of trying to * find the right thing to include. */ #ifndef MIN #define MIN(a,b) ( (a) < (b) ? (a) : (b) ) #endif #ifndef MAX #define MAX(a,b) ( (a) > (b) ? (a) : (b) ) #endif /* On Windows, sockets are SOCKET, everywhere else they are int */ #ifdef HAVE_MINGW typedef SOCKET sock_t; #else typedef int sock_t; #define INVALID_SOCKET -1 #endif /* * For HP-UX the definition of FILENAME_MAX seems not conformant with * POSIX standard. To avoid any problem we are forced to define a * private macro. This accounts also for other possible problematic OSes. * If none of the standard macros is defined, fall back to 256. */ #if defined(FILENAME_MAX) && FILENAME_MAX > 255 # define APC_FILENAME_MAX FILENAME_MAX #elif defined(PATH_MAX) && PATH_MAX > 255 # define APC_FILENAME_MAX PATH_MAX #elif defined(MAXPATHLEN) && MAXPATHLEN > 255 # define APC_FILENAME_MAX MAXPATHLEN #else # define APC_FILENAME_MAX 256 #endif #ifndef O_NDELAY # define O_NDELAY 0 #endif #ifndef O_CLOEXEC # define O_CLOEXEC 0 #endif /* ETIME not on BSD, incl. Darwin */ #ifndef ETIME # define ETIME ETIMEDOUT #endif /* If no system localtime_r(), forward declaration of our internal substitute. */ #if !defined(HAVE_LOCALTIME_R) && !defined(localtime_r) extern struct tm *localtime_r(const time_t *timep, struct tm *tm); #endif /* If no system inet_pton(), forward declaration of our internal substitute. */ #if !defined(HAVE_INETPTON) /* Define constants based on RFC 883, RFC 1034, RFC 1035 */ #define NS_PACKETSZ 512 /* maximum packet size */ #define NS_MAXDNAME 1025 /* maximum domain name */ #define NS_MAXCDNAME 255 /* maximum compressed domain name */ #define NS_MAXLABEL 63 /* maximum length of domain label */ #define NS_HFIXEDSZ 12 /* #/bytes of fixed data in header */ #define NS_QFIXEDSZ 4 /* #/bytes of fixed data in query */ #define NS_RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ #define NS_INT32SZ 4 /* #/bytes of data in a u_int32_t */ #define NS_INT16SZ 2 /* #/bytes of data in a u_int16_t */ #define NS_INT8SZ 1 /* #/bytes of data in a u_int8_t */ #define NS_INADDRSZ 4 /* IPv4 T_A */ #define NS_IN6ADDRSZ 16 /* IPv6 T_AAAA */ #define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ #define NS_DEFAULTPORT 53 /* For both TCP and UDP. */ extern int inet_pton(int af, const char *src, void *dst); #endif #ifndef HAVE_STRFTIME # define strftime(msg, max, format, tm) \ strlcpy(msg, "time not available", max) #endif /* !HAVE_STRFTIME */ /* Solaris doesn't define this */ #ifndef INADDR_NONE #define INADDR_NONE ((in_addr_t)-1) #endif /* Determine if the C(++) compiler requires complete function prototype */ #ifndef __P # if defined(__STDC__) || defined(__cplusplus) || defined(c_plusplus) # define __P(x) x # else # define __P(x) () # endif #endif #endif /* _DEFINES_H */ apcupsd-3.14.14/include/drivers.h000066400000000000000000000120101274230402600165670ustar00rootroot00000000000000/* * drivers.h * * Header file for exporting UPS drivers. */ /* * Copyright (C) 1999-2001 Riccardo Facchetti * Copyright (C) 1996-1999 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _DRIVERS_H #define _DRIVERS_H /* * This is the generic drivers structure. It contain any routine needed for * managing a device (or family of devices, like Smart UPSes). * * Routines defined: * * open() * Opens the device and setup the file descriptor. Returns a working file * descriptor. This function does not interact with hardware functionality. * In case of error, this function does not return. It simply exit. * * setup() * Setup the device for operations. This function interacts with hardware to * make sure on the other end there is an UPS and that the link is working. * In case of error, this function does not return. It simply exit. * * close() * Closes the device returning it to the original status. * This function always returns. * * kill_power() * Put the UPS into hibernation mode, killing output power. * This function always returns. * * shutdown() * Turn off the UPS completely. * This function always returns. * * read_ups_static_data() * Gets the static data from UPS like the UPS name. * This function always returns. * * read_ups_volatile_data() * Fills UPSINFO with dynamic UPS data. * This function always returns. * This function must lock the UPSINFO structure. * * get_ups_capabilities() * Try to understand what capabilities the UPS is able to perform. * This function always returns. * * check_ups_state() * Check if the UPS changed state. * This function always returns. * This function must lock the UPSINFO structure. * * program_eeprom(ups, command, data) * Commit changes to the internal UPS eeprom. * This function performs the eeprom change command (using data), * then returns. * * ups_generic_entry_point() * This is a generic entry point into the drivers for specific driver * functions called from inside the apcupsd core. * This function always return. * This function must lock the UPSINFO structure. * This function gets a void * that contain data. This pointer can be used * to pass data to the function or to get return values from the function, * depending on the value of "command" and the general design of the specific * command to be executed. * Each driver will have its specific functions and will ignore any * function that does not understand. */ class UpsDriver { public: UpsDriver(UPSINFO *ups) : _ups(ups) {} virtual ~UpsDriver() {} virtual bool Open() = 0; virtual bool Close() = 0; virtual bool read_static_data() = 0; virtual bool read_volatile_data() = 0; virtual bool get_capabilities() = 0; virtual bool check_state() = 0; virtual bool setup() { return true; } virtual bool kill_power() { return false; } virtual bool shutdown() { return false; } virtual bool program_eeprom(int cmd, const char *data) { return false; } virtual bool entry_point(int cmd, void *data) { return false; } protected: UPSINFO *_ups; }; typedef struct upsdriver { const char *driver_name; UpsDriver *(* factory) (UPSINFO *ups); } UPSDRIVER; /* Some defines that helps code readability. */ #define device_open(ups) ups->driver->Open() #define device_setup(ups) ups->driver->setup() #define device_close(ups) ups->driver->Close() #define device_kill_power(ups) ups->driver->kill_power() #define device_shutdown(ups) ups->driver->shutdown() #define device_read_static_data(ups) ups->driver->read_static_data() #define device_read_volatile_data(ups) ups->driver->read_volatile_data() #define device_get_capabilities(ups) ups->driver->get_capabilities() #define device_check_state(ups) ups->driver->check_state() #define device_program_eeprom(ups, command, data) ups->driver->program_eeprom(command, data) #define device_entry_point(ups, command, data) ups->driver->entry_point(command, data) /* Now some defines for device_entry_point commands. */ /* Dumb entry points. */ #define DEVICE_CMD_DTR_ENABLE 0x00 #define DEVICE_CMD_DTR_ST_DISABLE 0x01 /* Smart entry points. */ #define DEVICE_CMD_GET_SELFTEST_MSG 0x02 #define DEVICE_CMD_CHECK_SELFTEST 0x03 #define DEVICE_CMD_SET_DUMB_MODE 0x04 /* Support routines. */ UpsDriver *attach_driver(UPSINFO *ups); #endif /*_DRIVERS_H */ apcupsd-3.14.14/include/extern.h000066400000000000000000000130251274230402600164250ustar00rootroot00000000000000/* * extern.h * * Public exports. */ /* * Copyright (C) 2000-2005 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _EXTERN_H #define _EXTERN_H /* Function Prototypes */ extern UPSINFO *core_ups; extern char argvalue[MAXSTRING]; extern void (*error_out) (const char *file, int line, const char *fmt, va_list arg_ptr); extern void (*error_cleanup) (void); extern void error_out_wrapper(const char *file, int line, const char *fmt, ...) __attribute__((noreturn)); extern UPSCOMMANDS ups_event[]; extern UPSCMDMSG event_msg[]; /* Serial bits */ extern int le_bit; extern int dtr_bit; extern int rts_bit; extern int st_bit; extern int sr_bit; extern int cts_bit; extern int cd_bit; extern int rng_bit; extern int dsr_bit; /* File opened */ extern int flags; extern struct termios newtio; extern int debug_net; /* getopt flags (see apcoptd.c) */ extern int show_version; extern char *cfgfile; extern int configure_ups; extern int update_battery_date; extern int debug_level; extern int rename_ups; extern int terminate_on_powerfail; extern int hibernate_ups; extern int shutdown_ups; extern int dumb_mode_test; extern int go_background; /* In apcopt.c */ extern int parse_options(int argc, char *argv[]); /* In apcupsd.c */ extern void apcupsd_terminate(int sig); extern void clear_files(void); /* In apcdevice.c */ bool setup_device(UPSINFO *ups); extern void initiate_hibernate(UPSINFO *ups); extern void initiate_shutdown(UPSINFO *ups); extern void prep_device(UPSINFO *ups); extern void do_device(UPSINFO *ups); extern int fillUPS(UPSINFO *ups); /* In apcaction.c */ extern void do_action(UPSINFO *ups); extern void generate_event(UPSINFO *ups, int event); /* In apclock.c */ extern int create_lockfile(UPSINFO *ups); extern void delete_lockfile(UPSINFO *ups); /* In apcfile.c */ extern int make_file(UPSINFO *ups, const char *path); extern void make_pid_file(void); extern void make_pid(void); /* In apcconfig.c */ extern char APCCONF[APC_FILENAME_MAX]; extern void init_ups_struct(UPSINFO *ups); extern void check_for_config(UPSINFO *ups, char *cfgfile); /* In apcnis.c */ extern void do_server(UPSINFO *ups); extern int check_wrappers(char *av, int newsock); /* In apcstatus.c */ extern int output_status(UPSINFO *ups, int fd, void s_open(UPSINFO * ups), void s_write(UPSINFO *ups, const char *fmt, ...), int s_close(UPSINFO * ups, int fd)); extern void stat_open(UPSINFO *ups); extern int stat_close(UPSINFO *ups, int fd); extern void stat_print(UPSINFO *ups, const char *fmt, ...); /* In apcevents.c */ extern int trim_eventfile(UPSINFO *ups); extern int output_events(int sockfd, FILE *events_file); /* In apcreports.c */ extern void clear_files(void); extern int log_status(UPSINFO *ups); extern void do_reports(UPSINFO *ups); /* In apcsignal.c */ extern void init_signals(void (*handler) (int)); /* In newups.c */ extern UPSINFO *new_ups(void); extern UPSINFO *attach_ups(UPSINFO *ups); extern void detach_ups(UPSINFO *ups); extern void destroy_ups(UPSINFO *ups); #define read_lock(ups) _read_lock(__FILE__, __LINE__, (ups)) #define read_unlock(ups) _read_unlock(__FILE__, __LINE__, (ups)) #define write_lock(ups) _write_lock(__FILE__, __LINE__, (ups)) #define write_unlock(ups) _write_unlock(__FILE__, __LINE__, (ups)) #define read_lock(ups) _read_lock(__FILE__, __LINE__, (ups)) extern void _read_lock(const char *file, int line, UPSINFO *ups); extern void _read_unlock(const char *file, int line, UPSINFO *ups); extern void _write_lock(const char *file, int line, UPSINFO *ups); extern void _write_unlock(const char *file, int line, UPSINFO *ups); /* In apcexec.c */ extern int start_thread(UPSINFO *ups, void (*action) (UPSINFO * ups), const char *proctitle, char *argv0); extern int execute_command(UPSINFO *ups, UPSCOMMANDS cmd); extern void clean_threads(void); /* In apclog.c */ extern void log_event(const UPSINFO *ups, int level, const char *fmt, ...); extern void logf(const char *fmt, ...); extern int format_date(time_t timestamp, char *dest, size_t destlen); /* In apcerror.c */ extern void generic_error_out(const char *file, int line, const char *fmt, ...); extern void generic_error_exit(const char *fmt, ...); /* In asys.c */ int avsnprintf(char *str, size_t size, const char *format, va_list ap); int asnprintf(char *str, size_t size, const char *fmt, ...); #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t size); #endif #ifndef HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t size); #endif /* In sleep.c */ #ifndef HAVE_NANOSLEEP int nanosleep(const struct timespec *req, struct timespec *rem); #endif /* In sockcloexec.c */ sock_t socket_cloexec(int domain, int type, int protocol); sock_t accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen); /* * Common interface to the various versions of gethostbyname_r(). * Implemented in gethostname.c. */ struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen); #endif /* _EXTERN_H */ apcupsd-3.14.14/include/getopt.h000066400000000000000000000102701274230402600164210ustar00rootroot00000000000000/* Declarations for getopt. Copyright (C) 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 #ifdef __cplusplus extern "C" { #endif /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ extern char *optarg; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ extern int optind; /* Callers store zero here to inhibit the error message `getopt' prints for unrecognized options. */ extern int opterr; /* Set to an option character which was unrecognized. */ extern int optopt; /* Describe the long-named options requested by the application. The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector of `struct option' terminated by an element containing a name which is zero. The field `has_arg' is: no_argument (or 0) if the option does not take an argument, required_argument (or 1) if the option requires an argument, optional_argument (or 2) if the option takes an optional argument. If the field `flag' is not NULL, it points to a variable that is set to the value given in the field `val' when the option is found, but left unchanged if the option is not found. To have a long-named option do something other than set an `int' to a compiled-in constant, such as set a value from `optarg', set the option's `flag' field to zero and its `val' field to a nonzero value (the equivalent single-letter option character, if there is one). For long options that have a zero `flag' field, `getopt' returns the contents of the `val' field. */ struct option { #if defined (__STDC__) && __STDC__ const char *name; #else char *name; #endif /* has_arg can't be an enum because some compilers complain about type mismatches in all the code that assumes it is an int. */ int has_arg; int *flag; int val; }; /* Names for the values of the `has_arg' field of `struct option'. */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 #if defined (__STDC__) && __STDC__ extern int getopt(int argc, char *const *argv, const char *shortopts); extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); /* Internal only. Users should not call this directly. */ extern int _getopt_internal (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind, int long_only); #else /* not __STDC__ */ extern int getopt (); extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); #endif /* __STDC__ */ #ifdef __cplusplus } #endif #endif /* _GETOPT_H */ apcupsd-3.14.14/include/libusb.h.in000066400000000000000000000004371274230402600170100ustar00rootroot00000000000000/* * libusb pseudo-header * * libusb's API header is "usb.h", which is too generic a name * to include blindly. This header is filled in with the full * path at configure time and various apcupsd bits include this * when they need libusb's usb.h. */ #include "@LIBUSBH@" apcupsd-3.14.14/include/md5.h000066400000000000000000000065041274230402600156110ustar00rootroot00000000000000/* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.h,v 1.1 2006-07-22 15:14:15 adk0212 Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ void md5_init(md5_state_t *pms); /* Append a string to the message. */ void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ apcupsd-3.14.14/include/nis.h000066400000000000000000000033001274230402600157040ustar00rootroot00000000000000/* * nis.h * * Include file for nis.c definitions */ /* * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "defines.h" /* * Receive a message from the other end. Each message consists of * two packets. The first is a header that contains the size * of the data that follows in the second packet. * * Returns number of bytes read * Returns 0 on end of file * Returns -1 on error */ int net_recv(sock_t sockfd, char *buff, int maxlen); /* * Send a message over the network. The send consists of * two network packets. The first is sends a short containing * the length of the data packet which follows. * * Returns number of bytes sent * Returns -1 on error */ int net_send(sock_t sockfd, const char *buff, int len); /* * Open a TCP connection to the UPS network server * * Returns -1 on error * Returns socket file descriptor otherwise */ sock_t net_open(const char *host, char *service, int port); /* Close the network connection */ void net_close(sock_t sockfd); /* Wait for and accept a new TCP connection */ sock_t net_accept(sock_t fd, struct sockaddr_in *cli_addr); apcupsd-3.14.14/include/statmgr.h000066400000000000000000000031241274230402600166000ustar00rootroot00000000000000/* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef STATMGR_H #define STATMGR_H #include "apc.h" #include "amutex.h" #include "alist.h" #include "astring.h" #define MAX_STATS 256 #define MAX_DATA 100 class StatMgr { public: StatMgr(const char *host, unsigned short port); ~StatMgr(); bool Update(); astring Get(const char* key); bool GetAll(alist &keys, alist &values); bool GetEvents(alist &events); bool GetSummary(int &battstat, astring &statstr, astring &upsname); private: bool open(); void close(); char *ltrim(char *str); void rtrim(char *str); char *trim(char *str); void lock(); void unlock(); struct keyval { const char *key; const char *value; char data[MAX_DATA]; }; keyval m_stats[MAX_STATS]; astring m_host; unsigned short m_port; sock_t m_socket; amutex m_mutex; }; #endif // STATMGR_H apcupsd-3.14.14/include/struct.h000066400000000000000000000425701274230402600164530ustar00rootroot00000000000000/* * struct.h * * Common apcupsd structures. */ /* * Copyright (C) 2000-2005 Kern Sibbald * Copyright (C) 1996-1999 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _STRUCT_H #define _STRUCT_H typedef enum { NO_CABLE = 0, /* Default Disable */ // All simple cable types CUSTOM_SIMPLE, /* SIMPLE cable simple */ APC_940_0119A, /* APC cable number 940-0119A */ APC_940_0127A, /* APC cable number 940-0127A */ APC_940_0128A, /* APC cable number 940-0128A */ APC_940_0020B, /* APC cable number 940-0020B */ APC_940_0020C, /* APC cable number 940-0020C identical to 20B */ APC_940_0023A, /* APC cable number 940-0023A */ MAM_CABLE, /* MAM cable for Alfatronic SPS500X */ // These can (apparently) act as smart or simple cables; for our // purposes we treat them as simple cables. APC_940_0095A, /* APC cable number 940-0095A */ APC_940_0095B, /* APC cable number 940-0095B */ APC_940_0095C, /* APC cable number 940-0095C */ // All smart cable types CABLE_SMART, /* SMART cable smart */ // Other cables APC_NET, /* Ethernet Link */ USB_CABLE /* USB cable */ } UpsCable; typedef enum { NO_UPS = 0, /* Default Disable */ DUMB_UPS, /* Dumb UPS driver */ APCSMART_UPS, /* APC Smart UPS (any) */ USB_UPS, /* USB UPS driver */ NETWORK_UPS, /* NETWORK UPS driver */ TEST_UPS, /* TEST UPS Driver */ PCNET_UPS, /* PCNET UPS Driver */ SNMPLITE_UPS, /* SNMP Lite UPS Driver */ MODBUS_UPS, /* MODBUS UPS Driver */ } UpsMode; typedef enum { NO_CLASS = 0, STANDALONE, SHARESLAVE, SHAREMASTER, } ClassMode; typedef enum { NO_SHARE_NET = 0, DISABLE, /* Disable Share or Net UPS */ SHARE, /* ShareUPS Internal */ } ShareNetMode; typedef enum { NO_LOGON = 0, NEVER, /* Disable Setting NoLogon */ TIMEOUT, /* Based on TIMEOUT + 10 percent */ PERCENT, /* Based on PERCENT + 10 percent */ MINUTES, /* Based on MINUTES + 10 percent */ ALWAYS /* Stop All New Login Attempts. but ROOT */ } NoLoginMode; /* List all the internal self tests allowed. */ typedef enum { SMART_TEST_LEDS = 0, SMART_TEST_SELFTEST, SMART_TEST_POWERFAIL, SMART_TEST_CALIBRATION, SMART_CHANGE_NAME, SMART_CHANGE_BATTDATE, SMART_CHANGE_EPROM, SMART_TEST_MAX } SelfTests; typedef enum { XFER_NA = 0, /* Not supported by this UPS */ XFER_NONE, /* No xfer since power on */ XFER_OVERVOLT, /* Utility voltage too high */ XFER_UNDERVOLT, /* Utility voltage too low */ XFER_NOTCHSPIKE, /* Line voltage notch or spike */ XFER_RIPPLE, /* Excessive utility voltage rate of change */ XFER_SELFTEST, /* Auto or manual self test */ XFER_FORCED, /* Forced onto battery by sw command */ XFER_FREQ, /* Input frequency out of range */ XFER_UNKNOWN } LastXferCause; typedef enum { TEST_NA = 0, /* Not supported by this UPS */ TEST_NONE, /* No self test result available */ TEST_FAILED, /* Test failed (reason unknown) */ TEST_WARNING, /* Test passed with warning */ TEST_INPROGRESS, /* Test currently in progress */ TEST_PASSED, /* Test passed */ TEST_FAILCAP, /* Test failed due to insufficient capacity */ TEST_FAILLOAD, /* Test failed due to overload */ TEST_UNKNOWN } SelfTestResult; typedef struct geninfo { const char *name; /* JHNC: name mustn't contain whitespace */ const char *long_name; int type; } GENINFO; /* for static declaration of data */ typedef struct internalgeninfo { char name[MAXSTRING]; /* JHNC: name mustn't contain whitespace */ char long_name[MAXSTRING]; int type; } INTERNALGENINFO; /* for assigning into upsinfo */ class UpsDriver; class UPSINFO { public: /* Methods */ void clear_battlow() { Status &= ~UPS_battlow; }; void clear_boost() { Status &= ~UPS_boost; }; void clear_calibration() { Status &= ~UPS_calibration; }; void clear_commlost() { Status &= ~UPS_commlost; }; void clear_fastpoll() { Status &= ~UPS_fastpoll; }; void clear_onbatt_msg() { Status &= ~UPS_onbatt_msg; }; void clear_onbatt() { Status &= ~UPS_onbatt; }; void clear_online() { Status |= UPS_onbatt; Status &= ~UPS_online; }; void clear_overload() { Status &= ~UPS_overload; }; void clear_plugged() { Status &= ~UPS_plugged; }; void clear_replacebatt() { Status &= ~UPS_replacebatt; }; void clear_shut_btime() { Status &= ~UPS_shut_btime; }; void clear_shutdown() { Status &= ~UPS_shutdown; }; void clear_shut_emerg() { Status &= ~UPS_shut_emerg; }; void clear_shut_load() { Status &= ~UPS_shut_load; }; void clear_shut_ltime() { Status &= ~UPS_shut_ltime; }; void clear_shut_remote() { Status &= ~UPS_shut_remote; }; void clear_slavedown() { Status &= ~UPS_slavedown; }; void clear_slave() { Status &= ~UPS_slave; }; void clear_trim() { Status &= ~UPS_trim; }; void clear_battpresent() {Status &= ~UPS_battpresent; }; void set_battlow() { Status |= UPS_battlow; }; void set_battlow(int val) { if (val) set_battlow(); else clear_battlow(); }; void set_boost() { Status |= UPS_boost; }; void set_boost(int val) { if (val) set_boost(); else clear_boost(); }; void set_calibration() { Status |= UPS_calibration; }; void set_calibration(int val) { if (val) set_calibration(); else clear_calibration(); }; void set_commlost() { Status |= UPS_commlost; }; void set_fastpoll() { Status |= UPS_fastpoll; }; void set_onbatt_msg() { Status |= UPS_onbatt_msg; }; void set_onbatt() { Status |= UPS_onbatt; }; void set_online() { Status |= UPS_online; Status &= ~UPS_onbatt; }; void set_online(int val) { if (val) set_online(); else clear_online(); }; void set_overload() { Status |= UPS_overload; }; void set_overload(int val) { if (val) set_overload(); else clear_overload(); }; void set_plugged() { Status |= UPS_plugged; }; void set_replacebatt() { Status |= UPS_replacebatt; }; void set_replacebatt(int val) { if (val) set_replacebatt(); else clear_replacebatt(); }; void set_shut_btime() { Status |= UPS_shut_btime; }; void set_shut_btime(int val) { if (val) set_shut_btime(); else clear_shut_btime(); }; void set_shutdown() { Status |= UPS_shutdown; }; void set_shut_emerg() { Status |= UPS_shut_emerg; }; void set_shut_emerg(int val) { if (val) set_shut_emerg(); else clear_shut_emerg(); }; void set_shut_load() { Status |= UPS_shut_load; }; void set_shut_load(int val) { if (val) set_shut_load(); else clear_shut_load(); }; void set_shut_ltime() { Status |= UPS_shut_ltime; }; void set_shut_ltime(int val) { if (val) set_shut_ltime(); else clear_shut_ltime(); }; void set_shut_remote() { Status |= UPS_shut_remote; }; void set_slavedown() { Status |= UPS_slavedown; }; void set_slavedown(int val) { if (val) set_slavedown(); else clear_slavedown(); }; void set_slave() { Status |= UPS_slave; }; void set_trim() { Status |= UPS_trim; }; void set_trim(int val) { if (val) set_trim(); else clear_trim(); }; void set_battpresent() { Status |= UPS_battpresent; }; void set_battpresent(int val) { if (val) set_battpresent(); else clear_battpresent(); }; bool is_battlow() const { return (Status & UPS_battlow) == UPS_battlow; }; bool is_boost() const { return (Status & UPS_boost) == UPS_boost; }; bool is_calibration() const { return (Status & UPS_calibration) == UPS_calibration; }; bool is_commlost() const { return (Status & UPS_commlost) == UPS_commlost; }; bool is_fastpoll() const { return (Status & UPS_fastpoll) == UPS_fastpoll; }; bool is_onbatt() const { return (Status & UPS_onbatt) == UPS_onbatt; }; bool is_onbatt_msg() const { return (Status & UPS_onbatt_msg) == UPS_onbatt_msg; }; bool is_online() const { return (Status & UPS_online) == UPS_online; }; bool is_overload() const { return (Status & UPS_overload) == UPS_overload; }; bool is_plugged() const { return (Status & UPS_plugged) == UPS_plugged; }; bool is_replacebatt() const { return (Status & UPS_replacebatt) == UPS_replacebatt; }; bool is_shut_btime() const { return (Status & UPS_shut_btime) == UPS_shut_btime; }; bool is_shutdown() const { return (Status & UPS_shutdown) == UPS_shutdown; }; bool is_shut_emerg() const { return (Status & UPS_shut_emerg) == UPS_shut_emerg; }; bool is_shut_load() const { return (Status & UPS_shut_load) == UPS_shut_load; }; bool is_shut_ltime() const { return (Status & UPS_shut_ltime) == UPS_shut_ltime; }; bool is_shut_remote() const { return (Status & UPS_shut_remote) == UPS_shut_remote; }; bool is_slave() const { return (Status & UPS_slave) == UPS_slave; }; bool is_slavedown() const { return (Status & UPS_slavedown) == UPS_slavedown; }; bool is_trim() const { return (Status & UPS_trim) == UPS_trim; }; bool is_battpresent() const { return (Status & UPS_battpresent) == UPS_battpresent; }; bool chg_battlow() const { return ((Status ^ PrevStatus) & UPS_battlow) == UPS_battlow; }; bool chg_onbatt() const { return ((Status ^ PrevStatus) & UPS_onbatt) == UPS_onbatt; }; bool chg_battpresent() const { return ((Status ^ PrevStatus) & UPS_battpresent) == UPS_battpresent; }; bool chg_shut_remote() const { return ((Status ^ PrevStatus) & UPS_shut_remote) == UPS_shut_remote; }; /* DATA */ int fd; /* UPS device node file descriptor */ /* UPS capability array and codes */ char UPS_Cap[CI_MAXCI + 1]; /* TRUE if UPS has capability */ unsigned int UPS_Cmd[CI_MAXCI + 1]; /* Command or function code */ INTERNALGENINFO cable; /* UPSCABLE directive */ INTERNALGENINFO nologin; /* NOLOGON directive */ INTERNALGENINFO mode; /* UPSTYPE directive */ INTERNALGENINFO upsclass; /* UPSCLASS directive */ INTERNALGENINFO sharenet; /* UPSMODE directive */ int num_execed_children; /* children created in execute_command() */ /* Internal state flags set in response to UPS condition */ time_t ShutDown; /* set when doing shutdown */ time_t SelfTest; /* start time of self test */ time_t LastSelfTest; /* time of last self test */ time_t poll_time; /* last time UPS polled -- fillUPS() */ time_t start_time; /* time apcupsd started */ time_t last_onbatt_time; /* last time on batteries */ time_t last_offbatt_time; /* last time off batteries */ time_t last_time_on_line; time_t last_time_annoy; time_t last_time_nologon; time_t last_time_changeme; time_t last_master_connect_time; /* last time master connected */ time_t start_shut_ltime; time_t start_shut_load; time_t start_shut_lbatt; int num_xfers; /* number of times on batteries */ int cum_time_on_batt; /* total time on batteries since startup */ int wait_time; /* suggested wait time for drivers in * device_check_state() */ /* Items reported by smart UPS */ /* Volatile items -- i.e. they change with the state of the UPS */ char linequal[8]; /* Line quality */ unsigned int reg1; /* register 1 */ unsigned int reg2; /* register 2 */ unsigned int reg3; /* register 3 */ unsigned int dipsw; /* dip switch info */ unsigned int InputPhase; /* The current AC input phase. */ unsigned int OutputPhase; /* The current AC output phase. */ LastXferCause lastxfer; /* Reason for last xfer to battery */ SelfTestResult testresult; /* results of last seft test */ double BattChg; /* remaining UPS charge % */ double LineMin; /* min line voltage seen */ double LineMax; /* max line voltage seen */ double UPSLoad; /* output real power load percentage */ double LoadApparent; /* output apparent power load percentage */ double LineFreq; /* line freq. */ double LineVoltage; /* Line Voltage */ double OutputVoltage; /* Output Voltage */ double OutputFreq; /* Output Frequency */ double OutputCurrent; /* Output Current */ double UPSTemp; /* UPS internal temperature */ double BattVoltage; /* Actual Battery voltage -- about 24V */ double LastSTTime; /* hours since last self test -- not yet implemented */ int32_t Status; /* UPS status (Bitmapped) */ int32_t PrevStatus; /* Previous UPS status */ double TimeLeft; /* Est. time UPS can run on batt. */ double humidity; /* Humidity */ double ambtemp; /* Ambient temperature */ /* Items reported by smart UPS */ /* Static items that normally do not change during UPS operation */ int NomOutputVoltage; /* Nominal voltage when on batteries */ int NomInputVoltage; /* Nominal input voltage */ int NomPower; /* Nominal real power (watts) */ int NomApparentPower; /* Nominal apparent power (VA) */ double nombattv; /* Nominal batt. voltage -- not actual */ int extbatts; /* number of external batteries attached */ int badbatts; /* number of bad batteries */ int lotrans; /* min line voltage before using batt. */ int hitrans; /* max line voltage before using batt. */ int rtnpct; /* % batt charge necessary for return */ int dlowbatt; /* low batt warning in mins. */ int dwake; /* wakeup delay seconds */ int dshutd; /* shutdown delay seconds */ char birth[20]; /* manufacture date */ char serial[32]; /* serial number */ char battdat[20]; /* battery installation date */ char selftest[9]; /* selftest interval as ASCII */ char firmrev[20]; /* firmware revision */ char upsname[UPSNAMELEN]; /* UPS internal name */ char upsmodel[MAXSTRING]; /* ups model number */ char sensitivity[8]; /* sensitivity to line fluxuations */ char beepstate[8]; /* when to beep on power failure. */ char eprom[500]; /* Eprom values */ /* Items specified from config file */ int annoy; int maxtime; int annoydelay; /* delay before annoying users with logoff request */ int onbattdelay; /* delay before reacting to a power failure */ int killdelay; /* delay after pwrfail before issuing UPS shutdown */ int nologin_time; int nologin_file; int stattime; int datatime; int sysfac; int polltime; /* Time interval to poll the UPS */ int percent; /* shutdown when batt % less than this */ int runtime; /* shutdown when runtime less than this */ char nisip[64]; /* IP for NIS */ int statusport; /* NIS port */ int netstats; /* turn on/off network status */ int logstats; /* turn on/off logging of status info */ char device[MAXSTRING]; /* device name in use */ char configfile[APC_FILENAME_MAX]; /* config filename */ char statfile[APC_FILENAME_MAX]; /* status filename */ char eventfile[APC_FILENAME_MAX]; /* temp events file */ int eventfilemax; /* max size of eventfile in kilobytes */ int event_fd; /* fd for eventfile */ char master_name[APC_FILENAME_MAX]; char lockpath[APC_FILENAME_MAX]; int lockfile; char scriptdir[APC_FILENAME_MAX]; /* Path to apccontrol dir */ char pwrfailpath[APC_FILENAME_MAX]; /* Path to powerfail flag file dir */ char nologinpath[APC_FILENAME_MAX]; /* Path to nologin dir */ int ChangeBattCounter; /* For UPS_REPLACEBATT, see apcaction.c */ pthread_mutex_t mutex; int refcnt; /* thread attach count */ UpsDriver *driver; /* UPS driver for this UPSINFO */ void *driver_internal_data; /* Driver private data */ }; /*These are needed for commands executed in action.c */ typedef struct { const char *command; int pid; } UPSCOMMANDS; typedef struct s_cmd_msg { int level; const char *msg; } UPSCMDMSG; #endif /* _STRUCT_H */ apcupsd-3.14.14/include/usb_common.h000066400000000000000000000021671274230402600172660ustar00rootroot00000000000000/* * usb_common.h * * Public USB driver interface exposed to platform-specific USB sub-drivers. */ /* * Copyright (C) 2001-2004 Kern Sibbald * Copyright (C) 2004-2015 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _USB_COMMON_H #define _USB_COMMON_H #include bool MatchVidPid(uint16_t vid, uint16_t pid); /* Various known USB codes */ #define UPS_USAGE 0x840004 #define UPS_VOLTAGE 0x840030 #define UPS_OUTPUT 0x84001c #define UPS_BATTERY 0x840012 #endif /* _USB_COMMON_H */ apcupsd-3.14.14/include/version.h000066400000000000000000000002411274230402600166010ustar00rootroot00000000000000#define DEBUG 1 #define VERSION "3.14.14" #define ADATE "31 May 2016" #define APCUPSD_RELEASE VERSION #ifndef APCUPSD_HOST # define APCUPSD_HOST HOST #endif apcupsd-3.14.14/platforms/000077500000000000000000000000001274230402600153325ustar00rootroot00000000000000apcupsd-3.14.14/platforms/80-apcupsd-ups-policy.fdi000066400000000000000000000010701274230402600220020ustar00rootroot00000000000000 hald-addon-hid-ups apcupsd-3.14.14/platforms/Makefile000066400000000000000000000012141274230402600167700ustar00rootroot00000000000000.NOTPARALLEL: topdir:=.. SUBDIRS = etc $(DISTDIR) include $(topdir)/autoconf/targets.mak all-install: install-platform all-uninstall: uninstall-platform install-platform: $(call MKDIR,$(sysconfdir)) $(if $(wildcard ./$(DISTNAME)/apccontrol), \ $(call INSTORIG,744,$(DISTNAME)/apccontrol,$(sysconfdir)), \ $(call INSTORIG,744,apccontrol,$(sysconfdir))) $(if $(HALPOLICYDIR),$(call MKDIR,$(HALPOLICYDIR))) $(if $(HALPOLICYDIR),$(call INSTDATA,644,80-apcupsd-ups-policy.fdi,$(HALPOLICYDIR))) uninstall-platform: $(call UNINST,$(sysconfdir)/apccontrol) $(if $(HALPOLICYDIR),$(call UNINST,$(HALPOLICYDIR)/80-apcupsd-ups-policy.fdi)) apcupsd-3.14.14/platforms/alpha/000077500000000000000000000000001274230402600164175ustar00rootroot00000000000000apcupsd-3.14.14/platforms/alpha/Makefile000066400000000000000000000034331274230402600200620ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-alpha all-uninstall: uninstall-alpha install-alpha: $(call DISTINST,alpha) $(call MKDIR,/sbin/init.d) $(call INSTDATA,744,apcupsd,/sbin/init.d/apcupsd) $(call MKDIR,/sbin/rc2.d) $(call SYMLINK,../init.d/apcupsd,/sbin/rc2.d/K56apcupsd) $(call SYMLINK,../init.d/apcupsd,/sbin/rc2.d/S56apcupsd) $(call MKDIR,/sbin/rc3.d) $(call SYMLINK,../init.d/apcupsd,/sbin/rc3.d/K56apcupsd) $(call SYMLINK,../init.d/apcupsd,/sbin/rc3.d/S56apcupsd) # save old halt script $(call COPY,/sbin/rc0,/sbin/rc0.old) # insert apcupsd callout into halt script @echo " AWK " $(DESTDIR)/sbin/rc0 $(V)awk -f awkhaltprog $(DESTDIR)/sbin/rc0.old >$(DESTDIR)/sbin/rc0 $(V)chmod 744 $(DESTDIR)/sbin/rc0 @echo "=================================================" @echo " " @echo "apcupsd script installation for the Alpha $(DISTVER) complete." @echo " " @echo "You should now edit /etc/apcupsd/apcupsd.conf to correspond" @echo "to your setup then start the apcupsd daemon with:" @echo " " @echo "/sbin/init.d/apcupsd start" @echo " " @echo "thereafter when you reboot, it will be stopped and started" @echo "automatically." @echo " " @echo "Please check that your halt script in:" @echo " /sbin/rc0" @echo "was properly updated (see installation section of manual)" @echo " " @echo "=================================================" uninstall-alpha: $(call DISTUNINST,alpha) -$(call UNINST,/sbin/rc2.d/K56apcupsd) -$(call UNINST,/sbin/rc2.d/S56apcupsd) -$(call UNINST,/sbin/rc3.d/K56apcupsd) -$(call UNINST,/sbin/rc3.d/S56apcupsd) -$(call UNINST,/sbin/init.d/apcupsd) $(call COPY,/sbin/rc0,/sbin/rc0.old) $(V)grep -v "###apcupsd###" $(DESTDIR)/sbin/rc0.old >$(DESTDIR)/sbin/rc0 $(V)chmod 744 $(DESTDIR)/sbin/rc0 apcupsd-3.14.14/platforms/alpha/apcupsd.in000066400000000000000000000017471274230402600204170ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid return=" Suceeded" failed=" Failed" case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting UPS monitoring:" @sbindir@/apcupsd -f @sysconfdir@/apcupsd.conf || return=$failed echo "$return" ;; stop) echo -n "Shutting down UPS monitoring:" if [ -f $APCPID ]; then kill `cat $APCPID` || return=$failed rm -f $APCPID else return=$failed fi echo "$return" rm -f $APCPID ;; restart) $0 stop sleep 15 $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0 apcupsd-3.14.14/platforms/alpha/awkhaltprog.in000066400000000000000000000020501274230402600212670ustar00rootroot00000000000000# # Awk program to insert the necessary apcupsd script in # to a halt script. # # Suff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) } # We insert our code just before this line /^# Init single-user state if shutdown/ { print "# See if this is a powerfail situation. # ###apcupsd###" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ###apcupsd###" print " echo # ###apcupsd###" print " echo \"APCUPSD will now power off the UPS\" # ###apcupsd###" print " echo # ###apcupsd###" print " @sysconfdir@/apccontrol killpower # ###apcupsd###" print " echo # ###apcupsd###" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ###apcupsd###" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ###apcupsd###" print " echo # ###apcupsd###" print "fi # ###apcupsd###" print "" } # everything else is duplicated { print } apcupsd-3.14.14/platforms/apccontrol.in000066400000000000000000000076441274230402600200410ustar00rootroot00000000000000#!@SCRIPTSHELL@ # # Copyright (C) 1999-2002 Riccardo Facchetti # # for apcupsd release @VERSION@ (@DATE@) - @DISTNAME@ # # @configure_input@ # # Note, this is a generic file that can be used by most # systems. If a particular system needs to have something # special, start with this file, and put a copy in the # platform subdirectory. # # # These variables are needed for set up the autoconf other variables. # prefix=@prefix@ exec_prefix=@exec_prefix@ APCPID=@PIDDIR@/apcupsd.pid APCUPSD=@sbindir@/apcupsd SHUTDOWN=@SHUTDOWN@ SCRIPTSHELL=@SCRIPTSHELL@ SCRIPTDIR=@sysconfdir@ WALL=wall export SYSADMIN=root export APCUPSD_MAIL="@APCUPSD_MAIL@" if [ -f $SCRIPTDIR/config ]; then . $SCRIPTDIR/config ; fi # # Concatenate all output from this script to the events file # Note, the following kills the script in a power fail situation # where the disks are mounted read-only. # exec >>@LOGDIR@/apcupsd.events 2>&1 # # This piece is to substitute the default behaviour with your own script, # perl, or C program. # You can customize every single command creating an executable file (may be a # script or a compiled program) and calling it the same as the $1 parameter # passed by apcupsd to this script. # # After executing your script, apccontrol continues with the default action. # If you do not want apccontrol to continue, exit your script with exit # code 99. E.g. "exit 99". # # WARNING: the apccontrol file will be overwritten every time you update your # apcupsd, doing `make install'. Your own customized scripts will _not_ be # overwritten. If you wish to make changes to this file (discouraged), you # should change apccontrol.sh.in and then rerun the configure process. # if [ -f ${SCRIPTDIR}/${1} -a -x ${SCRIPTDIR}/${1} ] then ${SCRIPTDIR}/${1} ${2} ${3} ${4} # exit code 99 means he does not want us to do default action if [ $? = 99 ] ; then exit 0 fi fi case "$1" in killpower) echo "Apccontrol doing: ${APCUPSD} --killpower on UPS ${2}" | ${WALL} sleep 10 ${APCUPSD} --killpower echo "Apccontrol has done: ${APCUPSD} --killpower on UPS ${2}" | ${WALL} ;; commfailure) echo "Warning communications lost with UPS ${2}" | ${WALL} ;; commok) echo "Communications restored with UPS ${2}" | ${WALL} ;; # # powerout, onbattery, offbattery, mainsback events occur # in that order. # powerout) ;; onbattery) echo "Power failure on UPS ${2}. Running on batteries." | ${WALL} ;; offbattery) echo "Power has returned on UPS ${2}..." | ${WALL} ;; mainsback) if [ -f @PWRFAILDIR@/powerfail ] ; then printf "Continuing with shutdown." | ${WALL} fi ;; failing) echo "Battery power exhausted on UPS ${2}. Doing shutdown." | ${WALL} ;; timeout) echo "Battery time limit exceeded on UPS ${2}. Doing shutdown." | ${WALL} ;; loadlimit) echo "Remaining battery charge below limit on UPS ${2}. Doing shutdown." | ${WALL} ;; runlimit) echo "Remaining battery runtime below limit on UPS ${2}. Doing shutdown." | ${WALL} ;; doreboot) echo "UPS ${2} initiating Reboot Sequence" | ${WALL} ${SHUTDOWN} -r now "apcupsd UPS ${2} initiated reboot" ;; doshutdown) echo "UPS ${2} initiated Shutdown Sequence" | ${WALL} ${SHUTDOWN} -h now "apcupsd UPS ${2} initiated shutdown" ;; annoyme) echo "Power problems with UPS ${2}. Please logoff." | ${WALL} ;; emergency) echo "Emergency Shutdown. Possible battery failure on UPS ${2}." | ${WALL} ;; changeme) echo "Emergency! Batteries have failed on UPS ${2}. Change them NOW" | ${WALL} ;; remotedown) echo "Remote Shutdown. Beginning Shutdown Sequence." | ${WALL} ;; startselftest) ;; endselftest) ;; battdetach) ;; battattach) ;; *) echo "Usage: ${0##*/} command" echo " warning: this script is intended to be launched by" echo " apcupsd and should never be launched by users." exit 1 ;; esac apcupsd-3.14.14/platforms/contrib-rpm/000077500000000000000000000000001274230402600175665ustar00rootroot00000000000000apcupsd-3.14.14/platforms/contrib-rpm/README000066400000000000000000000055311274230402600204520ustar00rootroot00000000000000README file for apcupsd third party rpm contributors Sat Aug 19 2006 D. Scott Barninger This document outlines the procedures to create rpm packages for apcupsd for platforms supported in the rpm spec file but not published on sourceforge. Contributors wishing to build and supply such rpm packages for release on the sourceforge project page should read this documentation. Contributors should contact either Adam Kropelin or Scott Barninger . The general requirements to have contrib rpm packages published on the project page are: 1. Packages must be created using the current released source rpm and the shell script build_rpm.sh in this directory. 2. The packager must sign all rpm packages with his/her personal gpg key and supply a copy of the public key as both a text file and as an rpm using the spec file rpmkey.spec in this directory. 3. No modifications to either the apcupsd source code or spec file are permitted without consulting the project admins. 4. There will be only one sanctioned packager for a given distribution. 5. Contributors who submit two or more successful releases may be given release permissions to release their files directly to sourceforge. Prior to that you will need to coordinate the upload of your files to sourceforge with Adam or Scott to get them posted to the project page. How to create an rpmkey package: 1. Create a plaintext copy of your gpg public key in a file named yourname.asc where yourname is in the form first initial and last name, ie. sbarninger.asc 2. Edit the rpmkey.spec file and edit the line %define pubkeyname yourname replacing yourname with your name as in step 1 above. 3. Edit the rpmkey.spec file and edit the line Packager: Your Name inserting your name and email information. 4. Copy your key file to your SOURCES directory and the spec file to your SPECS directory and create an rpm package. 5. Both the key text file and the rpm will be published on sourceforge in your release package rpms-contrib-yourname. How to build a release: 1. Copy the file build_rpm.sh to a temporary working directory and open it in a text editor. Examine and edit the configuration section of the script to match your platform and build options. Set permissions on the script to 755. 3. Download the srpm you wish to build to the same directory. 4. Execute the script by ./build_rpm.sh The script will build all the necessary packages, move them into the current working directory, rename them for your platform, and sign them with your key. Note: you must have a file named .rpmmacros in your home directory containing at least the following 2 lines: %_signature gpg %_gpg_name Your Name The name and email information in the above line must correspond to the information in the key used to sign the packages when you generated the key. apcupsd-3.14.14/platforms/contrib-rpm/build_rpm.sh000077500000000000000000000057441274230402600221140ustar00rootroot00000000000000#!/bin/bash # shell script to build apcupsd rpm release # copy this script into a working directory with the src rpm to build and execute # 19 Aug 2006 D. Scott Barninger # licensed under GPL-v2 # signing rpms # Make sure you have a .rpmmacros file in your home directory containing the following: # # %_signature gpg # %_gpg_name Your Name # # the %_gpg_name information must match your key # usage: ./build_rpm.sh ########################################################################################### # script configuration section VERSION=3.14.10 RELEASE=1 # build platform for spec # set to one of rh7,rh8,rh9,fedora_core,rhel3,rhel4,suse,mdk PLATFORM=suse # platform designator for file names # for RedHat/Fedora set to one of rh7,rh8,rh9,fc1,fc3,fc4,fc5 OR # for RHEL3/clones set to el3 OR # for RHEL4/clones set to el4 OR # for SuSE set to su90, su91, su92, su100 or su101 OR # for Mandrake set to 101mdk or 20060mdk FILENAME=su114 # enter your name and email address here PACKAGER="D. Scott Barninger " # enter the full path to your RPMS output directory RPMDIR=/usr/src/packages/RPMS/i586 # enter your arch string here (i386, i586, i686, x86_64) ARCH=i586 # if the src rpm is not in the current working directory enter the directory location # with trailing slash where it is found. SRPMDIR= # set to 1 to sign packages, 0 not to sign if you want to sign on another machine. SIGN=0 # set to 1 to build gapcmon package (requires Gtk2 >= 2.4) or 0 to not build GAPCMON=1 # to override your language shell variable uncomment and edit this # export LANG=en_US.UTF-8 # Make no changes below this point without consensus ############################################################################################ SRPM=${SRPMDIR}apcupsd-$VERSION-$RELEASE.src.rpm echo Building packages for "$PLATFORM"... sleep 2 if [ "$GAPCMON" = "1" ]; then rpmbuild --rebuild --define "build_${PLATFORM} 1" \ --define "contrib_packager ${PACKAGER}" \ --define "build_gapcmon 1" ${SRPM} fi if [ "$GAPCMON" = "0" ]; then rpmbuild --rebuild --define "build_${PLATFORM} 1" \ --define "contrib_packager ${PACKAGER}" ${SRPM} fi # delete any debuginfo packages built rm -f ${RPMDIR}/apcupsd*debug* # copy files to cwd and rename files to final upload names mv -f ${RPMDIR}/apcupsd-${VERSION}-${RELEASE}.${ARCH}.rpm \ ./apcupsd-${VERSION}-${RELEASE}.${FILENAME}.${ARCH}.rpm mv -f ${RPMDIR}/apcupsd-multimon-${VERSION}-${RELEASE}.${ARCH}.rpm \ ./apcupsd-multimon-${VERSION}-${RELEASE}.${FILENAME}.${ARCH}.rpm mv -f ${RPMDIR}/apcupsd-gapcmon-${VERSION}-${RELEASE}.${ARCH}.rpm \ ./apcupsd-gapcmon-${VERSION}-${RELEASE}.${FILENAME}.${ARCH}.rpm # now sign the packages if [ "$SIGN" = "1" ]; then echo Ready to sign packages...; sleep 2; rpm --addsign ./*.rpm; fi echo echo Finished. echo ls # changelog # 19 Aug 2006 initial release # 21 Jan 2007 add new gapcmon build switch # 27 Jan 2007 add new snmp build switch # 02 Oct 2011 remove snmp build switch (deprecated) apcupsd-3.14.14/platforms/contrib-rpm/rpmkey.spec000066400000000000000000000020661274230402600217550ustar00rootroot00000000000000# rpm public key package # # # replace the string yourname with your name # first initial and lastname, ie. sbarninger %define pubkeyname yourname # replace below with your name and email address Packager: Your Name Summary: The %{pubkeyname} rpm public key Name: rpmkey-%{pubkeyname} Version: 0.1 Release: 1 License: GPL v2 Group: System/Packages Source0: %{pubkeyname}.asc BuildArch: noarch BuildRoot: %{_tmppath}/%{name}-root %define gpgkeypath /etc/apcupsd/pubkeys %description The %{pubkeyname} rpm public key. If you trust %{pubkeyname} component and you want to import this key to the RPM database, then install this RPM. After installing this package you may import the key into your rpm database, as root: rpm --import %{gpgkeypath}/%{pubkeyname}.asc %prep %setup -c -T a1 %build %install mkdir -p %{buildroot}%{gpgkeypath} cp -a %{SOURCE0} %{buildroot}%{gpgkeypath}/ %files %defattr(-, root, root) %{gpgkeypath}/%{pubkeyname}.asc %changelog * Sat Aug 19 2006 D. Scott Barninger CFBundleDevelopmentRegion English CFBundleIconFile CFBundleIdentifier com.apcupsd.driver.dummy CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType KEXT CFBundleSignature ???? CFBundleVersion 1.0.0d1 IOKitPersonalities APC Uninterruptible Power Supply 051d:0002 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 2 idVendor 1309 APC Uninterruptible Power Supply 051d:0003 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 3 idVendor 1309 APC Uninterruptible Power Supply 051d:0004 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 4 idVendor 1309 APC9620 Legacy Communications Card 051d:0001 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 1 idVendor 1309 APC9620 Legacy Communications Card 051d:ffff CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 65535 idVendor 1309 APC Uninterruptible Power Supply 051d:0005 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 5 idVendor 1309 HP T1500 G3 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 8163 idVendor 1008 APC Uninterruptible Power Supply 051d:c801 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51201 idVendor 1309 APC Uninterruptible Power Supply 051d:c802 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51202 idVendor 1309 APC Uninterruptible Power Supply 051d:c803 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51203 idVendor 1309 APC Uninterruptible Power Supply 051d:c804 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51204 idVendor 1309 APC Uninterruptible Power Supply 051d:c805 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51205 idVendor 1309 APC Uninterruptible Power Supply 16de:c801 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51201 idVendor 5854 APC Uninterruptible Power Supply 16de:c802 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51202 idVendor 5854 APC Uninterruptible Power Supply 16de:c803 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51203 idVendor 5854 APC Uninterruptible Power Supply 16de:c804 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51204 idVendor 5854 APC Uninterruptible Power Supply 16de:c805 CFBundleIdentifier com.apple.kpi.iokit IOClass IOService IOProviderClass IOUSBInterface bConfigurationValue 1 bInterfaceNumber 0 idProduct 51205 idVendor 5854 OSBundleLibraries com.apple.iokit.IOUSBFamily 1.8 apcupsd-3.14.14/platforms/darwin/ApcupsdDummy.kext/Contents/_CodeSignature/000077500000000000000000000000001274230402600266735ustar00rootroot00000000000000apcupsd-3.14.14/platforms/darwin/ApcupsdDummy.kext/Contents/_CodeSignature/CodeDirectory000066400000000000000000000002501274230402600313520ustar00rootroot00000000000000 4%3Mcom.apcupsd.driver.dummy84SFEK9KJ7lE%_)!IQeTdv/T\kF2m=ZbXkF2m=ZbXapcupsd-3.14.14/platforms/darwin/ApcupsdDummy.kext/Contents/_CodeSignature/CodeRequirements000066400000000000000000000002701274230402600320730ustar00rootroot00000000000000  com.apcupsd.driver.dummy *Hcd *Hcd subject.OU 84SFEK9KJ7apcupsd-3.14.14/platforms/darwin/ApcupsdDummy.kext/Contents/_CodeSignature/CodeResources000066400000000000000000000037241274230402600313710ustar00rootroot00000000000000 files files2 rules ^Resources/ ^Resources/.*\.lproj/ optional weight 1000 ^Resources/.*\.lproj/locversion.plist$ omit weight 1100 ^version.plist$ rules2 .*\.dSYM($|/) weight 11 ^(.*/)?\.DS_Store$ omit weight 2000 ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ nested weight 10 ^.* ^Info\.plist$ omit weight 20 ^PkgInfo$ omit weight 20 ^Resources/ weight 20 ^Resources/.*\.lproj/ optional weight 1000 ^Resources/.*\.lproj/locversion.plist$ omit weight 1100 ^[^/]+$ nested weight 10 ^embedded\.provisionprofile$ weight 20 ^version\.plist$ weight 20 apcupsd-3.14.14/platforms/darwin/ApcupsdDummy.kext/Contents/_CodeSignature/CodeSignature000066400000000000000000000205621274230402600313570ustar00rootroot000000000000000 *H 01 0 +0 *H d00z–! 0  *H  0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0 120201221215Z 270201221215Z0y1-0+U $Developer ID Certification Authority1&0$U Apple Certification Authority10U Apple Inc.1 0 UUS0"0  *H 0 vO[A#+_s?5 ?$?O>mG V)甝5 ʹ`)xEii`k_#:"1O4YBx.3E EoZ[: 2m6lp&D{H X#ş9~]2_R@꾬d[jDl>İ&{^j=GX1? v(mNi&NVtKfxLY00UW|-,T0U00U#0+iGv k.@GM^0.U'0%0#!http://crl.apple.com/root.crl0U0 *Hcd0  *H  B9tkƤ7* D,Ya2Կ;P9jDt[pKl#q-_œpe- xXI (3zvOߨJ Vg/>ă:wmt.#Qo`H»ZFE~' "rorPu=%]6H9;ꐀ.`x S>O2VMxଚBzFXV,*E K4aUD'sNp000  *H 0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0 060425214036Z 350209214036Z0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0"0  *H 0 䑩 GP^y-6WLUKl"0>P Af$kУ*z G[73Mir]_%UM] d5#KYPXPg ˬ, op?0C=+I(ε^=: !.t< bqGSU/ApLE~LkPAtb A30XZ2hesg^eIv3ew-z0v0U0U00U+iGv k.@GM^0U#0+iGv k.@GM^0U 00 *Hcd00*+https://www.apple.com/appleca/0+0Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.0  *H \6L-x팛wvw0O=G7@,ԱؾsdyO4آ>xk}9S 8ıO k+Y |@Vtӷ#;Go$ѷpE'mx~"5%kԢ$#s`[ /DH`8=&g 3j /Sj[dc3w:,V!ںsO6U٧2Bq~RB$*M^cKP 7uu!00'BP0  *H  0y1-0+U $Developer ID Certification Authority1&0$U Apple Certification Authority10U Apple Inc.1 0 UUS0 151027134605Z 201027134605Z010 &,d 84SFEK9KJ71=0;U 4Developer ID Application: Adam Kropelin (84SFEK9KJ7)10U 84SFEK9KJ710U Adam Kropelin1 0 UUS0"0  *H 0 XRK<Y::YGx@Qڅ AzGLyh &yvOtQKUƣ~ I.| <+"UB]8Mn`hObPy!:{#j`Y}2޷g/|^ !'RWdxn&Tux:=R%O˟S3r4n{M([B"DJ gwDz;!$K500@+40200+0$http://ocsp.apple.com/ocsp04-devid010U%Q:Lpjb90 U00U#0W|-,T0U 00  *Hcd005+)http://www.apple.com/certificateauthority0+0 Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.0U0U% 0 +0 *Hcd 0 *Hcd0  *H  jN cU:gr8[Y0蟦Y‹# Ű$z`KGHQWqPXFX/7[dPL=y6վkש}?؇\"߰fw8. -LJ}!3pcMV3_cXI;A]?xb?=2f+m^tirf6X'joե,A MJзs)`"ai|kHho(1000y1-0+U $Developer ID Certification Authority1&0$U Apple Certification Authority10U Apple Inc.1 0 UUS'BP0 +]0 *H  1  *H 0 *H  1 160129212017Z0# *H  1Ɂ\&(ѴJH/0  *H c i'%w[gV7ihu=s5Q!N}L>+Es'' É߼%]&h>-Rm/HG[4L~d}T @ʌOprg9OZ[-lɪ7.\dѿlv2\Al#+lH;MF5wnmJGq!50Z -^ خ<Çq%ob6nL:=~&F1o0 *H  10 *H 01 0 +0k *H  \Z0X*0!0 +6·!j="ѣ0tb1 yD20160129212017Z0 9A 00o`!0  *H  0|100.U 'Apple Timestamp Certification Authority1&0$U Apple Certification Authority10U Apple Inc.1 0 UUS0 160121004419Z 160303004419Z0A10U Timestamp Signer LTN10U Apple Inc.1 0 UUS0"0  *H 0 yyV rPK(=Po>6N}+k׀>+dg`E- &`mE h}BZIQzM*"4'b4Ib:b6_NI*J|x #3 p}؄p!2U1qh{8^΁eG=p8iN?)FmyT%*1|)?0>I8`#8:V>i00U{vOI7 ~0 U00U#04%N78X&)0U 00 *Hcd00(+http://www.apple.com/appleca0+0 Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.03U,0*0(&$"http://crl.apple.com/timestamp.crl0U0U% 0 +0  *H  %{?? )j\]u?ڇqmĝ@O<6;#j܏?RM 55t=mDrt XǂUHʲ2qS=*d |MͺkM84SKmK ݬ(%~ʬA B4mY 8E@y$ɾꮣpmep9|׿ʙʢ)i ( ȧlzoc>[4eg(`1,00}LWc0  *H  0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0 120405120244Z 270405120244Z0|100.U 'Apple Timestamp Certification Authority1&0$U Apple Certification Authority10U Apple Inc.1 0 UUS0"0  *H 0 wg\.#g>B } s@/P'4p <No97ڞecIm] 9 :JidF5ea. =o%L x"!{[ѣ~I; r3,JZr 9Pt(ny_~VVlĮ (tM&By^`EXQI^JMs{Rˣ]klt-D>a>E~4u&@u0Kw00U4%N78X&)0U00U#0+iGv k.@GM^0.U'0%0#!http://crl.apple.com/root.crl0U0 *Hcd 0  *H  6qS#xe[#Ǣϴ(p!93rC=BQu]ˌjj:T}k>mzT_Cv\ N<>r4\g e0B4ӧBsu|QC`ܮ'kg3EoɘMiKEN"W""En?厸F\ɰ:m7(FeoUhR>?&:k22H;Kу000  *H 0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0 060425214036Z 350209214036Z0b1 0 UUS10U  Apple Inc.1&0$U Apple Certification Authority10U Apple Root CA0"0  *H 0 䑩 GP^y-6WLUKl"0>P Af$kУ*z G[73Mir]_%UM] d5#KYPXPg ˬ, op?0C=+I(ε^=: !.t< bqGSU/ApLE~LkPAtb A30XZ2hesg^eIv3ew-z0v0U0U00U+iGv k.@GM^0U#0+iGv k.@GM^0U 00 *Hcd00*+https://www.apple.com/appleca/0+0Reliance on this certificate by any party assumes acceptance of the then applicable standard terms and conditions of use, certificate policy and certification practice statements.0  *H \6L-x팛wvw0O=G7@,ԱؾsdyO4آ>xk}9S 8ıO k+Y |@Vtӷ#;Go$ѷpE'mx~"5%kԢ$#s`[ /DH`8=&g 3j /Sj[dc3w:,V!ںsO6U٧2Bq~RB$*M^cKP 7uu!1?0;00|100.U 'Apple Timestamp Certification Authority1&0$U Apple Certification Authority10U Apple Inc.1 0 UUSo`!0 +0 *H  1  *H  0 *H  1 160129212017Z0# *H  1X•XoGnӘWU0+ *H   1000hCZ:F 590  *H {CXTqs/ƅNt$IK`8gb[b~KUCmH S,"rN?6w5uًK w|vA禫EX31zy,&3I MESLs>xOSz>:P,p$-4.Į%*N9\|^T3$pbzL bl^~)7wIʼ9Zz1! 40S`apcupsd-3.14.14/platforms/darwin/Conclusion.txt000066400000000000000000000014571274230402600215020ustar00rootroot00000000000000Apcupsd has been installed. If you are installing for the first time, an editor will be opened with the apcupsd configuration file, apcupsd.conf. Please edit the file as described in the apcupsd manual (http://www.apcupsd.org/manual) and save your changes before rebooting. If you are upgrading from an existing installation, your apcupsd.conf file will be preserved and a new default file will be provided as apcupsd.conf.new. In most cases you can continue to use your existing configuration file unmodified, but please check the release notes and/or compare against apcupsd.conf.new to catch any required changes. If you encounter any problems with the installation or operation of Apcupsd, please join the apcupsd-users mailing list (http://www.apcupsd.org/email-lists/) and post any questions there. apcupsd-3.14.14/platforms/darwin/Makefile000066400000000000000000000153501274230402600202620ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-darwin install-$(USBDRV) all-uninstall: uninstall-darwin install-darwin: $(call DISTINST,Darwin Mac OS X) $(call MKDIR,/Library/LaunchDaemons) $(call INSTDATA,644,org.apcupsd.apcupsd.plist,/Library/LaunchDaemons) -$(V)chown root:wheel $(DESTDIR)/Library/LaunchDaemons/org.apcupsd.apcupsd.plist $(call INSTDATA,755,apcupsd-uninstall,$(sbindir)) $(call INSTDATA,755,apcupsd-start,$(sbindir)) @echo "=================================================" @echo " " @echo "apcupsd script installation for MacOS X (Darwin) complete." @echo " " @echo "You should now edit $(DESTDIR)/$(sysconfdir)/apcupsd.conf to correspond" @echo "to your setup then start the apcupsd daemon with:" @echo " " @echo " sudo launchctl load /Library/LaunchDaemons/org.apcupsd.apcupsd.plist" @echo " " @echo "Thereafter when you reboot, it will be stopped and started" @echo "automatically." @echo " " @if [ -f $(DESTDIR)/$(sysconfdir)/apcupsd ] ; then \ echo "WARNING: Old startup script $(DESTDIR)/$(sysconfdir)/apcupsd was renamed to"; \ echo " $(DESTDIR)/$(sysconfdir)/apcupsd.obsolete. Be sure to remove any"; \ echo " references to that script that you may have manually"; \ echo " added to the system init scripts. Apcupsd startup is"; \ echo " now managed via SystemStarter, making the old script"; \ echo " obsolete."; \ echo " "; \ mv $(DESTDIR)/$(sysconfdir)/apcupsd $(DESTDIR)/$(sysconfdir)/apcupsd.obsolete; \ fi @echo "=================================================" install-usb: $(call MKDIR,/System/Library/Extensions/ApcupsdDummy.kext/Contents/_CodeSignature) -$(V)$(call INSTDATA,644,ApcupsdDummy.kext/Contents/Info.plist,/System/Library/Extensions/ApcupsdDummy.kext/Contents/Info.plist) -$(V)$(call INSTDATA,644,ApcupsdDummy.kext/Contents/_CodeSignature/CodeDirectory,/System/Library/Extensions/ApcupsdDummy.kext/Contents/_CodeSignature/CodeDirectory) -$(V)$(call INSTDATA,644,ApcupsdDummy.kext/Contents/_CodeSignature/CodeRequirements,/System/Library/Extensions/ApcupsdDummy.kext/Contents/_CodeSignature/CodeRequirements) -$(V)$(call INSTDATA,644,ApcupsdDummy.kext/Contents/_CodeSignature/CodeResources,/System/Library/Extensions/ApcupsdDummy.kext/Contents/_CodeSignature/CodeResources) -$(V)$(call INSTDATA,644,ApcupsdDummy.kext/Contents/_CodeSignature/CodeSignature,/System/Library/Extensions/ApcupsdDummy.kext/Contents/_CodeSignature/CodeSignature) -$(V)chmod 755 $(DESTDIR)/System/Library/Extensions/ApcupsdDummy.kext -$(V)chmod 755 $(DESTDIR)/System/Library/Extensions/ApcupsdDummy.kext/Contents -$(V)chmod 755 $(DESTDIR)/System/Library/Extensions/ApcupsdDummy.kext/Contents/_CodeSignature -$(V)chown -R root:wheel $(DESTDIR)/System/Library/Extensions/ApcupsdDummy.kext $(call UNINST,/System/Library/Extensions.mkext) $(call UNINST,/System/Library/Extensions.kextcache) @echo "=================================================" @echo " " @echo "Driver installation complete." @echo "You must REBOOT before running apcupsd." @echo " " @echo "=================================================" uninstall-darwin: $(call DISTUNINST,Darwin Mac OS X) -$(V)launchctl remove org.apcupsd.apcupsd -$(call UNINST,/System/Library/Extensions/ApcupsdDummy.kext) -$(call UNINST,/System/Library/Extensions.mkext) -$(call UNINST,/System/Library/Extensions.kextcache) -$(call UNINST,$(sbindir)/apcupsd-uninstall) -$(call UNINST,$(sbindir)/apcupsd-start) -$(call UNINST,/Library/LaunchDaemons/org.apcupsd.apcupsd.plist) @echo "=================================================" @echo " " @echo "Please REBOOT to complete uninstall." @echo " " @echo "=================================================" # Root of package build sandbox PKGROOT=/tmp/apcupsd-pkg # # Identity preferences for signing keys, set via Keychain Access utility or on # command line using 'security set-identity-preference' # # APCUPSD_CODE_SIGNING - Code signing key # APCUPSD_PACKAGE_SIGNING - Package signing key # # codesign searches by identity preference automatically CODEKEY := APCUPSD_CODE_SIGNING # productsign needs common name string, so look it up PKGKEY := $(shell \ security get-identity-preference -s APCUPSD_PACKAGE_SIGNING -c \ | grep "common name" | cut -d\" -f2) # Loose executables to sign EXES := $(sbindir)/apcupsd $(sbindir)/apcaccess $(sbindir)/apctest $(sbindir)/smtp # Make apcupsd installation package apcupsd.pkg: rm -rf $(PKGROOT) mkdir $(PKGROOT) mkdir $(PKGROOT)/Apcupsd mkdir $(PKGROOT)/Apcupsd.Resources mkdir $(PKGROOT)/Apcupsd.Scripts mkdir $(PKGROOT)/Apcupsd.Root mkdir $(PKGROOT)/Apcagent.Scripts ( cd $(topdir) && DESTDIR=$(PKGROOT)/Apcupsd.Root make install ) cp $(topdir)/ReleaseNotes $(PKGROOT)/Apcupsd.Resources cp $(topdir)/COPYING $(PKGROOT)/Apcupsd.Resources cp Welcome.txt $(PKGROOT)/Apcupsd.Resources cp Conclusion.txt $(PKGROOT)/Apcupsd.Resources cp ApcupsdDaemon.preflight $(PKGROOT)/Apcupsd.Scripts/preinstall cp ApcupsdDaemon.postflight $(PKGROOT)/Apcupsd.Scripts/postinstall cp apcagent.postinstall $(PKGROOT)/Apcagent.Scripts/postinstall -chown root:wheel $(PKGROOT)/Apcupsd.Root/Library -chown root:wheel $(PKGROOT)/Apcupsd.Root/Library/LaunchDaemons -chmod 1775 $(PKGROOT)/Apcupsd.Root/Library -chmod 0775 $(PKGROOT)/Apcupsd.Root/Library/LaunchDaemons -codesign --sign $(CODEKEY) --timestamp --verbose --force --prefix com.apcupsd. $(addprefix $(PKGROOT)/Apcupsd.Root/,$(EXES)) && \ codesign --verify --verbose $(addprefix $(PKGROOT)/Apcupsd.Root/,$(EXES)) -codesign --sign $(CODEKEY) --timestamp --verbose --force $(PKGROOT)/Apcupsd.Root/Applications/apcagent.app && \ codesign --verify --verbose $(PKGROOT)/Apcupsd.Root/Applications/apcagent.app pkgbuild --root $(PKGROOT)/Apcupsd.Root/Applications \ --identifier com.apcupsd.apcagent --version $(VERSION) \ --install-location /Applications --scripts $(PKGROOT)/Apcagent.Scripts \ --component-plist component.plist $(PKGROOT)/apcagent.pkg rm -rf $(PKGROOT)/Apcupsd.Root/Applications pkgbuild --root $(PKGROOT)/Apcupsd.Root \ --identifier com.apcupsd.apcupsd --version $(VERSION) \ --install-location / --scripts $(PKGROOT)/Apcupsd.Scripts \ $(PKGROOT)/apcupsd.pkg productbuild --distribution apcupsd.dist --package-path $(PKGROOT) \ --resources $(PKGROOT)/Apcupsd.Resources --identifier org.apcupsd.apcupsd \ --version $(VERSION) $(PKGROOT)/Apcupsd-$(VERSION).pkg -productsign --timestamp --sign "$(PKGKEY)" $(PKGROOT)/Apcupsd-$(VERSION).pkg $(PKGROOT)/Apcupsd/Apcupsd-$(VERSION).pkg hdiutil create -ov -fs HFS+ -srcfolder $(PKGROOT)/Apcupsd -volname Apcupsd-$(VERSION) Apcupsd-$(VERSION).dmg apcupsd-3.14.14/platforms/darwin/Welcome.txt000066400000000000000000000016421274230402600207550ustar00rootroot00000000000000Welcome to the Apcupsd installer. You will be guided through the steps necessary to install this software. If you are installing for the first time, at the end of the install procedure an editor will be opened with the apcupsd configuration file, apcupsd.conf. Please edit the file as described in the apcupsd manual (http://www.apcupsd.org/manual) and save your changes before rebooting. If you are upgrading from an existing installation, your apcupsd.conf file will be preserved and a new default file will be provided as apcupsd.conf.new. In most cases you can continue to use your existing configuration file unmodified, but please check the release notes and/or compare against apcupsd.conf.new to catch any required changes. If you encounter any problems with the installation or operation of Apcupsd, please join the apcupsd-users mailing list (http://www.apcupsd.org/email-lists/) and post any questions there. apcupsd-3.14.14/platforms/darwin/apcagent.postinstall000077500000000000000000000004071274230402600227020ustar00rootroot00000000000000#!/bin/sh # Remove abandoned files from /sbin now that install goes to /usr/local/sbin rm -f /sbin/apcupsd rm -f /sbin/apcaccess rm -f /sbin/apctest rm -f /sbin/smtp rm -f /sbin/apcupsd-start rm -f /sbin/apcupsd-uninstall # Launch apcagent open $2/apcagent.app apcupsd-3.14.14/platforms/darwin/apccontrol.in000066400000000000000000000102051274230402600213100ustar00rootroot00000000000000#!@SCRIPTSHELL@ # # Copyright (C) 1999-2002 Riccardo Facchetti # # for apcupsd release @VERSION@ (@DATE@) - @DISTNAME@ # # @configure_input@ # # Note, this is a generic file that can be used by most # systems. If a particular system needs to have something # special, start with this file, and put a copy in the # platform subdirectory. # # # These variables are needed for set up the autoconf other variables. # prefix=@prefix@ exec_prefix=@exec_prefix@ APCPID=@PIDDIR@/apcupsd.pid APCUPSD=@sbindir@/apcupsd SHUTDOWN=@SHUTDOWN@ SCRIPTSHELL=@SCRIPTSHELL@ SCRIPTDIR=@sysconfdir@ WALL=wall export SYSADMIN=root export APCUPSD_MAIL="@APCUPSD_MAIL@" if [ -f $SCRIPTDIR/config ]; then . $SCRIPTDIR/config ; fi # Log notifications using Growl, if available GROWLSEARCH="/usr/bin/growlnotify /usr/local/bin/growlnotify /opt/local/bin/growlnotify" for GROWL in $GROWLSEARCH ; do if [ -x $GROWL ] ; then WALL="$GROWL -t Apcupsd Notice" break fi done # # Concatenate all output from this script to the events file # Note, the following kills the script in a power fail situation # where the disks are mounted read-only. # exec >>@LOGDIR@/apcupsd.events 2>&1 # # This piece is to substitute the default behaviour with your own script, # perl, or C program. # You can customize every single command creating an executable file (may be a # script or a compiled program) and calling it the same as the $1 parameter # passed by apcupsd to this script. # # After executing your script, apccontrol continues with the default action. # If you do not want apccontrol to continue, exit your script with exit # code 99. E.g. "exit 99". # # WARNING: the apccontrol file will be overwritten every time you update your # apcupsd, doing `make install'. Your own customized scripts will _not_ be # overwritten. If you wish to make changes to this file (discouraged), you # should change apccontrol.sh.in and then rerun the configure process. # if [ -f ${SCRIPTDIR}/${1} -a -x ${SCRIPTDIR}/${1} ] then ${SCRIPTDIR}/${1} ${2} ${3} ${4} # exit code 99 means he does not want us to do default action if [ $? = 99 ] ; then exit 0 fi fi case "$1" in killpower) echo "Apccontrol doing: ${APCUPSD} --killpower on UPS ${2}" sleep 10 ${APCUPSD} --killpower echo "Apccontrol has done: ${APCUPSD} --killpower on UPS ${2}" | ${WALL} ;; commfailure) echo "Communications lost with UPS ${2}" | ${WALL} ;; commok) echo "Communications restored with UPS ${2}" | ${WALL} ;; # # powerout, onbattery, offbattery, mainsback events occur # in that order. # powerout) ;; onbattery) echo "Power failure on UPS ${2}. Running on batteries." | ${WALL} ;; offbattery) echo "Power has returned on UPS ${2}..." | ${WALL} ;; mainsback) if [ -f @PWRFAILDIR@/powerfail ] ; then printf "Continuing with shutdown." | ${WALL} fi ;; failing) echo "Battery power exhausted on UPS ${2}. Doing shutdown." | ${WALL} ;; timeout) echo "Battery time limit exceeded on UPS ${2}. Doing shutdown." | ${WALL} ;; loadlimit) echo "Remaining battery charge below limit on UPS ${2}. Doing shutdown." | ${WALL} ;; runlimit) echo "Remaining battery runtime below limit on UPS ${2}. Doing shutdown." | ${WALL} ;; doreboot) echo "UPS ${2} initiating Reboot Sequence" | ${WALL} ${SHUTDOWN} -r now "apcupsd UPS ${2} initiated reboot" ;; doshutdown) echo "UPS ${2} initiated Shutdown Sequence" | ${WALL} ${SHUTDOWN} -h now "apcupsd UPS ${2} initiated shutdown" ;; annoyme) echo "Power problems with UPS ${2}. Please logoff." | ${WALL} ;; emergency) echo "Emergency Shutdown. Possible battery failure on UPS ${2}." | ${WALL} ;; changeme) echo "Emergency! Batteries have failed on UPS ${2}. Change them NOW" | ${WALL} ;; remotedown) echo "Remote Shutdown. Beginning Shutdown Sequence." | ${WALL} ;; startselftest) ;; endselftest) ;; battdetach) ;; battattach) ;; *) echo "Usage: ${0##*/} command" echo " warning: this script is intended to be launched by" echo " apcupsd and should never be launched by users." exit 1 ;; esac apcupsd-3.14.14/platforms/darwin/apcupsd-start.in000077500000000000000000000001211274230402600217350ustar00rootroot00000000000000#!/bin/sh rm -f /etc/apcupsd/powerfail rm -f /etc/nologin @sbindir@/apcupsd $@ apcupsd-3.14.14/platforms/darwin/apcupsd-uninstall.in000077500000000000000000000022561274230402600226240ustar00rootroot00000000000000#!/bin/sh if [ "$USER" != "root" ] ; then echo This script must be run as root. echo Try \'sudo $0\' exit 1 fi confirm= read -p "Are you sure you want to uninstall apcupsd? [Y/N] " confirm case $confirm in y|Y) break ;; *) exit 1 ;; esac launchctl remove org.apcupsd.apcupsd files="/System/Library/Extensions/ApcupsdDummy.kext \ /Library/StartupItems/apcupsd \ /Library/LaunchDaemons/org.apcupsd.apcupsd.plist \ /Applications/apcagent.app \ /etc/apcupsd \ @sbindir@/apcaccess \ @sbindir@/apcupsd \ @sbindir@/apctest \ @sbindir@/smtp \ /usr/share/man/man5/apcupsd.conf.5 \ /usr/share/man/man8/apcaccess.8 \ /usr/share/man/man8/apccontrol.8 \ /usr/share/man/man8/apcupsd.8 \ /usr/share/man/man8/apctest.8 \ /Library/Receipts/Apcupsd-*.pkg \ @sbindir@/apcupsd-uninstall \ @sbindir@/apcupsd-start" echo Removing files... for file in $files ; do if [ -e "$file" ] ; then echo Removing $file rm -rf "$file" fi done # Ensure kext cache gets rebuilt touch /System/Library/Extensions echo Apcupsd files removed. Please reboot to complete the uninstall. apcupsd-3.14.14/platforms/darwin/apcupsd.dist000066400000000000000000000023201274230402600211370ustar00rootroot00000000000000 Apcupsd apcupsd.pkg apcagent.pkg apcupsd-3.14.14/platforms/darwin/build-notes.txt000066400000000000000000000061331274230402600216070ustar00rootroot00000000000000The information in this file is for those who wish to build an apcupsd binary package to run on machines other than the machine on which it was built. If you are building apcupsd for use on the same machine as the one you are building it on, you do not have to do any of this. In that case, just install dependent libs such as libgd and libusb binaries from Fink or MacPorts (or build from source) with no special treatment needed. [Note that for compatibility with the MODBUS driver, libusb now requires a patch...see below.] To build the most compatible apcupsd binary package possible, we must... * Build all dependent libraries static to ensure no extra dylibs are needed on the taget machine * Target a recent SDK so modern features like Notification Center will work * Specify an older minimum version (10.5) so binary will be runnable on older systems (although possibly with certain capabilities disabled) * Build for i386 (not x86_64) to ensure compatibility with 32-bit systems Instructions: - Make a symlink from /Developer to your Xcode Developer directory. This is not required, but makes the paths below much simpler. sudo ln -s /Applications/Xcode.app/Contents/Developer /Developer - Apply darwin-libusb-0.1.12.patch to libusb-0.1.12. This patch fixes several compile errors with newer XCode versions as well as adding support for timeouts on interrupt transfers, which is required by the MODBUS driver. - Build dependent libs (libusb, libpng, libgd) * Tested with libusb-0.1.12, libpng-1.2.51, and gd-2.1.0 libpng & libusb: CPPFLAGS="-isysroot /Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -mmacosx-version-min=10.5" \ LDFLAGS="-Wl,-syslibroot,/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -mmacosx-version-min=10.5 -arch i386" \ CFLAGS="-arch i386" CXXFLAGS="-arch i386" \ ./configure \ --disable-shared \ --disable-dependency-tracking make sudo make install libgd (depends on libpng, so build/install that first): CPPFLAGS="-isysroot /Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -mmacosx-version-min=10.5" \ LDFLAGS="-Wl,-syslibroot,/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -mmacosx-version-min=10.5 -arch i386" \ CFLAGS="-arch i386" CXXFLAGS="-arch i386" \ ./configure \ --disable-shared --disable-dependency-tracking \ --without-fontconfig --without-freetype --without-x \ --with-png=/usr/local make sudo make install - Build apcupsd CPPFLAGS="-isysroot /Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -mmacosx-version-min=10.5" \ LDFLAGS="-L/usr/local/lib -Wl,-syslibroot,/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk -mmacosx-version-min=10.5 -arch i386" \ CFLAGS="-arch i386" CXXFLAGS="-arch i386" \ ./configure --sbindir=/usr/local/sbin \ --enable-usb --enable-cgi --enable-snmp --enable-modbus-usb make - Build apcupsd binary package cd platforms/darwin sudo make apcupsd.pkg The resulting binary package is found in platforms/darwin/Apcupsd-.dmg apcupsd-3.14.14/platforms/darwin/component.plist000066400000000000000000000005751274230402600217040ustar00rootroot00000000000000 RootRelativeBundlePath apcagent.app BundleIsRelocatable BundleOverwriteAction upgrade apcupsd-3.14.14/platforms/darwin/darwin-libusb-0.1.12.patch000066400000000000000000000126631274230402600231260ustar00rootroot00000000000000--- libusb-0.1.12/darwin.c 2006-03-03 21:52:46.000000000 -0500 +++ libusb-0.1.12a/darwin.c 2016-05-03 21:50:23.000000000 -0400 @@ -54,6 +54,7 @@ #include #include #include +#include /* standard includes for darwin/os10 (IOKit) */ #include @@ -247,7 +248,8 @@ io_cf_plugin_ref_t *plugInInterface = NULL; usb_device_t **device; io_service_t usbDevice; - long result, score; + long result; + SInt32 score; if (!IOIteratorIsValid (deviceIterator) || !(usbDevice = IOIteratorNext(deviceIterator))) return NULL; @@ -447,7 +449,7 @@ IOUSBFindInterfaceRequest request; struct darwin_dev_handle *device; - long score; + SInt32 score; int current_interface; device = dev->impl_info; @@ -758,6 +760,7 @@ /* argument to handle multiple parameters to rw_completed */ struct rw_complete_arg { + UInt32 done; UInt32 io_size; IOReturn result; CFRunLoopRef cf_loop; @@ -768,15 +771,28 @@ struct rw_complete_arg *rw_arg = (struct rw_complete_arg *)refcon; if (usb_debug > 2) - fprintf(stderr, "io async operation completed: %s, size=%lu, result=0x%08x\n", darwin_error_str(result), - (UInt32)io_size, result); + fprintf(stderr, "io async operation completed: %s, size=%u, result=0x%08x\n", darwin_error_str(result), + (unsigned int)io_size, result); rw_arg->io_size = (UInt32)io_size; rw_arg->result = result; + rw_arg->done = 1; CFRunLoopStop(rw_arg->cf_loop); } +#define S_TO_NS(x) ( (x) * 1000000000ULL ) +#define MS_TO_NS(x) ( (x) * 1000000ULL ) +#define US_TO_NS(x) ( (x) * 1000ULL ) +#define NS_TO_MS(x) ( ((x)+999999) / 1000000ULL ) + +static uint64_t GetTod() +{ + struct timeval now; + gettimeofday(&now, NULL); + return S_TO_NS(now.tv_sec) + US_TO_NS(now.tv_usec); +} + static int usb_bulk_transfer (usb_dev_handle *dev, int ep, char *bytes, int size, int timeout, rw_async_func_t rw_async, rw_async_to_func_t rw_async_to) { @@ -825,24 +841,54 @@ size, ep); /* Bulk transfer */ - if (transferType == kUSBInterrupt && usb_debug > 3) - fprintf (stderr, "libusb/darwin.c usb_bulk_transfer: USB pipe is an interrupt pipe. Timeouts will not be used.\n"); - + uint64_t endtime = 0; if ( transferType != kUSBInterrupt && rw_async_to != NULL) - result = rw_async_to (device->interface, pipeRef, bytes, size, timeout, timeout, (IOAsyncCallback1)rw_completed, (void *)&rw_arg); - else + else { + endtime = GetTod() + MS_TO_NS(timeout); /* Manual timeout handling */ result = rw_async (device->interface, pipeRef, bytes, size, (IOAsyncCallback1)rw_completed, (void *)&rw_arg); + } + /* wait for transfer to complete */ if (result == kIOReturnSuccess) { - /* wait for write to complete */ - if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, true) == kCFRunLoopRunTimedOut) { - (*(device->interface))->AbortPipe(device->interface, pipeRef); - CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); /* Pick up aborted callback */ - if (usb_debug) - fprintf(stderr, "usb_bulk_read: input timed out\n"); + + if (endtime) { + + /* No timeout support from USB, need to do it manually */ + int aborted = 0; + + /* Timeouts of a second or more get low resolution but efficient handling */ + if (timeout >= 1000) { + if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, (timeout+999)/1000, false) == kCFRunLoopRunTimedOut) { + (*(device->interface))->AbortPipe(device->interface, pipeRef); + aborted = 1; + } + } + + /* Wait for transfer to complete */ + while (!rw_arg.done) { + + if (!aborted && GetTod() >= endtime) { + (*(device->interface))->AbortPipe(device->interface, pipeRef); + aborted = 1; /* We've timed out, continue looping until abort happens */ + } + + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true); + + /* Relax CPU */ + if (!rw_arg.done) + usleep(5000); + } + + /* Abort means we timed out */ + if (rw_arg.result == kIOReturnAborted) + result = kIOUSBTransactionTimeout; + } else { + /* Timeout handled automatically by USB */ + /* Run loop is stopped when rw_completed callback runs */ + CFRunLoopRun(); } } @@ -862,10 +908,7 @@ error_str = darwin_error_str (result); } - if (transferType != kUSBInterrupt && rw_async_to != NULL) - USB_ERROR_STR(-error_code, "usb_bulk_transfer (w/ Timeout): %s", error_str); - else - USB_ERROR_STR(-error_code, "usb_bulk_transfer (No Timeout): %s", error_str); + USB_ERROR_STR(-error_code, "usb_bulk_transfer: %s", error_str); } return rw_arg.io_size; @@ -1064,7 +1107,7 @@ result = (*(device))->GetDeviceAddress(device, (USBDeviceAddress *)&address); if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_devices: Found USB device at location 0x%08lx\n", location); + fprintf(stderr, "usb_os_find_devices: Found USB device at location 0x%08x\n", (unsigned int)location); /* first byte of location appears to be associated with the device's bus */ if (location >> 24 == bus_loc >> 24) { @@ -1091,8 +1134,8 @@ LIST_ADD(fdev, dev); if (usb_debug >= 2) - fprintf(stderr, "usb_os_find_devices: Found %s on %s at location 0x%08lx\n", - dev->filename, bus->dirname, location); + fprintf(stderr, "usb_os_find_devices: Found %s on %s at location 0x%08x\n", + dev->filename, bus->dirname, (unsigned int)location); } /* release the device now */ apcupsd-3.14.14/platforms/darwin/org.apcupsd.apcupsd.plist.in000066400000000000000000000011331274230402600241610ustar00rootroot00000000000000 Label org.apcupsd.apcupsd UserName root GroupName wheel Program @sbindir@/apcupsd-start ProgramArguments /bin/sh -f/etc/apcupsd/apcupsd.conf -b KeepAlive RunAtLoad apcupsd-3.14.14/platforms/debian/000077500000000000000000000000001274230402600165545ustar00rootroot00000000000000apcupsd-3.14.14/platforms/debian/Makefile000066400000000000000000000022101274230402600202070ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-debian all-uninstall: uninstall-debian install-debian: $(call DISTINST,debian) $(if $(DESTDIR),,$(V)/usr/sbin/update-rc.d apcupsd remove) $(call MKDIR,/etc/init.d) $(call INSTDATA,744,apcupsd,/etc/init.d/apcupsd) $(if $(DESTDIR),,$(V)/usr/sbin/update-rc.d apcupsd start 20 1 2 3 4 5 . stop 20 0 1 6 .) $(call INSTORIG,744,ups-monitor,/etc/init.d/ups-monitor) @echo "---------------------------------------------------------------------" @echo " NOTE: APCUPSD will almost certainly not work \"out of the box.\"" @echo " You MUST properly edit $(sysconfdir)/apcupsd.conf or apcupsd" @echo " will fail on startup. Also, please see that your script" @echo " at /etc/init.d/halt properly calls /etc/init.d/ups-monitor" @echo " as shown in platforms/debian/examples/halt.ex." @echo "---------------------------------------------------------------------" uninstall-debian: $(call DISTUNINST,debian) -$(call UNINST,/etc/init.d/apcupsd) -$(if $(DESTDIR),,$(V)/usr/sbin/update-rc.d apcupsd remove) -$(call UNINST,/etc/init.d/ups-monitor) apcupsd-3.14.14/platforms/debian/apcupsd.in000066400000000000000000000027321274230402600205470ustar00rootroot00000000000000#! /bin/sh # # apcupsd # Start the APC UPS daemon to monitor power status. # # Modified for Debian GNU/Linux by Leon Breedt # Last update: Wed Jul 14 15:14:50 SAST 1999 # Further modifications by Gordon Morehouse # Last update: Sun Apr 08 19:07 PDT 2001 DAEMONPID=@PIDDIR@/apcupsd.pid DAEMON=@sbindir@/apcupsd test -x $DAEMON || exit 0 set -e case "$1" in start) echo -n "Starting APC UPS power management: " rm -f @PWRFAILDIR@/powerfail if [ ! -f @nologdir@/nologin.boot -a -f @nologdir@/nologin ]; then rm -f @nologdir@/nologin fi if [ "`pidof apcupsd`" = "" ] then start-stop-daemon --start --quiet --pidfile $DAEMONPID --exec $DAEMON echo "apcupsd." else echo "" echo "A copy of the daemon is still running. If you just stopped it," echo "please wait about 5 seconds for it to shut down." exit 0 fi ;; stop) echo -n "Stopping APC UPS power management: " start-stop-daemon --stop --quiet --pidfile $DAEMONPID echo "apcupsd." ;; restart|force-reload) echo -n "Restarting APC UPS power management: " start-stop-daemon --stop --quiet --pidfile $DAEMONPID sleep 10 start-stop-daemon --start --quiet --pidfile $DAEMONPID --exec $DAEMON echo "apcupsd." ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: /etc/init.d/apcupsd {start|stop|restart|force-reload|status}" >&2 exit 1 ;; esac exit 0 apcupsd-3.14.14/platforms/debian/examples/000077500000000000000000000000001274230402600203725ustar00rootroot00000000000000apcupsd-3.14.14/platforms/debian/examples/cron.d.ex000066400000000000000000000001331274230402600221100ustar00rootroot00000000000000# # Regular cron jobs for the apcupsd package # 0 4 * * * root apcupsd_maintenance apcupsd-3.14.14/platforms/debian/examples/cron.daily000077500000000000000000000004201274230402600223560ustar00rootroot00000000000000#! /bin/sh # apcupsd Cron script to rotate apcupsd log files daily. # # Written by Kevin Foss . # 5/31/99 cd /var/log LOG=apcupsd.log if [ -f $LOG ]; then savelog -g adm -m 644 -u root -c 7 $LOG >/dev/null fi /etc/init.d/apcupsd restart &>/dev/null apcupsd-3.14.14/platforms/debian/examples/emacsen-install.ex000066400000000000000000000023231274230402600240070ustar00rootroot00000000000000#! /bin/sh -e # /usr/lib/emacsen-common/packages/install/apcupsd # Written by Jim Van Zandt , borrowing heavily # from the install scripts for gettext by Santiago Vila # and octave by Dirk Eddelbuettel . FLAVOR=$1 PACKAGE=apcupsd if [ ${FLAVOR} = emacs ]; then exit 0; fi echo install/${PACKAGE}: Handling install for emacsen flavor ${FLAVOR} #FLAVORTEST=`echo $FLAVOR | cut -c-6` #if [ ${FLAVORTEST} = xemacs ] ; then # SITEFLAG="-no-site-file" #else # SITEFLAG="--no-site-file" #fi FLAGS="${SITEFLAG} -q -batch -l path.el -f batch-byte-compile" ELDIR=/usr/share/emacs/site-lisp/${PACKAGE} ELCDIR=/usr/share/${FLAVOR}/site-lisp/${PACKAGE} # Install-info-altdir does not actually exist. # Maybe somebody will write it. if test -x /usr/sbin/install-info-altdir; then echo install/${PACKAGE}: install Info links for ${FLAVOR} install-info-altdir --quiet --section "" "" --dirname=${FLAVOR} /usr/info/${PACKAGE}.info.gz fi install -m 755 -d ${ELCDIR} cd ${ELDIR} FILES=`echo *.el` cp ${FILES} ${ELCDIR} cd ${ELCDIR} cat << EOF > path.el (setq load-path (cons "." load-path) byte-compile-warnings nil) EOF ${FLAVOR} ${FLAGS} ${FILES} rm -f *.el path.el exit 0 apcupsd-3.14.14/platforms/debian/examples/emacsen-remove.ex000066400000000000000000000007211274230402600236360ustar00rootroot00000000000000#!/bin/sh -e # /usr/lib/emacsen-common/packages/remove/apcupsd FLAVOR=$1 PACKAGE=apcupsd if [ ${FLAVOR} != emacs ]; then if test -x /usr/sbin/install-info-altdir; then echo remove/${PACKAGE}: removing Info links for ${FLAVOR} install-info-altdir --quiet --remove --dirname=${FLAVOR} /usr/info/apcupsd.info.gz fi echo remove/${PACKAGE}: purging byte-compiled files for ${FLAVOR} rm -rf /usr/share/${FLAVOR}/site-lisp/${PACKAGE} fi apcupsd-3.14.14/platforms/debian/examples/emacsen-startup.ex000066400000000000000000000013501274230402600240420ustar00rootroot00000000000000;; -*-emacs-lisp-*- ;; ;; Emacs startup file for the Debian GNU/Linux apcupsd package ;; ;; Originally contributed by Nils Naumann ;; Modified by Dirk Eddelbuettel ;; Adapted for dh-make by Jim Van Zandt ;; The apcupsd package follows the Debian/GNU Linux 'emacsen' policy and ;; byte-compiles its elisp files for each 'emacs flavor' (emacs19, ;; xemacs19, emacs20, xemacs20...). The compiled code is then ;; installed in a subdirectory of the respective site-lisp directory. ;; We have to add this to the load-path: (setq load-path (cons (concat "/usr/share/" (symbol-name flavor) "/site-lisp/apcupsd") load-path)) apcupsd-3.14.14/platforms/debian/examples/halt.ex000077500000000000000000000004311274230402600216610ustar00rootroot00000000000000#! /bin/sh # # halt Execute the halt command. # # Version: @(#)halt 2.75 19-May-1998 miquels@cistron.nl # PATH=/sbin:/bin:/usr/sbin:/usr/bin # See if we need to cut the power. if [ -x /etc/init.d/ups-monitor ] then /etc/init.d/ups-monitor poweroff fi halt -d -f -i -p apcupsd-3.14.14/platforms/debian/examples/manpage.1.ex000066400000000000000000000035371274230402600225070ustar00rootroot00000000000000.\" Hey, EMACS: -*- nroff -*- .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) .TH APCUPSD SECTION "March 11, 2001" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: .\" .nh disable hyphenation .\" .hy enable hyphenation .\" .ad l left justify .\" .ad b justify to both left and right margins .\" .nf disable filling .\" .fi enable filling .\" .br insert line break .\" .sp insert n+1 empty lines .\" for manpage-specific macros, see man(7) .SH NAME apcupsd \- program to do something .SH SYNOPSIS .B apcupsd .RI [ options ] " files" ... .br .B bar .RI [ options ] " files" ... .SH DESCRIPTION This manual page documents briefly the .B apcupsd and .B bar commands. This manual page was written for the Debian GNU/Linux distribution because the original program does not have a manual page. Instead, it has documentation in the GNU Info format; see below. .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. \fBapcupsd\fP is a program that... .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. .TP .B \-h, \-\-help Show summary of options. .TP .B \-v, \-\-version Show version of program. .SH SEE ALSO .BR bar (1), .BR baz (1). .br The programs are documented fully by .IR "The Rise and Fall of a Fooish Bar" , available via the Info system. .SH AUTHOR This manual page was written by root , for the Debian GNU/Linux system (but may be used by others). apcupsd-3.14.14/platforms/debian/examples/manpage.sgml.ex000066400000000000000000000077561274230402600233200ustar00rootroot00000000000000 FIRSTNAME"> SURNAME"> March 11, 2001"> SECTION"> fgp@phlo.org"> APCUPSD"> Debian GNU/Linux"> GNU"> ]>
&dhemail;
&dhfirstname; &dhsurname; 2000 &dhusername; &dhdate;
&dhucpackage; &dhsection; &dhpackage; program to do something &dhpackage; DESCRIPTION This manual page documents briefly the &dhpackage; and bar commands. This manual page was written for the &debian; distribution because the original program does not have a manual page. Instead, it has documentation in the &gnu; Info format; see below. &dhpackage; is a program that... OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. Show summary of options. Show version of program. SEE ALSO bar (1), baz (1). The programs are documented fully by The Rise and Fall of a Fooish Bar available via the Info system. AUTHOR This manual page was written by &dhusername; &dhemail; for the &debian; system (but may be used by others).
apcupsd-3.14.14/platforms/debian/examples/menu.ex000066400000000000000000000001621274230402600216730ustar00rootroot00000000000000?package(apcupsd):needs=X11|text|vc|wm section=Apps/see-menu-manual\ title="apcupsd" command="/usr/bin/apcupsd" apcupsd-3.14.14/platforms/debian/examples/postinst.ex000066400000000000000000000023361274230402600226170ustar00rootroot00000000000000#! /bin/sh # postinst script for apcupsd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `configure' # * `abort-upgrade' # * `abort-remove' `in-favour' # # * `abort-deconfigure' `in-favour' # `removing' # # for details, see /usr/share/doc/packaging-manual/ # # quoting from the policy: # Any necessary prompting should almost always be confined to the # post-installation script, and should be protected with a conditional # so that unnecessary prompting doesn't happen if a package's # installation fails and the `postinst' is called with `abort-upgrade', # `abort-remove' or `abort-deconfigure'. case "$1" in configure) ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 0 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 apcupsd-3.14.14/platforms/debian/examples/postrm.ex000066400000000000000000000015501274230402600222550ustar00rootroot00000000000000#! /bin/sh # postrm script for apcupsd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' overwrit>r> # for details, see /usr/share/doc/packaging-manual/ case "$1" in purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; *) echo "postrm called with unknown argument \`$1'" >&2 exit 0 esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# apcupsd-3.14.14/platforms/debian/examples/preinst.ex000066400000000000000000000015641274230402600224220ustar00rootroot00000000000000#! /bin/sh # preinst script for apcupsd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `install' # * `install' # * `upgrade' # * `abort-upgrade' # # For details see /usr/share/doc/packaging-manual/ case "$1" in install|upgrade) # if [ "$1" = "upgrade" ] # then # start-stop-daemon --stop --quiet --oknodo \ # --pidfile /var/run/apcupsd.pid \ # --exec /usr/sbin/apcupsd 2>/dev/null || true # fi ;; abort-upgrade) ;; *) echo "preinst called with unknown argument \`$1'" >&2 exit 0 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 apcupsd-3.14.14/platforms/debian/examples/prerm.ex000066400000000000000000000016161274230402600220610ustar00rootroot00000000000000#! /bin/sh # prerm script for apcupsd # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `upgrade' # * `failed-upgrade' # * `remove' `in-favour' # * `deconfigure' `in-favour' # `removing' # # for details, see /usr/share/doc/packaging-manual/ case "$1" in remove|upgrade|deconfigure) # install-info --quiet --remove /usr/info/apcupsd.info.gz ;; failed-upgrade) ;; *) echo "prerm called with unknown argument \`$1'" >&2 exit 0 ;; esac # dh_installdeb will replace this with shell code automatically # generated by other debhelper scripts. #DEBHELPER# exit 0 apcupsd-3.14.14/platforms/debian/examples/watch.ex000066400000000000000000000004751274230402600220440ustar00rootroot00000000000000# Example watch control file for uscan # Rename this file to "watch" and then you can run the "uscan" command # to check for upstream updates and more. # Site Directory Pattern Version Script sunsite.unc.edu /pub/Linux/Incoming apcupsd-(.*)\.tar\.gz debian uupdate apcupsd-3.14.14/platforms/debian/packageinfo/000077500000000000000000000000001274230402600210235ustar00rootroot00000000000000apcupsd-3.14.14/platforms/debian/packageinfo/apcupsd.conffiles000066400000000000000000000004041274230402600243520ustar00rootroot00000000000000/etc/apcupsd/apcupsd.conf /etc/init.d/apcupsd /etc/logrotate.d/apcupsd /etc/apcupsd/hosts.conf /etc/apcupsd/multimon.conf /etc/apcupsd/apccontrol /etc/apcupsd/changeme /etc/apcupsd/commfailure /etc/apcupsd/commok /etc/apcupsd/offbattery /etc/apcupsd/onbattery apcupsd-3.14.14/platforms/debian/packageinfo/apcupsd.dirs000066400000000000000000000000551274230402600233450ustar00rootroot00000000000000sbin etc/logrotate.d usr/lib/cgi-bin/apcupsd apcupsd-3.14.14/platforms/debian/packageinfo/apcupsd.docs000066400000000000000000000004001274230402600233260ustar00rootroot00000000000000doc/README.BackUPS doc/README.BackUPS-Pro doc/README.NewerBackUPS-Pro doc/README.Share-UPS doc/README.SmartUPS-VS doc/README.apcaccess doc/README.autoconfig doc/README.cable doc/Statement.APCC doc/apcupsd-bug-1 doc/apcupsd-bug-2 doc/apcupsd.txt doc/manual apcupsd-3.14.14/platforms/debian/packageinfo/apcupsd.logrotate000066400000000000000000000002661274230402600244100ustar00rootroot00000000000000"/var/log/apcupsd.log" { rotate 7 daily compress missingok } "/var/log/apcupsd.events" { rotate 7 daily compress missingok } apcupsd-3.14.14/platforms/debian/packageinfo/changelog000066400000000000000000000040431274230402600226760ustar00rootroot00000000000000apcupsd (3.8.1.5-1) unstable; urgency=low * New upstream release. (closes: #79045, #74060, #83059) * Provide ups-monitor. (closes: #78058) * Update to standards version 3.5.2. * Update build depends. (closes: #70159) * Change section to admin. * Move events and status files to appropriate places. (closes: #63745) -- Martin Mitchell Sun, 8 Apr 2001 22:57:24 +1000 apcupsd (3.7.1-2) unstable; urgency=low * Fix init.d script problem with environment variable. -- Martin Mitchell Wed, 17 May 2000 01:20:06 +1000 apcupsd (3.7.1-1) unstable; urgency=low * New upstream release. (closes: #57131, #61777, #52206, #61636, #43447) * Update copyright information. * Update to standards version 3.1.1. * Remove implicit bash dependency. (closes: #46505) -- Martin Mitchell Tue, 25 Apr 2000 14:21:54 +1000 apcupsd (3.6.2-1) unstable; urgency=low * New upstream release. (closes: #42653) * New maintainer. * Update to standards version 3.0.1. * Remove files and substvars. (closes: #41599) -- Martin Mitchell Mon, 9 Aug 1999 01:11:48 +1000 apcupsd (3.6.1-1) unstable; urgency=low * New upstream release * Binaries now reside in /usr/sbin (upstream change) -- Leon Breedt Wed, 14 Jul 1999 14:35:57 +0200 apcupsd (3.5.8-4) unstable; urgency=low * Removed empty README.Debian (closes #38956) * Fixed cron.daily to restart quietly (closes #41056) -- Leon Breedt Fri, 9 Jul 1999 21:39:29 +0200 apcupsd (3.5.8-3) unstable; urgency=low * Various edits to /etc/apcupsd.conf * Fixed /etc/init.d/apcupsd * Added logrotate script -- Leon Breedt Mon, 7 Jun 1999 17:33:59 +0200 apcupsd (3.5.8-2) unstable; urgency=low * Added apcupsd.conf warning -- Leon Breedt Tue, 25 May 1999 21:42:53 +0200 apcupsd (3.5.8-1) unstable; urgency=low * Initial Release. -- Leon Breedt Sun, 23 May 1999 20:47:12 +0200 Local variables: mode: debian-changelog End: apcupsd-3.14.14/platforms/debian/packageinfo/conffiles000077500000000000000000000000561274230402600227220ustar00rootroot00000000000000/etc/apcupsd/apcupsd.conf /etc/init.d/apcupsd apcupsd-3.14.14/platforms/debian/packageinfo/control000077500000000000000000000011071274230402600224300ustar00rootroot00000000000000Source: apcupsd Section: admin Priority: optional Maintainer: Martin Mitchell Build-Depends: debhelper, mawk, libncurses-dev, automake Standards-Version: 3.5.2 Package: apcupsd Architecture: any Provides: ups-monitor Conflicts: ups-monitor Suggests: logrotate Depends: ${shlibs:Depends}, bsdutils Description: APC UPS Power Management Controls / monitors the status of an APC UPS under Linux. Allows your computer or server to run for a specified length of time on UPS power, and then executes a controlled shutdown in the case of an extended power failure. apcupsd-3.14.14/platforms/debian/packageinfo/copyright000066400000000000000000000013451274230402600227610ustar00rootroot00000000000000 This package was first debianized by Leon Breedt on Sun, 23 May 1999 20:47:12 +0200. Additional changes made by root March 2001 More changes made by Gordon Morehouse April 2001 This package is now maintained by Martin Mitchell . It was downloaded from http://ftp.oasi.gpa.it/pub/apcupsd/stable. An alternative download site is http://www.sibbald.com/apcupsd. Upstream Author(s): Riccardo Facchetti Andre M. Hedrick Kern Sibbald and others. Apcupsd is placed under the GNU General Public License, a copy of which may be found in /usr/share/common-licenses/GPL. apcupsd-3.14.14/platforms/debian/packageinfo/ex.doc-base.package000066400000000000000000000010071274230402600244260ustar00rootroot00000000000000Document: apcupsd Title: Debian apcupsd Manual Author: Abstract: This manual describes what apcupsd is and how it can be used to manage online manuals on Debian systems. Section: unknown Format: debiandoc-sgml Files: /usr/share/doc/apcupsd/apcupsd.sgml.gz Format: postscript Files: /usr/share/doc/apcupsd/apcupsd.ps.gz Format: text Files: /usr/share/doc/apcupsd/apcupsd.text.gz Format: HTML Index: /usr/share/doc/apcupsd/html/index.html Files: /usr/share/doc/apcupsd/html/*.html apcupsd-3.14.14/platforms/debian/packageinfo/examples000066400000000000000000000001171274230402600225630ustar00rootroot00000000000000examples/apcupsd.conf examples/apcupsd.slave.conf examples/apcupsd.master.conf apcupsd-3.14.14/platforms/debian/packageinfo/postinst000077500000000000000000000005651274230402600226420ustar00rootroot00000000000000#!/bin/sh -e update-rc.d apcupsd start 20 1 2 3 4 5 . stop 20 0 1 6 . &>/dev/null # if we have a running copy, restart, else start if [ "`pidof apcupsd`" = "" ] then /etc/init.d/apcupsd start else if [ -f /var/run/apcupsd.pid ] then /etc/init.d/apcupsd restart fi fi echo echo 'Please verify that the settings in /etc/apcupsd.conf are correct.' apcupsd-3.14.14/platforms/debian/packageinfo/postrm000077500000000000000000000003371274230402600223000ustar00rootroot00000000000000#!/bin/sh -e if [ "$1" = "purge" ] ; then update-rc.d apcupsd remove >/dev/null rm -f /etc/apcupsd/apcupsd.conf rm -f /etc/apcupsd/apcupsd.status rm -f /etc/apcupsd/apcupsd.events rm -f /etc/apcupsd fi apcupsd-3.14.14/platforms/debian/packageinfo/prerm000077500000000000000000000000641274230402600220760ustar00rootroot00000000000000#!/bin/sh set -e /etc/init.d/apcupsd stop sleep 6 apcupsd-3.14.14/platforms/debian/packageinfo/rules000077500000000000000000000046501274230402600221100ustar00rootroot00000000000000#!/usr/bin/make -f #-*- makefile -*- # Made with the aid of dh_make, by Craig Small # Sample debian/rules that uses debhelper. GNU copyright 1997 by Joey Hess. # Some lines taken from debmake, by Christoph Lameter. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 DESTDIR=`pwd`/debian/tmp build: build-stamp build-stamp: dh_testdir # Add here commands to compile the package. -autoconf -l autoconf autoconf/configure.in >configure SHUTDOWN=/sbin/shutdown CFLAGS="-O2 -g -Wall" ./configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-powerflute --enable-cgi --sysconfdir=/etc/apcupsd --with-cgi-bin=/usr/lib/cgi-bin/apcupsd --with-catgets --with-pid-dir=/var/run $(MAKE) touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp install-stamp # Add here commands to clean up after the build process. -$(MAKE) realclean dh_clean install: install-stamp install-stamp: build-stamp dh_testdir dh_testroot dh_clean -k dh_installdirs # Install the package into debian/tmp. make prefix=`pwd`/debian/tmp/usr cgibin=`pwd`/debian/tmp/usr/lib/cgi-bin/apcupsd sysconfdir=`pwd`/debian/tmp/etc/apcupsd sbindir=`pwd`/debian/tmp/sbin mandir=`pwd`/debian/tmp/usr/share/man install install -m 0644 -g root -o root debian/apcupsd.conf `pwd`/debian/tmp/etc/apcupsd install -m 0755 -g root -o root debian/apccontrol `pwd`/debian/tmp/etc/apcupsd touch install-stamp # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot dh_installdocs dh_installexamples dh_installmenu dh_installlogrotate dh_installinit dh_installinit --init-script=ups-monitor dh_installcron dh_installmanpages dh_undocumented dh_installchangelogs ChangeLog dh_link dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb source diff: @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary apcupsd-3.14.14/platforms/debian/packageinfo/undocumented000066400000000000000000000000431274230402600234350ustar00rootroot00000000000000powersc.1 apcaccess.1 powerflute.1 apcupsd-3.14.14/platforms/debian/ups-monitor.in000066400000000000000000000010251274230402600213760ustar00rootroot00000000000000#!/bin/sh # apcupsd halt script # by Martin Mitchell # modifications by Gordon Morehouse April 2001 case "$1" in poweroff | killpower) if [ -f @PWRFAILDIR@/powerfail ]; then echo "" echo -n "apcupsd: Ordering UPS to kill power... " @sysconfdir@/apccontrol killpower echo "done." echo "" echo "Please ensure the UPS has powered off before rebooting." echo "Otherwise, the UPS may cut the power during the reboot!" echo "" sleep 2d fi ;; *) ;; esac exit 0 apcupsd-3.14.14/platforms/engarde/000077500000000000000000000000001274230402600167375ustar00rootroot00000000000000apcupsd-3.14.14/platforms/engarde/Makefile000066400000000000000000000032451274230402600204030ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-engarde all-uninstall: uninstall-engarde install-engarde: $(call DISTINST,engarde) # unlink old rc script (if not doing a DESTDIR install) $(call CHKCFG,del,/etc/init.d/apcupsd) # install new rc script $(call MKDIR,/etc/init.d) $(call INSTDATA,744,apcupsd,/etc/init.d) # link new rc script (if not doing a DESTDIR install) $(call CHKCFG,add,/etc/init.d/apcupsd) # save old halt script $(call COPY,/etc/init.d/halt,/etc/init.d/halt.old) # insert apcupsd callout into halt script @echo " AWK " $(DESTDIR)/etc/init.d/halt $(V)awk -f awkhaltprog $(DESTDIR)/etc/init.d/halt.old >$(DESTDIR)/etc/init.d/halt $(V)chmod 744 $(DESTDIR)/etc/init.d/halt @echo "=================================================" @echo " " @echo "apcupsd script installation for Engarde Secure Linux complete." @echo " " @echo "You should now edit /etc/apcupsd/apcupsd.conf to correspond" @echo "to your setup then start the apcupsd daemon with:" @echo " " @echo "/etc/init.d/apcupsd start" @echo " " @echo "thereafter when you reboot, it will be stopped and started" @echo "automatically." @echo " " @echo "Please check that your halt script in:" @echo " /etc/init.d/halt" @echo "was properly updated (see installation section of manual)" @echo " " @echo "=================================================" uninstall-engarde: $(call DISTUNINST,engarde) # unlink old rc script (if not doing a DESTDIR install) -$(call CHKCFG,del,/etc/init.d/apcupsd) -$(call UNINST,/etc/init.d/apcupsd) -$(call COPY,$(DESTDIR)/etc/init.d/halt.old,/etc/init.d/halt) -$(call UNINST,/etc/init.d/halt.old) apcupsd-3.14.14/platforms/engarde/apcupsd.in000066400000000000000000000020221274230402600207220ustar00rootroot00000000000000#! /bin/sh # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # processname: apcupsd # pidfile: @PIDDIR@/apcupsd.pid # config: @sysconfdir@/apcupsd.conf APCPID=@PIDDIR@/apcupsd.pid # Source function library. . /etc/init.d/functions [ -f @sbindir@/apcupsd ] || exit 0 [ -f @sysconfdir@/apcupsd.conf ] || exit 0 # See how we were called. case "$1" in start) echo -n " APCUPSD UPS monitor " rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin daemon @sbindir@/apcupsd -f @sysconfdir@/apcupsd.conf echo touch @LOCKDIR@/apcupsd ;; stop) echo -n " APCUPSD UPS monitor " killproc apcupsd echo rm -f $APCPID rm -f @LOCKDIR@/apcupsd ;; restart) $0 stop sleep 15 $0 start ;; status) status apcupsd @sbindir@/apcaccess status ;; *) echo "Usage: apcupsd {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/engarde/apcupsd.spec.in000066400000000000000000000123311274230402600216570ustar00rootroot00000000000000 %define initdir /etc/init.d Summary: APC UPS Power Control Daemon for Linux Name: apcupsd Version: @VERSION@ Release: 1 Vendor: APC UPS Daemon Team Distribution: The apcupsd Team Packager: Kern Sibbald URL: http://www.sibbald.com/apcupsd/ Source: http://www.sibbald.com/apcupsd/%{name}-%{version}.tar.gz Group: System Environment/Daemons Copyright: GPL v2 BuildRoot: %{_tmppath}/%{name}-root %description Apcupsd can be used for controlling most APC UPSes. During a power failure, apcupsd will inform the users about the power failure and that a shutdown may occur. If power is not restored, a system shutdown will follow when the battery is exausted, a timeout (seconds) expires, or the battery runtime expires based on internal APC calculations determined by power consumption rates. If the power is restored before one of the above shutdown conditions is met, apcupsd will inform users about this fact. Some features depend on what UPS model you have (simple or smart). %prep %setup %build %configure \ --prefix=%{_prefix} \ --sbindir=/sbin \ --sysconfdir=%{_sysconfdir}/apcupsd \ --with-cgi-bin=%{_sysconfdir}/apcupsd/cgi \ --enable-cgi \ --enable-pthreads make %install mkdir -p $RPM_BUILD_ROOT%{initdir} mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/cgi make \ prefix=$RPM_BUILD_ROOT%{_prefix} \ sbindir=$RPM_BUILD_ROOT/sbin \ sysconfdir=$RPM_BUILD_ROOT%{_sysconfdir}/apcupsd \ cgibin=$RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/cgi \ mandir=$RPM_BUILD_ROOT%{_mandir} \ install-apcupsd install-cgi install -m744 distributions/redhat/apccontrol.sh \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/apccontrol install -m755 distributions/redhat/apcupsd $RPM_BUILD_ROOT%{initdir} %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc COPYING ChangeLog INSTALL TODO doc/* examples %dir /etc/apcupsd %dir /etc/apcupsd/cgi %{initdir}/apcupsd %config(noreplace) /etc/apcupsd/apccontrol %config(noreplace) /etc/apcupsd/changeme %config(noreplace) /etc/apcupsd/commfailure %config(noreplace) /etc/apcupsd/commok %config(noreplace) /etc/apcupsd/onbattery %config(noreplace) /etc/apcupsd/offbattery %config(noreplace) /etc/apcupsd/apcupsd.conf %config(noreplace) /etc/apcupsd/hosts.conf %config(noreplace) /etc/apcupsd/multimon.conf /etc/apcupsd/cgi/* /sbin/* %attr(-,root,man) %{_mandir}/*/* %pre %post # delete then add our links /sbin/chkconfig --del apcupsd /sbin/chkconfig --add apcupsd cp -f /etc/init.d/halt /etc/init.d/halt.old awk '# Stuff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert the new apcupsd code just before the following line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " /etc/apcupsd/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # Everything else is duplicated { print } ' /etc/init.d/halt.old > /etc/init.d/halt chmod 744 /etc/init.d/halt # Undo things a bit %preun if [ $1 = 0 ] ; then # stop running version (if any) # I have removed the following because it sometimes produces # an error message which may confuse someone. #/sbin/service apcupsd stop # remove startup links /sbin/chkconfig --del apcupsd # restore old halt script (hopefully) # mv -f /etc/init.d/halt.old /etc/init.d/halt cp -f /etc/init.d/halt /etc/init.d/halt.old awk '# Stuff added by apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # Everything else is duplicated { print } ' /etc/init.d/halt.old > /etc/init.d/halt chmod 744 /etc/init.d/halt fi %postun if [ "$1" -ge "1" ]; then : # /sbin/service apcupsd condrestart >/dev/null 2>&1 || : fi %changelog * Wed Sep 05 2001 kern@sibbald.com - Applied very nice patch to this spec by Giulio Orsero * Thu Sep 14 2000 kern@sibbald.com - Many thanks to Fredrik Persson and Neil Darlow for helping me write this spec file. apcupsd-3.14.14/platforms/engarde/awkhaltprog.in000066400000000000000000000026321274230402600216150ustar00rootroot00000000000000# # Awk program to insert the necessary apcupsd script in # to a halt script. # # Suff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert our code just before this line /^### Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " @sysconfdir@/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # everything else is duplicated { print } apcupsd-3.14.14/platforms/etc/000077500000000000000000000000001274230402600161055ustar00rootroot00000000000000apcupsd-3.14.14/platforms/etc/Makefile000066400000000000000000000007101274230402600175430ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-etc all-uninstall: uninstall-etc install-etc: $(call MKDIR,$(sysconfdir)) $(call INSTNEW,644,apcupsd.conf,$(sysconfdir)) $(call INSTORIG,744,changeme,$(sysconfdir)) $(call INSTORIG,744,commfailure,$(sysconfdir)) $(call INSTORIG,744,commok,$(sysconfdir)) $(call INSTORIG,744,offbattery,$(sysconfdir)) $(call INSTORIG,744,onbattery,$(sysconfdir)) uninstall-etc: apcupsd-3.14.14/platforms/etc/apcupsd.conf.in000066400000000000000000000317271274230402600210320ustar00rootroot00000000000000## apcupsd.conf v1.1 ## # # for apcupsd release @VERSION@ (@DATE@) - @DISTNAME@ # # "apcupsd" POSIX config file # # Note that the apcupsd daemon must be restarted in order for changes to # this configuration file to become active. # # # ========= General configuration parameters ============ # # UPSNAME xxx # Use this to give your UPS a name in log files and such. This # is particulary useful if you have multiple UPSes. This does not # set the EEPROM. It should be 8 characters or less. #UPSNAME # UPSCABLE # Defines the type of cable connecting the UPS to your computer. # # Possible generic choices for are: # simple, smart, ether, usb # # Or a specific cable model number may be used: # 940-0119A, 940-0127A, 940-0128A, 940-0020B, # 940-0020C, 940-0023A, 940-0024B, 940-0024C, # 940-1524C, 940-0024G, 940-0095A, 940-0095B, # 940-0095C, 940-0625A, M-04-02-2000 # UPSCABLE @UPSCABLE@ # To get apcupsd to work, in addition to defining the cable # above, you must also define a UPSTYPE, which corresponds to # the type of UPS you have (see the Description for more details). # You must also specify a DEVICE, sometimes referred to as a port. # For USB UPSes, please leave the DEVICE directive blank. For # other UPS types, you must specify an appropriate port or address. # # UPSTYPE DEVICE Description # apcsmart /dev/tty** Newer serial character device, appropriate for # SmartUPS models using a serial cable (not USB). # # usb Most new UPSes are USB. A blank DEVICE # setting enables autodetection, which is # the best choice for most installations. # # net hostname:port Network link to a master apcupsd through apcupsd's # Network Information Server. This is used if the # UPS powering your computer is connected to a # different computer for monitoring. # # snmp hostname:port:vendor:community # SNMP network link to an SNMP-enabled UPS device. # Hostname is the ip address or hostname of the UPS # on the network. Vendor can be can be "APC" or # "APC_NOTRAP". "APC_NOTRAP" will disable SNMP trap # catching; you usually want "APC". Port is usually # 161. Community is usually "private". # # netsnmp hostname:port:vendor:community # OBSOLETE # Same as SNMP above but requires use of the # net-snmp library. Unless you have a specific need # for this old driver, you should use 'snmp' instead. # # dumb /dev/tty** Old serial character device for use with # simple-signaling UPSes. # # pcnet ipaddr:username:passphrase:port # PowerChute Network Shutdown protocol which can be # used as an alternative to SNMP with the AP9617 # family of smart slot cards. ipaddr is the IP # address of the UPS management card. username and # passphrase are the credentials for which the card # has been configured. port is the port number on # which to listen for messages from the UPS, normally # 3052. If this parameter is empty or missing, the # default of 3052 will be used. # # modbus /dev/tty** Serial device for use with newest SmartUPS models # supporting the MODBUS protocol. # modbus Leave the DEVICE setting blank for MODBUS over USB # or set to the serial number of the UPS to ensure # that apcupsd binds to that particular unit # (helpful if you have more than one USB UPS). # UPSTYPE @UPSTYPE@ DEVICE @SERIALDEV@ # POLLTIME # Interval (in seconds) at which apcupsd polls the UPS for status. This # setting applies both to directly-attached UPSes (UPSTYPE apcsmart, usb, # dumb) and networked UPSes (UPSTYPE net, snmp). Lowering this setting # will improve apcupsd's responsiveness to certain events at the cost of # higher CPU utilization. The default of 60 is appropriate for most # situations. #POLLTIME 60 # LOCKFILE # Path for device lock file. This is the directory into which the lock file # will be written. The directory must already exist; apcupsd will not create # it. The actual name of the lock file is computed from DEVICE. # Not used on Win32. LOCKFILE @LOCKDIR@ # SCRIPTDIR # Directory in which apccontrol and event scripts are located. SCRIPTDIR @sysconfdir@ # PWRFAILDIR # Directory in which to write the powerfail flag file. This file # is created when apcupsd initiates a system shutdown and is # checked in the OS halt scripts to determine if a killpower # (turning off UPS output power) is required. PWRFAILDIR @PWRFAILDIR@ # NOLOGINDIR # Directory in which to write the nologin file. The existence # of this flag file tells the OS to disallow new logins. NOLOGINDIR @nologdir@ # # ======== Configuration parameters used during power failures ========== # # The ONBATTERYDELAY is the time in seconds from when a power failure # is detected until we react to it with an onbattery event. # # This means that, apccontrol will be called with the powerout argument # immediately when a power failure is detected. However, the # onbattery argument is passed to apccontrol only after the # ONBATTERYDELAY time. If you don't want to be annoyed by short # powerfailures, make sure that apccontrol powerout does nothing # i.e. comment out the wall. ONBATTERYDELAY 6 # # Note: BATTERYLEVEL, MINUTES, and TIMEOUT work in conjunction, so # the first that occurs will cause the initation of a shutdown. # # If during a power failure, the remaining battery percentage # (as reported by the UPS) is below or equal to BATTERYLEVEL, # apcupsd will initiate a system shutdown. BATTERYLEVEL 5 # If during a power failure, the remaining runtime in minutes # (as calculated internally by the UPS) is below or equal to MINUTES, # apcupsd, will initiate a system shutdown. MINUTES 3 # If during a power failure, the UPS has run on batteries for TIMEOUT # many seconds or longer, apcupsd will initiate a system shutdown. # A value of 0 disables this timer. # # Note, if you have a Smart UPS, you will most likely want to disable # this timer by setting it to zero. That way, you UPS will continue # on batteries until either the % charge remaing drops to or below BATTERYLEVEL, # or the remaining battery runtime drops to or below MINUTES. Of course, # if you are testing, setting this to 60 causes a quick system shutdown # if you pull the power plug. # If you have an older dumb UPS, you will want to set this to less than # the time you know you can run on batteries. TIMEOUT 0 # Time in seconds between annoying users to signoff prior to # system shutdown. 0 disables. ANNOY 300 # Initial delay after power failure before warning users to get # off the system. ANNOYDELAY 60 # The condition which determines when users are prevented from # logging in during a power failure. # NOLOGON [ disable | timeout | percent | minutes | always ] NOLOGON disable # If KILLDELAY is non-zero, apcupsd will continue running after a # shutdown has been requested, and after the specified time in # seconds attempt to kill the power. This is for use on systems # where apcupsd cannot regain control after a shutdown. # KILLDELAY 0 disables KILLDELAY 0 # # ==== Configuration statements for Network Information Server ==== # # NETSERVER [ on | off ] on enables, off disables the network # information server. If netstatus is on, a network information # server process will be started for serving the STATUS and # EVENT data over the network (used by CGI programs). NETSERVER on # NISIP # IP address on which NIS server will listen for incoming connections. # This is useful if your server is multi-homed (has more than one # network interface and IP address). Default value is 0.0.0.0 which # means any incoming request will be serviced. Alternatively, you can # configure this setting to any specific IP address of your server and # NIS will listen for connections only on that interface. Use the # loopback address (127.0.0.1) to accept connections only from the # local machine. NISIP @NISIP@ # NISPORT default is 3551 as registered with the IANA # port to use for sending STATUS and EVENTS data over the network. # It is not used unless NETSERVER is on. If you change this port, # you will need to change the corresponding value in the cgi directory # and rebuild the cgi programs. NISPORT @NISPORT@ # If you want the last few EVENTS to be available over the network # by the network information server, you must define an EVENTSFILE. EVENTSFILE @LOGDIR@/apcupsd.events # EVENTSFILEMAX # By default, the size of the EVENTSFILE will be not be allowed to exceed # 10 kilobytes. When the file grows beyond this limit, older EVENTS will # be removed from the beginning of the file (first in first out). The # parameter EVENTSFILEMAX can be set to a different kilobyte value, or set # to zero to allow the EVENTSFILE to grow without limit. EVENTSFILEMAX 10 # # ========== Configuration statements used if sharing ============= # a UPS with more than one machine # # Remaining items are for ShareUPS (APC expansion card) ONLY # # UPSCLASS [ standalone | shareslave | sharemaster ] # Normally standalone unless you share an UPS using an APC ShareUPS # card. UPSCLASS standalone # UPSMODE [ disable | share ] # Normally disable unless you share an UPS using an APC ShareUPS card. UPSMODE disable # # ===== Configuration statements to control apcupsd system logging ======== # # Time interval in seconds between writing the STATUS file; 0 disables STATTIME 0 # Location of STATUS file (written to only if STATTIME is non-zero) STATFILE @LOGDIR@/apcupsd.status # LOGSTATS [ on | off ] on enables, off disables # Note! This generates a lot of output, so if # you turn this on, be sure that the # file defined in syslog.conf for LOG_NOTICE is a named pipe. # You probably do not want this on. LOGSTATS off # Time interval in seconds between writing the DATA records to # the log file. 0 disables. DATATIME 0 # FACILITY defines the logging facility (class) for logging to syslog. # If not specified, it defaults to "daemon". This is useful # if you want to separate the data logged by apcupsd from other # programs. #FACILITY DAEMON # # ========== Configuration statements used in updating the UPS EPROM ========= # # # These statements are used only by apctest when choosing "Set EEPROM with conf # file values" from the EEPROM menu. THESE STATEMENTS HAVE NO EFFECT ON APCUPSD. # # UPS name, max 8 characters #UPSNAME UPS_IDEN # Battery date - 8 characters #BATTDATE mm/dd/yy # Sensitivity to line voltage quality (H cause faster transfer to batteries) # SENSITIVITY H M L (default = H) #SENSITIVITY H # UPS delay after power return (seconds) # WAKEUP 000 060 180 300 (default = 0) #WAKEUP 60 # UPS Grace period after request to power off (seconds) # SLEEP 020 180 300 600 (default = 20) #SLEEP 180 # Low line voltage causing transfer to batteries # The permitted values depend on your model as defined by last letter # of FIRMWARE or APCMODEL. Some representative values are: # D 106 103 100 097 # M 177 172 168 182 # A 092 090 088 086 # I 208 204 200 196 (default = 0 => not valid) #LOTRANSFER 208 # High line voltage causing transfer to batteries # The permitted values depend on your model as defined by last letter # of FIRMWARE or APCMODEL. Some representative values are: # D 127 130 133 136 # M 229 234 239 224 # A 108 110 112 114 # I 253 257 261 265 (default = 0 => not valid) #HITRANSFER 253 # Battery charge needed to restore power # RETURNCHARGE 00 15 50 90 (default = 15) #RETURNCHARGE 15 # Alarm delay # 0 = zero delay after pwr fail, T = power fail + 30 sec, L = low battery, N = never # BEEPSTATE 0 T L N (default = 0) #BEEPSTATE T # Low battery warning delay in minutes # LOWBATT 02 05 07 10 (default = 02) #LOWBATT 2 # UPS Output voltage when running on batteries # The permitted values depend on your model as defined by last letter # of FIRMWARE or APCMODEL. Some representative values are: # D 115 # M 208 # A 100 # I 230 240 220 225 (default = 0 => not valid) #OUTPUTVOLTS 230 # Self test interval in hours 336=2 weeks, 168=1 week, ON=at power on # SELFTEST 336 168 ON OFF (default = 336) #SELFTEST 336 apcupsd-3.14.14/platforms/etc/changeme.in000077500000000000000000000006541274230402600202140ustar00rootroot00000000000000#!/bin/sh # # This shell script if placed in /etc/apcupsd # will be called by /etc/apcupsd/apccontrol when apcupsd # detects that the battery should be replaced. # We send an email message to root to notify him. # HOSTNAME=`hostname` MSG="$HOSTNAME UPS $1 battery needs changing NOW." # ( echo "Subject: $MSG" echo " " echo "$MSG" echo " " @sbindir@/apcaccess status ) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN exit 0 apcupsd-3.14.14/platforms/etc/commfailure.in000077500000000000000000000007071274230402600207470ustar00rootroot00000000000000#!/bin/sh # # This shell script if placed in /etc/apcupsd # will be called by /etc/apcupsd/apccontrol when apcupsd # loses contact with the UPS (i.e. the serial connection is not responding). # We send an email message to root to notify him. # HOSTNAME=`hostname` MSG="$HOSTNAME Communications with UPS $1 lost" # ( echo "Subject: $MSG" echo " " echo "$MSG" echo " " @sbindir@/apcaccess status ) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN exit 0 apcupsd-3.14.14/platforms/etc/commok.in000077500000000000000000000007101274230402600177230ustar00rootroot00000000000000#!/bin/sh # # This shell script if placed in /etc/apcupsd # will be called by /etc/apcupsd/apccontrol when apcupsd # restores contact with the UPS (i.e. the serial connection is restored). # We send an email message to root to notify him. # HOSTNAME=`hostname` MSG="$HOSTNAME Communications with UPS $1 restored" # ( echo "Subject: $MSG" echo " " echo "$MSG" echo " " @sbindir@/apcaccess status ) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN exit 0 apcupsd-3.14.14/platforms/etc/hosts.conf000066400000000000000000000012261274230402600201150ustar00rootroot00000000000000# Network UPS Tools - hosts.conf # # This file does double duty - it lists the systems that multimon will # monitor, and also specifies the systems that upsstats is allowed to # watch. It keeps people from feeding random addresses to upsstats, # among other things. upsimage also uses this file to know who it # may speak to. upsfstats too. # # Usage: list systems running upsd that you want to monitor # # MONITOR
"" # # Please note, MONITOR must start in column 1 (no spaces permitted) # # Example: # MONITOR 10.64.1.1 "Finance department" # MONITOR 10.78.1.1 "Sierra High School data room #1" # MONITOR 127.0.0.1 "Local Host" apcupsd-3.14.14/platforms/etc/multimon.conf000066400000000000000000000044501274230402600206230ustar00rootroot00000000000000# Sample multimon configuration file # # This file is not required. Without it, multimon will use the default # field layout. # # Temperature selection # # Pick "TEMPC" for Celsius or "TEMPF" for Fahrenheit. This will override # the --enable-celsius setting from the compile. UPSTEMP (below) will # use this setting by default. TEMPC # Format: # FIELD "" "" # # is either a word from the UPS protocol like battchg (see the # table in src/cgi/upsfetch.c) or a special word in uppercase. # # Special words are: # MODEL - Show the model name for this system in cyan # # STATUS - Parse the status for this system using the appropriate color # # UPSTEMP and AMBTEMP use the default scale. This is set to C if you use # --enable-celsius at compile time *or* if you use "TEMPC" above. # # UPSTEMP - Show the UPS temperature in the default scale (suffix ignored) # AMBTEMP - Show the ambient temperature in the default scale (suffix ignored) # # UPSTEMPC - Show the UPS temperature in degrees C (suffix ignored) # UPSTEMPF - Show the UPS temperature in degrees F (suffix ignored) # AMBTEMPC - Show the ambient temperature in degrees C (suffix ignored) # AMBTEMPF - Show the ambient temperature in degrees F (suffix ignored) # # They're called "special" since they actually understand the content # being printed and do other things based on what's in there. # # is what you'd like this column to be called on the page. # Remember that this is HTML, so you can actually embed markup in here. # This means you can even include images here. You can include quotes # (and backslashes!) in the string by escaping them with a backslash (\). # # is typically something like % or VAC. It's useful if # you want to convey the units that apply to a value. # # Example config FIELD SYSTEM "System" "" FIELD MODEL "Model" "" FIELD STATUS "Status" "" FIELD battpct "Battery Chg" "%" FIELD utility "Utility" "VAC" FIELD loadpct "UPS Load" "%" FIELD UPSTEMP "UPS Temp" "" FIELD runtime "Batt. Run Time" "min." FIELD DATA "Data" "All data" # These are only useful if you have a Smart-UPS model with the Measure-UPS II # measurement card. No other models presently support these features. # # FIELD AMBTEMP "Ambient Temp" "" # FIELD HUMIDITY "Ambient Humidity" "%" apcupsd-3.14.14/platforms/etc/offbattery.in000077500000000000000000000006531274230402600206110ustar00rootroot00000000000000#!/bin/sh # # This shell script if placed in /etc/apcupsd # will be called by /etc/apcupsd/apccontrol when the # UPS goes back on to the mains after a power failure. # We send an email message to root to notify him. # HOSTNAME=`hostname` MSG="$HOSTNAME UPS $1 Power has returned" # ( echo "Subject: $MSG" echo " " echo "$MSG" echo " " @sbindir@/apcaccess status ) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN exit 0 apcupsd-3.14.14/platforms/etc/onbattery.in000077500000000000000000000006101274230402600204440ustar00rootroot00000000000000#!/bin/sh # # This shell script if placed in /etc/apcupsd # will be called by /etc/apcupsd/apccontrol when the UPS # goes on batteries. # We send an email message to root to notify him. # HOSTNAME=`hostname` MSG="$HOSTNAME UPS $1 Power Failure !!!" # ( echo "Subject: $MSG" echo " " echo "$MSG" echo " " @sbindir@/apcaccess status ) | $APCUPSD_MAIL -s "$MSG" $SYSADMIN exit 0 apcupsd-3.14.14/platforms/freebsd/000077500000000000000000000000001274230402600167445ustar00rootroot00000000000000apcupsd-3.14.14/platforms/freebsd/Makefile000066400000000000000000000051051274230402600204050ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-freebsd all-uninstall: uninstall-freebsd install-freebsd: $(call DISTINST,FreeBSD) $(call MKDIR,/etc) $(call INSTPROG,744,apcupsd,/etc/rc.apcupsd) $(VV)-today="`date +%Y%m%d%H%M`"; \ grep -q '# TAG_APCUPSD' /etc/rc.shutdown; \ if [ $$? -ne 0 ]; then \ echo " PATCH $(DESTDIR)/etc/rc.shutdown"; \ rm -f $(DESTDIR)/etc/rc.shutdown.$$today; \ cp -p /etc/rc.shutdown $(DESTDIR)/etc/rc.shutdown.$$today; \ $(SED) -e '/exit 0/d'< $(DESTDIR)/etc/rc.shutdown.$$today > $(DESTDIR)/etc/rc.shutdown; \ ( echo "# Do not remove the 'TAG_APCUPSD' text, below"; \ echo "if [ -f $(PWRFAILDIR)/powerfail ]; then # TAG_APCUPSD";\ echo " powerdown=YES # TAG_APCUPSD"; \ echo " echo '' # TAG_APCUPSD"; \ echo " echo 'Please ensure that the UPS has powered off before' # TAG_APCUPSD"; \ echo " echo 'rebooting. Otherwise, the UPS may cut the power' # TAG_APCUPSD"; \ echo " echo 'during the reboot.' # TAG_APCUPSD"; \ echo " echo '' # TAG_APCUPSD"; \ echo "fi # TAG_APCUPSD"; \ echo "exit 0"; \ ) >> $(DESTDIR)/etc/rc.shutdown; \ chmod 744 $(DESTDIR)/etc/rc.shutdown; \ fi; \ grep -q /etc/rc.apcupsd /etc/rc.local; \ if [ $$? -ne 0 ]; then \ echo " PATCH $(DESTDIR)/etc/rc.local"; \ rm -f $(DESTDIR)/etc/rc.local.$$today; \ cp -p /etc/rc.local $(DESTDIR)/etc/rc.local.$$today; \ ( echo "# Start the UPS daemon. Do not remove the 'TAG_APCUPSD' text"; \ echo "# if [ -x /etc/rc.apcupsd ]; then # TAG_APCUPSD"; \ echo "# /etc/rc.apcupsd start # TAG_APCUPSD"; \ echo "# fi # TAG_APCUPSD"; \ ) >> $(DESTDIR)/etc/rc.local; \ echo ""; \ ( echo "While /etc/rc.local has been patched to run apcupsd,";\ echo "the commands are currently commented out. You should"; \ echo "examine the $(sysconfdir)/apcupsd.conf file to ensure"; \ echo "that it is suitable for your site. Then run"; \ echo "/etc/rc.apcupsd manually to ensure sane operation."; \ echo "Once you are satisfied, uncomment the appropriate"; \ echo "lines in /etc/rc.local" ) | /usr/bin/fmt; \ fi uninstall-freebsd: $(call DISTUNINST,FreeBSD) -$(call UNINST,/etc/rc.apcupsd) $(VV)-today="`date +%Y%m%d%H%M`"; \ for f in $(DESTDIR)/etc/rc.local $(DESTDIR)/etc/rc.shutdown; do \ grep -q '# TAG_APCUPSD' $$f; \ if [ $$? -eq 0 ]; then \ echo " PATCH $$f"; \ rm -f $$f.$$today; \ cp -p $$f $$f.$$today; \ $(SED) -e '/TAG_APCUPSD/d;' \ < $$f.$$today > $$f; \ chmod 644 $$f; \ fi; \ done apcupsd-3.14.14/platforms/freebsd/apccontrol.in000066400000000000000000000062121274230402600214410ustar00rootroot00000000000000#!@SCRIPTSHELL@ # # Copyright (C) 1999-2002 Riccardo Facchetti # # for apcupsd release @VERSION@ (@DATE@) - @DISTNAME@ # # @configure_input@ # # # These variables are needed for set up the autoconf other variables. # prefix=@prefix@ exec_prefix=@exec_prefix@ APCPID=@PIDDIR@/apcupsd.pid APCUPSD=@sbindir@/apcupsd SHUTDOWN=@SHUTDOWN@ SCRIPTSHELL=@SCRIPTSHELL@ SCRIPTDIR=@sysconfdir@ export SYSADMIN=root export APCUPSD_MAIL="@APCUPSD_MAIL@" if [ -f $SCRIPTDIR/config ]; then . $SCRIPTDIR/config ; fi # # This piece is to substitute the default behaviour with your own script, # perl, or C program. # You can customize every single command creating an executable file (may be a # script or a compiled program) and calling it the same as the $1 parameter # passed by apcupsd to this script. # # After executing your script, apccontrol continues with the default action. # If you do not want apccontrol to continue, exit your script with exit # code 99. E.g. "exit 99". # # WARNING: the apccontrol file will be overwritten every time you update your # apcupsd, doing `make install'. Your own customized scripts will _not_ be # overwritten. If you wish to make changes to this file (discouraged), you # should change apccontrol.sh.in and then rerun the configure process. # if [ -f ${SCRIPTDIR}/${1} -a -x ${SCRIPTDIR}/${1} ] then ${SCRIPTDIR}/${1} ${2} ${3} ${4} # exit code 99 means he does not want us to do default action if [ $? = 99 ] ; then exit 0 fi fi case "$1" in killpower) printf "UPS now committed to shut down" | wall # echo "Apccontrol doing: ${APCUPSD} --killpower" # sleep 10 # ${APCUPSD} --killpower ;; commfailure) printf "Communications with UPS lost." | wall ;; commok) printf "Communciations with UPS restored." | wall ;; powerout) ;; onbattery) printf "Power failure. Running on UPS batteries." | wall ;; offbattery) printf "Power has returned..." | wall ;; mainsback) if [ -f @PWRFAILDIR@/powerfail ] ; then printf "Continuing with shutdown." | wall fi ;; failing) printf "UPS battery power exhausted. Doing shutdown.\n" | wall ;; timeout) printf "UPS battery runtime limit exceeded. Doing shutdown.\n" | wall ;; loadlimit) printf "UPS battery discharge limit reached. Doing shutdown.\n" | wall ;; runlimit) printf "UPS battery runtime percent reached. Doing shutdown.\n" \ | wall ;; doreboot) printf "Beginning Reboot Sequence" | wall ${SHUTDOWN} -r now "apcupsd initiated reboot" ;; doshutdown) printf "Beginning Shutdown Sequence" | wall ${SHUTDOWN} -h now "apcupsd initiated shutdown" ;; annoyme) printf "Power problems please logoff." | wall ;; emergency) printf "Emergency Shutdown. Possible UPS battery failure." \ | wall ;; changeme) printf "Emergency! UPS batteries have failed\nChange them NOW" \ | wall ;; remotedown) printf "Remote Shutdown.\nBeginning Shutdown Sequence." | wall ;; startselftest) ;; endselftest) ;; battdetach) ;; battattach) ;; *) echo "Usage: ${0##*/} command" echo " warning: this script is intended to be launched by" echo " apcupsd and should never be launched by users." exit 1 ;; esac apcupsd-3.14.14/platforms/freebsd/apcupsd.in000066400000000000000000000017101274230402600207320ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid APCLOCK=@LOCKDIR@/apcupsd.lock DISTVER="@DISTVER@" return=" Done." case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting apcupsd power management" @sbindir@/apcupsd --kill-on-powerfail || return=" Failed." touch $APCLOCK echo -e "$return" ;; stop) echo -n "Stopping apcupsd power management" if [ -f ${APCPID} ]; then THEPID=`cat ${APCPID}` kill ${THEPID} || return=" Failed." rm -f ${APCPID} else return=" Failed." fi rm -f $APCLOCK echo -e "$return" ;; restart) $0 stop $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/gentoo/000077500000000000000000000000001274230402600166255ustar00rootroot00000000000000apcupsd-3.14.14/platforms/gentoo/Makefile000066400000000000000000000006251274230402600202700ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-gentoo all-uninstall: uninstall-gentoo install-gentoo: $(call DISTINST,gentoo) $(call MKDIR,/etc/init.d) $(call INSTPROG,744,apcupsd,/etc/init.d/apcupsd) $(call INSTPROG,744,halt,/etc/init.d/halt) uninstall-gentoo: $(call DISTUNINST,gentoo) -$(call UNINST,/etc/init.d/apcupsd) # $(call UNINST,/etc/init.d/halt) apcupsd-3.14.14/platforms/gentoo/README000066400000000000000000000003041274230402600175020ustar00rootroot00000000000000Thanks to Zach Welch we've got Gentoo Linux platform support. Please, if you plan to build the package with ebuild, edit it to reflect the current gentoo and apcupsd status (no need for patches). apcupsd-3.14.14/platforms/gentoo/apcupsd.in000066400000000000000000000011001274230402600206040ustar00rootroot00000000000000#!/sbin/runscript # Copyright 1999-2002 Gentoo Technologies, Inc. # Distributed under the terms of the GNU General Public License, v2 or later # $Header: /home/adk0212/src/cvs2svn/cvsrepo/apcupsd/platforms/gentoo/apcupsd.in,v 1.1 2002-09-14 12:03:18 rfacchetti Exp $ APCPID=@PIDDIR@/apcupsd.pid APCUPSD=@sbindir@/apcupsd start() { rm -f /etc/apcupsd/powerfail ebegin "Starting APC UPS daemon" start-stop-daemon --start --quiet --exec $APCUPSD -- 1>&2 eend $? } stop() { ebegin "Stopping APC UPS daemon" start-stop-daemon --stop --quiet --pidfile $APCPID eend $? } apcupsd-3.14.14/platforms/gentoo/ebuild000066400000000000000000000065111274230402600200170ustar00rootroot00000000000000# Copyright 1999-2002 Gentoo Technologies, Inc. # Distributed under the terms of the GNU General Public License, v2 or later # $Header: /home/adk0212/src/cvs2svn/cvsrepo/apcupsd/platforms/gentoo/ebuild,v 1.3 2004-04-01 20:32:22 wrking Exp $ S=${WORKDIR}/${P} DESCRIPTION="APC UPS daemon with integrated tcp/ip remote shutdown (*ALPHA*)" SRC_URI="http://www.sibbald.com/apcupsd/development/${P}.tar.gz \ http://www.sibbald.com/apcupsd/contrib/gd1.2.tar.gz" HOMEPAGE="http://www.sibbald.com/apcupsd/" KEYWORDS="x86" SLOT="0" LICENSE="GPL-2" DEPEND="virtual/glibc net-mail/ssmtp sys-libs/ncurses" XPIDDIR=/var/run XLOGDIR=/var/log XLOCKDIR=/var/lock XSYSCONFDIR=/etc/apcupsd XPWRFAILDIR=${XSYSCONFDIR} src_unpack() { unpack ${A} cp -a ${WORKDIR}/gd1.2 ${S}/src/ cp -a ${S} ${S}-orig ln -s /usr/portage/sys-apps/apcupsd/files ${WORKDIR}/files cd ${S} patch -p1 < ${FILESDIR}/${P}-gentoo.patch } src_compile() { # patch touches configure.in, so we must regenerate configure WANT_AUTOCONF_2_5=1 autoconf/autoregen.sh APCUPSD_MAIL=/usr/sbin/ssmtp ./configure \ --prefix=/usr \ --sbindir=/usr/sbin \ --sysconfdir=${XSYSCONFDIR} \ --with-pwrfail-dir=${XPWRFAILDIR} \ --with-lock-dir=${XLOCKDIR} \ --with-pid-dir=${XPIDDIR} \ --with-log-dir=${XLOGDIR} \ --with-distname=gentoo \ --with-upstype=usb \ --with-upscable=usb \ --with-serial-dev=/dev/usb/hid/hiddev[0-9] \ --with-net-port=6666 \ --with-nis-port=7000 \ --enable-usb \ --enable-net \ --enable-powerflute \ --enable-pthreads \ --with-cgi-bin=/home/httpd/apcupsd \ --enable-cgi \ || die make || die } src_install () { GEN2DD=${D} make DESTDIR=${GEN2DD%*/} install # fixup smtp scripts for ssmtp compatibility echo "Editing mail scripts for ssmtp compatibility..." cd ${D}etc/apcupsd/ patch -p1 < ${FILESDIR}/${P}-ssmtp.patch echo "Installing full documentation into /usr/share/doc/${P}..." cd ${S}/doc dodoc README.* docinto developers_manual dodoc developers_manual/* docinto logo dodoc logo/* docinto manual dodoc manual/* docinto old_documents dodoc old_documents/* docinto vim dodoc vim/* } stop_apcupsd() { echo "Stopping old apcupsd daemon..." /etc/init.d/apcupsd stop } XAPCPID=${XPIDDIR}/apcupsd.pid pkg_preinst() { if test -f $XAPCPID -a -d /proc/`cat $XAPCPID`; then stop_apcupsd touch /etc/apcupsd/.wasrunning elif ! test -f /etc/apcupsd/apcupsd.conf; then mkdir -p /etc/apcupsd touch /etc/apcupsd/.newinstall fi } pkg_postinst() { if test -f /etc/apcupsd/.wasrunning; then echo "Restarting new apcupsd daemon..." /etc/init.d/apcupsd start rm -f /etc/apcupsd/.wasrunning elif test -f /etc/apcupsd/.newinstall; then echo "Adding to standard runlevels..." rc-update add apcupsd boot default nonetwork single rm -f /etc/apcupsd/.newinstall echo "Edit ${SYSCONFDIR}/apcupsd.conf for your UPS." fi } pkg_prerm() { if test -f $XAPCPID -a -d /proc/`cat $XAPCPID`; then stop_apcupsd fi } pkg_postrm() { # if all packages instances are unmerged, daemon will go missing if ! test -x /usr/sbin/apcupsd -o -x /sbin/apcupsd; then # so then clean up the config files to avoid a messy /etc echo "Removing apcupsd from all runlevels..." rc-update del apcupsd echo "Removing apcupsd configuration files..." rm -rf /etc/apcupsd rm -f /etc/init.d/apcupsd rm -f /etc/init.d/halt # we installed it, but still... fi } apcupsd-3.14.14/platforms/gentoo/halt.in000066400000000000000000000010071274230402600201030ustar00rootroot00000000000000#!/bin/sh # # halt Execute the halt command. # # Version: @(#)halt 2.75 19-May-1998 miquels@cistron.nl # modified by Holger Brueckner # for apcupsd 28-June-2001 PATH=/sbin:/bin:/usr/sbin:/usr/bin APCCONTROL="@sysconfdir@/apccontrol killpower" # See if we need to cut the power. # See if this is a powerfail situation. if [ -f @PWRFAILDIR@/powerfail ]; then echo "APCUPSD to the Rescue!" echo $APCCONTROL echo sleep 120 exit 1 fi /sbin/halt -nfip apcupsd-3.14.14/platforms/hpux/000077500000000000000000000000001274230402600163165ustar00rootroot00000000000000apcupsd-3.14.14/platforms/hpux/Makefile000066400000000000000000000012001274230402600177470ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-unknown all-uninstall: uninstall-unknown install-unknown: $(call DISTINST,Unknown) @echo "You have to manually install apcupsd boot script and" @echo "halt script for clean emergency shutdown." @echo "Please contribute your distribution install to apcupsd team." @echo "I'm sorry: you are on your own." uninstall-unknown: $(call DISTUNINST,Unknown) @echo "You have to manually uninstall apcupsd boot script and" @echo "halt script." @echo "Please contribute your distribution install to apcupsd team." @echo "I'm sorry: you are on your own." apcupsd-3.14.14/platforms/hpux/apcupsd.in000066400000000000000000000020141274230402600203020ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # POWERPID=@PIDDIR@/power.pid APCPID=@PIDDIR@/apcupsd.pid DISTVER="@DISTVER@" return=" Done." case "$1" in start) rm -f ${POWERPID} rm -f @PWRFAILDIR@/powerfail rm -f /etc/powerstatus rm -f @nologdir@/nologin echo -n "Starting apcupsd power management" @sbindir@/apcupsd || return=" Failed." touch @LOCKDIR@/subsys/apcupsd echo -e "$return" ;; stop) echo -n "Stopping apcupsd power management" if [ -f ${APCPID} ]; then THEPID=`cat ${APCPID}` kill ${THEPID} || return=" Failed." rm -f ${APCPID} else return=" Failed." fi rm -f @LOCKDIR@/subsys/apcupsd echo -e "$return" ;; restart) $0 stop sleep 10 $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/hpux/halt.in000077500000000000000000000026021274230402600176010ustar00rootroot00000000000000#! /bin/sh # Copyright (c) 1996 S.u.S.E. GmbH Fuerth, Germany. All rights reserved. # # Author: Florian La Roche , 1996 # Werner Fink , 1996 # # Updated for "apcupsd" # Andre M. Hedrick , 1997 # # /sbin/init.d/halt (and symlinked to reboot) # . /etc/rc.config case "$0" in *halt) message="The system is halted." command="halt" ;; *reboot) message="Please stand by while rebooting the system..." command="reboot" ;; *) echo "$0: call me as \"halt\" or \"reboot\" please!" exit 1 ;; esac # Write to wtmp file before unmounting /var $command -w echo "Sending all processes the TERM signal..." killall5 -15 if [ "$1" = "fast" ]; then sleep 1 else sleep 5 fi echo "Sending all processes the KILL signal..." killall5 -9 echo "Turning off swap." sync ; sync swapoff -a echo "Unmounting file systems" umount -av # maybe we use Multiple devices if test -f /etc/mdtab -a -x /sbin/mdadd ; then echo -n "Disable Multiple Devices" /sbin/mdstop -a echo "." fi # See if this is a powerfail situation. if [ -f @PWRFAILDIR@/powerfail ]; then echo echo "Apcupsd will now power off the UPS!" echo @sysconfdir@/apccontrol killpower echo fi # on umsdos fs this would lead to an error message. so direct errors to # /dev/null mount -no remount,ro / 2> /dev/null sync echo $message exec $command -d -f apcupsd-3.14.14/platforms/mandrake/000077500000000000000000000000001274230402600171145ustar00rootroot00000000000000apcupsd-3.14.14/platforms/mandrake/Makefile000066400000000000000000000023621274230402600205570ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-mandrake all-uninstall: uninstall-mandrake install-mandrake: $(call DISTINST,Mandrake) # unlink old rc script (if not doing a DESTDIR install) $(call CHKCFG,del,/etc/rc.d/init.d/apcupsd) # install new rc script $(call MKDIR,/etc/rc.d/init.d) $(call INSTDATA,744,apcupsd,/etc/rc.d/init.d) # link new rc script (if not doing a DESTDIR install) $(call CHKCFG,add,/etc/rc.d/init.d/apcupsd) # mandrake halt script already handles apcupsd so no patching necessary @echo "=================================================" @echo " " @echo "apcupsd script installation for Mandrake $(DISTVER) complete." @echo " " @echo "You should now edit /etc/apcupsd/apcupsd.conf to correspond" @echo "to your setup then start the apcupsd daemon with:" @echo " " @echo "/etc/rc.d/init.d/apcupsd start" @echo " " @echo "thereafter when you reboot, it will be stopped and started" @echo "automatically." @echo " " @echo "=================================================" uninstall-mandrake: $(call DISTUNINST,Mandrake) # unlink old rc script (if not doing a DESTDIR install) -$(call CHKCFG,del,/etc/rc.d/init.d/apcupsd) -$(call UNINST,/etc/rc.d/init.d/apcupsd) apcupsd-3.14.14/platforms/mandrake/apcupsd.in000066400000000000000000000036121274230402600211050ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 60 99 # description: apcupsd monitors power and takes action if necessary # ### BEGIN INIT INFO # Provides: apcupsd # Required-Start: $network $syslog # Required-Stop: $network $syslog # Default-Start: 2 3 5 # Default-Stop: # Description: Start the apcupsd daemon ### END INIT INFO APCPID=@PIDDIR@/apcupsd.pid # Source function libarary . /etc/rc.d/init.d/functions if [ ! -x @sbindir@/apcupsd -o ! -r @sysconfdir@/apcupsd.conf ]; then exit 0 fi case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin # check for stale lockfiles LOCKDIR=`grep "^LOCKFILE" @sysconfdir@/apcupsd.conf | awk '{ print $2}'` DEVICE=`grep "^DEVICE" @sysconfdir@/apcupsd.conf | awk '{ print $2 }' | sed -e 's@/dev/@@g'` if [ -z "${DEVICE}" ]; then DEVICE=usb fi LOCKFILE="${LOCKDIR}/LCK..${DEVICE}" if [ -f $LOCKFILE ]; then PID=`cat $LOCKFILE | awk '{ printf("%d",$1) }'` else PID="" fi PIDREAL=`ps -e | awk '{print $1}' | grep "${PID}"` if [ ! -z "$PID" -a ! "$PID" = "$PIDREAL" ]; then echo "Stale lockfile, removing $LOCKFILE" if [ -f $LOCKFILE ]; then rm -f $LOCKFILE fi fi echo -n "Starting UPS monitoring:" @sbindir@/apcupsd -f @sysconfdir@/apcupsd.conf && success || failure echo touch @LOCKDIR@/subsys/apcupsd ;; stop) echo -n "Shutting down UPS monitoring:" killproc apcupsd echo rm -f $APCPID rm -f @LOCKDIR@/subsys/apcupsd ;; restart|reload) $0 stop sleep 15 $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|reload|status}" exit 1 ;; esac exit 0 apcupsd-3.14.14/platforms/mandrake/apcupsd.spec.in000066400000000000000000000432551274230402600220450ustar00rootroot00000000000000# Platform configuration # # Select the platform by setting the define below either by command # line arguments, # e.g. rpmbuild -ba --define "build_suse 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define suse 1 # # If you want the gapcmon package, use: # e.g. rpmbuild -ba --define "build_gapcmon 1" --define "build_suse 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define gapcmon 1 # # If you want the (obsolete) NET-SNMP driver, use: # e.g. rpmbuild -ba --define "build_snmp 1" --define "build_suse 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define snmp 1 # The modern SNMP driver is always enabled since it has no dependencies. # # Note, to build, you need: # Release_Notes-%{version}-%{release}.tar.gz in your # rpm SOURCES directory, and the tar file must contain # Release_Notes-%{version}-%{release}.txt # # basic defines for every build %define _version @VERSION@ %define _release 1 #-------------------------------------------------------------------------- # it should not be necessary to change anything below here for a release # except for patch macros in the setup section if used #-------------------------------------------------------------------------- %define pwrfaildir @PWRFAILDIR@ %define halpolicydir /usr/share/hal/fdi/policy/20thirdparty # third party packagers %define _packager D. Scott Barninger %{?contrib_packager:%define _packager %{contrib_packager}} %define rh7 0 %{?build_rh7:%define rh7 1} %define rh8 0 %{?build_rh8:%define rh8 1} %define rh9 0 %{?build_rh9:%define rh9 1} # all FC releases to date %define fedora_core 0 %{?build_fedora_core:%define fedora_core 1} # RedHat Enterprise and all clones %define rhel3 0 %{?build_rhel3:%define rhel3 1} %define rhel4 0 %{?build_rhel4:%define rhel4 1} %define rhel5 0 %{?build_rhel5:%define rhel5 1} # SuSE 9.x and 10.x %define suse 0 %{?build_suse:%define suse 1} # Mandrake and Mandriva %define mdk 0 %{?build_mdk:%define mdk 1} %if ! %{suse} %define suse_version 0 %endif %if %{suse} %define initdir /etc/rc.d %else %define initdir /etc/rc.d/init.d %endif # set destination directories for multimon %define cgidir /var/www/cgi-bin %if %{suse} %define cgidir /srv/www/cgi-bin %endif # set ownership of files %define binowner root %define bingroup root %define dataowner apache %define datagroup apache %if %{suse} %define dataowner wwwrun %define datagroup www %endif # should we build gapcmon, requires gtk2 >= 2.4 %define gapcmon 0 %{?build_gapcmon:%define gapcmon 1} # should we build net-snmp driver %define snmp 0 %{?build_snmp:%define snmp 1} Summary: APC UPS Power Control Daemon for Linux Name: apcupsd Version: %{_version} Release: %{_release} Vendor: APC UPS Daemon Team Distribution: The apcupsd Team Packager: %{_packager} URL: http://www.apcupsd.com Source0: http://www.spcupsd.com/%{name}-%{version}.tar.gz Source1: Release_Notes-%{version}-%{release}.tar.gz Group: System Environment/Daemons License: GPL v2 BuildRoot: %{_tmppath}/%{name}-root BuildRequires: gd-devel, ncurses-devel, ghostscript, libstdc++-devel %if %{rh7} BuildRequires: glibc-devel >= 2.2, libjpeg-devel, libpng-devel, zlib-devel, freetype-devel %else BuildRequires: glibc-devel >= 2.3 %endif %if %{gapcmon} BuildRequires: glibc-devel, gtk2-devel >= 2.4, glib2-devel, atk-devel BuildRequires: ORBit2, pango-devel, pkgconfig %endif %if %{suse} && %{gapcmon} BuildRequires: bonobo-activation, freetype2-devel, cairo-devel, fontconfig-devel BuildRequires: gconf2-devel, gnome-vfs2-devel, libpng-devel, glitz-devel, xorg-x11-libs BuildRequires: libbonobo-devel, libbonoboui-devel %endif %if %{fedora_core} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif %if %{mdk} && %{gapcmon} BuildRequires: libbonobo2_0-devel, libbonoboui2_0-devel, freetype2-devel, libGConf2_4-devel %endif %if %{rhel4} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif %if %{rhel5} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif %if %{snmp} BuildRequires: net-snmp-devel %endif Provides: apcupsd Obsoletes: apcupsd-std apcupsd-usb Requires: perl, ncurses %if %{rh7} Requires: glibc >= 2.2 %else Requires: glibc >= 2.3 %endif %if %{snmp} Requires: net-snmp %endif %description Apcupsd can be used for controlling most APC UPSes. During a power failure, apcupsd will inform the users about the power failure and that a shutdown may occur. If power is not restored, a system shutdown will follow when the battery is exausted, a timeout (seconds) expires, or the battery runtime expires based on internal APC calculations determined by power consumption rates. If the power is restored before one of the above shutdown conditions is met, apcupsd will inform users about this fact. Some features depend on what UPS model you have (simple or smart). This package is configured for USB but can be reconfigured for standard serial port UPS models. See the manual. %package multimon Summary: APC UPS Power Control Daemon for Linux Group: Applications/Internet Requires: libstdc++ %if %{fedora_core} || %{suse} || %{mdk} || %{rhel4} || %{rhel5} Requires: gd >= 2.0 %else Requires: gd < 2.0 %endif %if %{rh7} Requires: glibc >= 2.2, libjpeg, libpng, zlib, freetype %else Requires: glibc >= 2.3 %endif %description multimon apcupsd Network Monitoring (CGI) Programs which will give you the status of your UPS or UPSes over the network. %if %{gapcmon} %package gapcmon Summary: APC UPS Power Control Daemon for Linux Group: Applications/System Requires: glibc, gtk2 >= 2.4, glib2, atk, libbonobo, libbonoboui, ORBit2, pango %endif %if %{suse} && %{gapcmon} Requires: bonobo-activation, freetype2, cairo, fontconfig, gconf2, gnome-vfs2, libpng, glitz, xorg-x11-libs %endif %if %{fedora_core} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{mdk} && %{gapcmon} Requires: freetype2, GConf2 %endif %if %{rhel4} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{rhel5} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{gapcmon} %description gapcmon A Gnome application to monitor the status of your UPS. %endif # SuSE turns off stripping of binaries by default. In order to get # stripped packages we must generate debug package. RedHat and Mandriva # turn debug packages on by default but strip binaries regardless. %if %{suse} %debug_package %endif %prep %setup -b 1 %build %configure \ --prefix=%{_prefix} \ --sbindir=/sbin \ --sysconfdir=%{_sysconfdir}/apcupsd \ --with-cgi-bin=%{cgidir} \ --enable-cgi \ --enable-net \ --enable-pcnet \ --enable-apcsmart \ --enable-dumb \ --enable-usb \ --enable-snmp \ %if %{gapcmon} --enable-gapcmon \ %endif %if %{snmp} --enable-net-snmp \ %endif --with-serial-dev= \ --with-upstype=usb \ --with-halpolicydir=%{halpolicydir} \ --with-upscable=usb make cd examples make hid-ups cd ../ %install [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{initdir} mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/cgi make \ DESTDIR=$RPM_BUILD_ROOT \ install install -m744 platforms/apccontrol \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/apccontrol %if ! %{suse} && ! %{mdk} install -m755 platforms/redhat/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if %{suse} install -m755 platforms/suse/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if %{mdk} install -m755 platforms/mandrake/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if ! %{mdk} rm $RPM_BUILD_ROOT%{initdir}/halt rm $RPM_BUILD_ROOT%{initdir}/halt.old %endif install -m744 examples/hid-ups \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/hid-ups install -m744 examples/make-hiddev \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/make-hiddev %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT rm -f $RPM_BUILD_DIR/Release_Notes-%{version}-%{release}.txt %files %defattr(-,root,root) %{_sysconfdir}/apcupsd/make-hiddev %{_sysconfdir}/apcupsd/hid-ups %{halpolicydir}/80-apcupsd-ups-policy.fdi %doc COPYING DISCLAIMER ReleaseNotes ChangeLog ../Release_Notes-%{version}-%{release}.txt doc/manual/manual.html doc/manual/*.png %dir %{_sysconfdir}/apcupsd %{initdir}/apcupsd %config(noreplace) %{_sysconfdir}/apcupsd/apccontrol %config(noreplace) %{_sysconfdir}/apcupsd/changeme %config(noreplace) %{_sysconfdir}/apcupsd/commfailure %config(noreplace) %{_sysconfdir}/apcupsd/commok %config(noreplace) %{_sysconfdir}/apcupsd/onbattery %config(noreplace) %{_sysconfdir}/apcupsd/offbattery %config(noreplace) %{_sysconfdir}/apcupsd/apcupsd.conf /sbin/* %attr(-,root,man) %{_mandir}/*/* %files multimon %defattr(-,root,root) %dir %{_sysconfdir}/apcupsd %dir %{cgidir} %attr(-,%{dataowner},%{datagroup}) %{_sysconfdir}/apcupsd/apcupsd.css %attr(-,%{binowner},%{bingroup}) %{cgidir}/* %attr(-,%{dataowner},%{datagroup}) %config(noreplace) %{_sysconfdir}/apcupsd/hosts.conf %attr(-,%{dataowner},%{datagroup}) %config(noreplace) %{_sysconfdir}/apcupsd/multimon.conf %if %{gapcmon} %files gapcmon %defattr(-,root,root) %{_prefix}/bin/gapcmon %{_prefix}/share/applications/gapcmon.desktop %{_prefix}/share/pixmaps/apcupsd.png %{_prefix}/share/pixmaps/charging.png %{_prefix}/share/pixmaps/gapc_prefs.png %{_prefix}/share/pixmaps/onbatt.png %{_prefix}/share/pixmaps/online.png %{_prefix}/share/pixmaps/unplugged.png %endif %post # get rid of any 3.6.2 stuff rm -f /etc/rc.d/rc[0-6].d/[KS]20apcups rm -f %{initdir}/apcups # add our links if [ "$1" -ge 1 ] ; then /sbin/chkconfig --add apcupsd fi # are we Red Hat or SuSE? # Mandrake already handles apcupsd if [ -s /etc/redhat-release -o -s /etc/SuSE-release -o -s /etc/whitebox-release ]; then cp -f %{initdir}/halt %{initdir}/halt.old awk '# Stuff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert the new apcupsd code just before the following line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f %{pwrfaildir}/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " %{pwrfaildir}/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # Everything else is duplicated { print } ' %{initdir}/halt.old > %{initdir}/halt chmod 744 %{initdir}/halt fi # restart the daemon if we are upgrading if [ "$1" -ge "2" ] ; then %{initdir}/apcupsd restart fi # Undo things a bit %preun if [ "$1" = 0 ] ; then # remove startup links /sbin/chkconfig --del apcupsd # are we Red Hat or SuSE? # Mandrake already handles apcupsd if [ -s /etc/redhat-release -o -s /etc/SuSE-release -o -s /etc/whitebox-release ]; then cp -f %{initdir}/halt %{initdir}/halt.old awk '# Stuff added by apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # Everything else is duplicated { print } ' %{initdir}/halt.old > %{initdir}/halt chmod 744 %{initdir}/halt fi fi %changelog * Sun Jan 10 2010 Adam Kropelin - changes for new snmp driver * Sat Aug 01 2009 D. Scott Barninger - fix restart on upgrade using $1 variable. remove previously commented out code * Sat May 16 2009 D. Scott Barninger - comment out latex build * Fri May 15 2009 Adam Kropelin - changes for new user manual location and format * Sat May 31 2008 D. Scott Barninger - add check for upgrade and restart daemon * Sun May 11 2008 Adam Kropelin - remove powerflute * Sun Feb 03 2008 D. Scott Barninger - add debug package to strip suse * Sat Nov 17 2007 D. Scott Barninger - add hal policy file * Sat Nov 10 2007 D. Scott Barninger - SuSE 10.3 replaces tetex with texlive-latex package * Sun May 27 2007 Adam Kropelin - add support for rhel5 * Sun Jan 28 2007 D. Scott Barninger - remove /etc/apcupsd/masterconnect and mastertimeout files * Sat Jan 27 2007 D. Scott Barninger - add snmp build - fix location of Requires for base package * Sun Jan 21 2007 D. Scott Barninger - correct gapcmon dependancies * Sat Jan 20 2007 D. Scott Barninger - restructure for 3.14 release - merge std and ups packages - remove --enable-pthreads and --enable-master-slave - add --enable-pcnet - break out multimon into separate package - add gapcmon package * Sat Aug 19 2006 D. Scott Barninger - add third party packager tag * Fri May 05 2006 D. Scott Barninger - update build requirments to include ghostscript - update fedora_core build requirements to include latex2html * Sun Apr 23 2006 D. Scott Barninger - add pdf manual to doc package - remove redundant code for std and usb packages - add powerflute * Sat Apr 22 2006 D. Scott Barninger - clean up build defines, add rhel4 * Sat Jan 21 2006 D. Scott Barninger - release 3.12.2 update docs * Sun Sep 18 2005 D. Scott Barninger - Change deprecated Copyright tag to License * Tue Jun 07 2005 Adam Kropelin - Rename mainsback.in to offbattery.in so default power loss/return actions - are symmetrical. * Sat Apr 30 2005 D. Scott Barninger - fix typo in rh7 dependencies * Sat Mar 12 2005 D. Scott Barninger - clean up halt insertion code, add check for whitebox-release - remove cruft that has been commented out for a long time - add pwrfaildir as variable - correct SuSE initdir - add libjpeg libpng zlib freetype dependencies for RH7 * Sun Nov 28 2004 D. Scott Barninger - correct awk insertion in halt script for SuSE * Fri Nov 05 2004 D. Scott Barninger - change Mandrake logic in preun and post scriptlets to if;then;fi * Sun Oct 31 2004 D. Scott Barninger - add Mandrake support * Wed Aug 04 2004 D. Scott Barninger - changed location of apcupsd.css to /etc/apcupsd from /etc/apcupsd/cgi - corrected typo introduced in SuSE configuration for initdir definition * Sun Apr 25 2004 D. Scott Barninger - add SuSE configuration * Sat Apr 24 2004 D. Scott Barninger - tidy up doc includes, add release notes * Mon Mar 08 2004 D. Scott Barninger - added additional clean of buildroot to beginning of install section - corrected post install routines for nicer chkconfig * Sat Jan 17 2004 D. Scott Barninger - added build of net driver to configure - moved usb driver build into both packages - set --with-serial-dev= to blank so will find any device and removed rh7 patch * Sat Jan 10 2004 D. Scott Barninger - added build tags for rh8 rh9 fedora_core and wb3 - cleaned up dependancies and Requires by platform * Thu Jan 1 2004 D. Scott Barninger - removed rh_version from package names - added platform build configuration section to beginning of file * Sat Nov 08 2003 Scott at fairfieldcomputers dot com - expanded usb devices from 0-9 to 0-15 * Fri Nov 07 2003 Scott at fairfieldcomputers dot com - corrected device path for usb devices to /dev/usb and added patch for - rh7 builds to make it /dev/usb/hid in /etc/apcupsd/apcupsd.conf * Sat Oct 18 2003 Scott at fairfieldcomputers dot com - added master-slave, apcsmart and dumb to configure options * Sun Sep 14 2003 Scott at fairfieldcomputers dot com - added rm commands during install to remove halt scripts created - in the build root * Mon May 11 2003 Scott at fairfieldcomputers dot com - combined layout for usb/serial builds * Thu Jan 16 2003 Scott at fairfieldcomputers dot com - Update spec to new source layout - Added masterconnect and mastertimout to files section - Changed make install-apcupsd and make install-cgi to make install * Wed Sep 05 2001 kern at sibbald dot com - Applied very nice patch to this spec by Giulio Orsero * Thu Sep 14 2000 kern at sibbald dot com - Many thanks to Fredrik Persson and Neil Darlow for helping me write this spec file. - Basic spec by Kern Sibbald apcupsd-3.14.14/platforms/mandrake/apcupsd.spec.in.old000066400000000000000000000101131274230402600226050ustar00rootroot00000000000000%define name apcupsd %define version @VERSION@ %define release 1mdk %define _cgibin /var/www/cgi-bin %define _sysconfdir /etc/apcupsd %define _sbindir /sbin Summary: Power management software for APC UPS hardware Name: %{name} Version: %{version} Release: %{release} Source0: http://prdownloads.sourceforge.net/apcupsd/%{name}-%{version}.tar.gz License: GPL URL: http://sourceforge.net/projects/apcupsd/ Group: System/Servers Requires: initscripts >= 6.27-5mdk BuildRoot: %{_tmppath}/%{name}-buildroot Prefix: %{_prefix} BuildRequires: ncurses-devel gpm-devel libgd-devel %description UPS power management under Linux for APCC Products. It allows your computer/server to run during power problems for a specified length of time or the life of the batteries in your BackUPS, BackUPS Pro, SmartUPS v/s, or SmartUPS, and then properly executes a controlled shutdown during an extended power failure. %prep %setup -q %build %serverbuild %configure --enable-usb --enable-net --enable-master-slave --enable-powerflute --enable-pthreads --enable-cgi --with-cgi-bin=%{_cgibin} --enable-nls --with-serial-dev= --with-upstype=usb --with-upscable=usb --with-nisip=127.0.0.1 # %%make doesn't work make %install rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d mkdir -p $RPM_BUILD_ROOT%{_cgibin} perl -pi -e 's|/etc|\$\$RPM_BUILD_ROOT/etc|g' platforms/mandrake/Makefile.in perl -pi -e 's|\@/sbin/chkconfig|\#\@/sbin/chkconfig|' platforms/mandrake/Makefile.in %makeinstall cgibin=$RPM_BUILD_ROOT%{_cgibin} %find_lang %{name} %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT %post %_post_service apcupsd %preun %_preun_service apcupsd %files -f %{name}.lang %defattr(-,root,root) %config(noreplace) /etc/apcupsd/* %config(noreplace) /etc/rc.d/init.d/apcupsd %{_sbindir}/* %{_mandir}/man8/* %{_cgibin}/* %doc COPYING ChangeLog INSTALL doc/ examples/ %changelog * Mon Jan 19 2004 David Walser 3.10.10-1mdk - 3.10.10 - use USB by default * Thu Jan 01 2004 David Walser 3.10.9-1mdk - 3.10.9 * Fri Nov 21 2003 Erwan Velu 3.10.7-1mdk - New release * Tue Feb 04 2003 David Walser 3.10.5-1mdk - 3.10.5 - only listen on localhost by default (Network Information Server) - use gz instead of bz2 for apcupsd project version of spec file * Sun Feb 01 2003 David Walser 3.10.4-1mdk - 3.10.4 - updated URLs - remove explicit libgd1 dependency, let rpm figure it out - Remove patches (integrated upstream) * Tue Jun 11 2002 Frederic Lepied 3.9.8-2mdk - fix for gcc3 - rebuild for libintl2 * Tue Apr 16 2002 Ben Reser 3.9.8-1mdk - 3.9.8 - updated URLs - moved cgi scripts to /var/www/cgi-bin - Split the documentation from the examples in /usr/share/doc/ - Switched to using the system gd library and generating PNG's instead of the patent encumbered GIF. - Added the mandrake distribution setting so it stops saying it's running redhat. - Enabled USB support. * Thu Nov 22 2001 Frederic Lepied 3.8.2-2mdk - rebuild for new spec-helper * Fri Oct 19 2001 Frederic Lepied 3.8.2-1mdk - 3.8.2 * Thu Oct 18 2001 David MacKenzie 3.8.1-3mdk - Move programs from /usr/sbin to /sbin so they'll work after /usr is unmounted when shutting down. * Mon Sep 17 2001 Frederic Lepied 3.8.1-2mdk - remove %%post modifications of halt and put the right dependency on initscripts instead (Juergen Holm). * Fri Jun 1 2001 Frederic Lepied 3.8.1-1mdk - 3.8.1 * Thu Mar 29 2001 Frederic Lepied 3.8.0-2mdk - use the new rpm macros for servers. * Mon Dec 4 2000 Frederic Lepied 3.8.0-1mdk - new version * Wed Aug 30 2000 Frederic Lepied 3.7.0-3mdk - %%postun => %%preun * Mon Aug 07 2000 Frederic Lepied 3.7.0-2mdk - automatically added BuildRequires * Fri Jul 28 2000 Frederic Lepied 3.7.0-1mdk - first mandrake version # end of file apcupsd-3.14.14/platforms/mandrake/awkhaltprog.in000066400000000000000000000020451274230402600217700ustar00rootroot00000000000000# # Awk program to insert the necessary apcupsd script in # to a halt script. # # Suff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert our code just before this line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " @sysconfdir@/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # everything else is duplicated { print } apcupsd-3.14.14/platforms/mingw/000077500000000000000000000000001274230402600164535ustar00rootroot00000000000000apcupsd-3.14.14/platforms/mingw/Makefile000066400000000000000000000022361274230402600201160ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-mingw all-uninstall: uninstall-mingw install-mingw: $(call DISTINST,mingw) @echo "You have to manually install apcupsd boot script and" @echo "halt script for clean emergency shutdown." @echo "Please contribute your distribution install to apcupsd team." @echo "I'm sorry: you are on your own." uninstall-mingw: $(call DISTUNINST,mingw) @echo "You have to manually uninstall apcupsd boot script and" @echo "halt script." @echo "Please contribute your distribution install to apcupsd team." @echo "I'm sorry: you are on your own." TEXTFILES := $(topdir)/COPYING \ $(topdir)/ChangeLog \ $(topdir)/ReleaseNotes \ $(wildcard $(topdir)/doc/*.txt) MAKENSIS = makensis UNIX2DOS = unix2dos winapcupsd.exe: $(STRP) $(wildcard $(topdir)/src/*.exe) $(wildcard $(topdir)/src/win32/*.exe) $(wildcard $(topdir)/src/cgi/*.cgi) $(UNIX2DOS) -k -n $(foreach f,$(TEXTFILES),$(f) installer/$(subst .txt,,$(notdir $(f))).txt) $(MAKENSIS) -V2 -DDEPKGS="$(DEPKGS)" -DCROSSTOOLS="$(CROSSTOOLS)" -DVERSION="$(VERSION)" -DTOPDIR="${topdir}" installer/winapcupsd.nsiapcupsd-3.14.14/platforms/mingw/apccontrol.bat000077500000000000000000000137601274230402600213210ustar00rootroot00000000000000@echo off setlocal rem rem This is the Windows apccontrol file. rem rem Assign parameters to named variables SET command=%1 SET sbindir=%5 rem Strip leading and trailing quotation marks from paths. rem This is easily accomplished on NT, but Win95/98/ME rem require an evil little trick with 'FOR'. SET sbindir=%sbindir:"=% IF "%sbindir%" == "" FOR %%A IN (%5) DO SET sbindir=%%A rem Paths to important executables SET APCUPSD="%sbindir%\apcupsd" SET SHUTDOWN="%sbindir%\shutdown" SET BACKGROUND="%sbindir%\background" rem Only do popups on Win95/98/ME/NT. All other platforms support rem balloon notifications which are provided by apctray. SET POPUP=echo VER | FIND /I "Windows 95" > NUL IF NOT ERRORLEVEL 1 SET POPUP=%BACKGROUND% "%sbindir%\popup" VER | FIND /I "Windows 98" > NUL IF NOT ERRORLEVEL 1 SET POPUP=%BACKGROUND% "%sbindir%\popup" VER | FIND /I "Windows ME" > NUL IF NOT ERRORLEVEL 1 SET POPUP=%BACKGROUND% "%sbindir%\popup" VER | FIND /I "Windows NT" > NUL IF NOT ERRORLEVEL 1 SET POPUP=%BACKGROUND% "%sbindir%\popup" rem rem This piece is to substitute the default behaviour with your own script, rem perl, C program, etc. rem rem You can customize any command by creating an executable file (may be a rem script or a compiled program) and naming it the same as the %1 parameter rem passed by apcupsd to this script. We will accept files with any extension rem included in PATHEXT (*.exe, *.bat, *.cmd, etc). rem rem After executing your script, apccontrol continues with the default action. rem If you do not want apccontrol to continue, exit your script with exit rem code 99. E.g. "exit /b 99". rem rem WARNING: please be aware that if you add any commands before the shutdown rem in the downshutdown) case and your command errors or stalls, it will rem prevent your machine from being shutdown, so test, test, test to rem make sure it works correctly. rem rem The apccontrol.bat file will be replaced every time apcupsd is installed, rem so do NOT make event modifications in this file. Instead, override the rem event actions using event scripts as described above. rem rem Use CALL here because event script might be a batch file itself CALL ".\%command%" 2> NUL rem This is retarded. "IF ERRORLEVEL 99" means greater-than-or- rem equal-to 99, so we have to synthesize an == using two IFs. rem Ahh, the glory of Windows batch programming. At least they rem gave us a NOT op. IF NOT ERRORLEVEL 99 GOTO :events IF NOT ERRORLEVEL 100 GOTO :done :events rem rem powerout, onbattery, offbattery, mainsback events occur rem in that order. rem IF "%command%" == "commfailure" GOTO :commfailure IF "%command%" == "commok" GOTO :commok IF "%command%" == "powerout" GOTO :powerout IF "%command%" == "onbattery" GOTO :onbattery IF "%command%" == "offbattery" GOTO :offbattery IF "%command%" == "mainsback" GOTO :mainsback IF "%command%" == "failing" GOTO :failing IF "%command%" == "timeout" GOTO :timeout IF "%command%" == "loadlimit" GOTO :loadlimit IF "%command%" == "runlimit" GOTO :runlimit IF "%command%" == "doshutdown" GOTO :doshutdown IF "%command%" == "annoyme" GOTO :annoyme IF "%command%" == "emergency" GOTO :emergency IF "%command%" == "changeme" GOTO :changeme IF "%command%" == "remotedown" GOTO :remotedown IF "%command%" == "startselftest" GOTO :startselftest IF "%command%" == "endselftest" GOTO :endselftest IF "%command%" == "battdetach" GOTO :battdetach IF "%command%" == "battattach" GOTO :battattach echo Unknown command '%command%' echo. echo Usage: %0 command echo. echo Warning: this script is intended to be launched by echo apcupsd and should never be launched by users. GOTO :done :commfailure %POPUP% "Communications with UPS lost." GOTO :done :commok %POPUP% "Communciations with UPS restored." GOTO :done :powerout GOTO :done :onbattery %POPUP% "Power failure. Running on UPS batteries." GOTO :done :offbattery %POPUP% "Power has returned. No longer running on UPS batteries." GOTO :done :mainsback GOTO :done :failing %POPUP% "UPS battery power exhausted. Doing shutdown." GOTO :done :timeout %POPUP% "UPS battery runtime limit exceeded. Doing shutdown." GOTO :done :loadlimit %POPUP% "UPS battery discharge limit reached. Doing shutdown." GOTO :done :runlimit %POPUP% "UPS battery runtime percent reached. Doing shutdown." GOTO :done :doshutdown rem rem If you want to try to power down your UPS, uncomment rem out the following lines, but be warned that if the rem following shutdown -h now doesn't work, you may find rem the power being shut off to a running computer :-( rem Also note, we do this in the doshutdown case, because rem there is no way to get control when the machine is rem shutdown to call this script with --killpower. As rem a consequence, we do both killpower and shutdown rem here. rem Note that Win32 lacks a portable way to delay for a rem given time, so we use the trick of pinging a rem non-existent IP address with a given timeout. rem rem %APCUPSD% /kill rem ping -n 1 -w 5000 10.255.255.254 > NUL rem %POPUP% "Doing %APCUPSD% --killpower" rem %APCUPSD% --killpower rem ping -n 1 -w 12000 10.255.255.254 > NUL rem %SHUTDOWN% -h now GOTO :done :annoyme %POPUP% "Power problems: please logoff." GOTO :done :emergency %POPUP% "Emergency shutdown initiated." GOTO :done :changeme %POPUP% "Emergency! UPS batteries have failed: Change them NOW" GOTO :done :remotedown %POPUP% "Shutdown due to master state or comms lost." GOTO :done :startselftest %POPUP% "Self-test starting" GOTO :done :endselftest %POPUP% "Self-test completed" GOTO :done :battdetach %POPUP% "Battery disconnected" GOTO :done :battattach %POPUP% "Battery reattached" GOTO :done :done rem That's all, folks apcupsd-3.14.14/platforms/mingw/apcupsd.cat000066400000000000000000000002501274230402600206000ustar00rootroot00000000000000This file will contain the digital signature of the files to be installed on the system. This file will be provided by Microsoft upon certification of your drivers. apcupsd-3.14.14/platforms/mingw/apcupsd.conf.in000066400000000000000000000314401274230402600213700ustar00rootroot00000000000000## apcupsd.conf v1.1 ## # # for apcupsd release @VERSION@ - win32-mingw # # "apcupsd" POSIX config file # # Note that the apcupsd daemon must be restarted in order for changes to # this configuration file to become active. # # # ========= General configuration parameters ============ # # UPSNAME xxx # Use this to give your UPS a name in log files and such. This # is particulary useful if you have multiple UPSes. This does not # set the EEPROM. It should be 8 characters or less. #UPSNAME # UPSCABLE # Defines the type of cable connecting the UPS to your computer. # # Possible generic choices for are: # simple, smart, ether, usb # # Or a specific cable model number may be used: # 940-0119A, 940-0127A, 940-0128A, 940-0020B, # 940-0020C, 940-0023A, 940-0024B, 940-0024C, # 940-1524C, 940-0024G, 940-0095A, 940-0095B, # 940-0095C, 940-0625A, M-04-02-2000 # UPSCABLE usb # To get apcupsd to work, in addition to defining the cable # above, you must also define a UPSTYPE, which corresponds to # the type of UPS you have (see the Description for more details). # You must also specify a DEVICE, sometimes referred to as a port. # For USB UPSes, please leave the DEVICE directive blank. For # other UPS types, you must specify an appropriate port or address. # # UPSTYPE DEVICE Description # apcsmart COMx Newer serial character device, appropriate for # SmartUPS models using a serial cable (not USB). # Can be COM1, COM2, etc. # # usb Most new UPSes are USB. A blank DEVICE # setting enables autodetection, which is # the best choice for most installations. # # net hostname:port Network link to a master apcupsd through apcupsd's # Network Information Server. This is used if the # UPS powering your computer is connected to a # different computer for monitoring. # # snmp hostname:port:vendor:community # SNMP network link to an SNMP-enabled UPS device. # Hostname is the ip address or hostname of the UPS # on the network. Vendor can be can be "APC" or # "APC_NOTRAP". "APC_NOTRAP" will disable SNMP trap # catching; you usually want "APC". Port is usually # 161. Community is usually "private". # # netsnmp hostname:port:vendor:community # OBSOLETE # Same as SNMP above but requires use of the # net-snmp library. Unless you have a specific need # for this old driver, you should use 'snmp' instead. # # dumb COMx Old serial character device for use with # simple-signaling UPSes. Can be COM1, COM2, etc. # # pcnet ipaddr:username:passphrase # PowerChute Network Shutdown protocol which can be # used as an alternative to SNMP with the AP9617 # family of smart slot cards.ipaddr is the IP # address of the UPS mgmtcard. username and # passphrase are the credentials for which the card # has been configured. # # modbus COMx Serial device for use with newest SmartUPS models # supporting the MODBUS protocol. # modbus Leave the DEVICE setting blank for MODBUS over USB # or set to the serial number of the UPS to ensure # that apcupsd binds to that particular unit # (helpful if you have more than one USB UPS). # UPSTYPE usb DEVICE # POLLTIME # Interval (in seconds) at which apcupsd polls the UPS for status. This # setting applies both to directly-attached UPSes (UPSTYPE apcsmart, usb, # dumb) and networked UPSes (UPSTYPE net, snmp). Lowering this setting # will improve apcupsd's responsiveness to certain events at the cost of # higher CPU utilization. The default of 60 is appropriate for most # situations. #POLLTIME 60 # SCRIPTDIR # Directory in which apccontrol and event scripts are located. SCRIPTDIR @sysconfdir@ # PWRFAILDIR # Directory in which to write the powerfail flag file. This file # is created when apcupsd initiates a system shutdown and is # checked in the OS halt scripts to determine if a killpower # (turning off UPS output power) is required. PWRFAILDIR @PWRFAILDIR@ # NOLOGINDIR # Directory in which to write the nologin file. The existence # of this flag file tells the OS to disallow new logins. NOLOGINDIR @nologdir@ # # ======== Configuration parameters used during power failures ========== # # The ONBATTERYDELAY is the time in seconds from when a power failure # is detected until we react to it with an onbattery event. # # This means that, apccontrol will be called with the powerout argument # immediately when a power failure is detected. However, the # onbattery argument is passed to apccontrol only after the # ONBATTERYDELAY time. If you don't want to be annoyed by short # powerfailures, make sure that apccontrol powerout does nothing # i.e. comment out the wall. ONBATTERYDELAY 6 # # Note: BATTERYLEVEL, MINUTES, and TIMEOUT work in conjunction, so # the first that occurs will cause the initation of a shutdown. # # If during a power failure, the remaining battery percentage # (as reported by the UPS) is below or equal to BATTERYLEVEL, # apcupsd will initiate a system shutdown. BATTERYLEVEL 5 # If during a power failure, the remaining runtime in minutes # (as calculated internally by the UPS) is below or equal to MINUTES, # apcupsd, will initiate a system shutdown. MINUTES 3 # If during a power failure, the UPS has run on batteries for TIMEOUT # many seconds or longer, apcupsd will initiate a system shutdown. # A value of 0 disables this timer. # # Note, if you have a Smart UPS, you will most likely want to disable # this timer by setting it to zero. That way, you UPS will continue # on batteries until either the % charge remaing drops to or below BATTERYLEVEL, # or the remaining battery runtime drops to or below MINUTES. Of course, # if you are testing, setting this to 60 causes a quick system shutdown # if you pull the power plug. # If you have an older dumb UPS, you will want to set this to less than # the time you know you can run on batteries. TIMEOUT 0 # Time in seconds between annoying users to signoff prior to # system shutdown. 0 disables. ANNOY 300 # Initial delay after power failure before warning users to get # off the system. ANNOYDELAY 60 # The condition which determines when users are prevented from # logging in during a power failure. # NOLOGON [ disable | timeout | percent | minutes | always ] NOLOGON disable # If KILLDELAY is non-zero, apcupsd will continue running after a # shutdown has been requested, and after the specified time in # seconds attempt to kill the power. This is for use on systems # where apcupsd cannot regain control after a shutdown. # KILLDELAY 0 disables KILLDELAY 0 # # ==== Configuration statements for Network Information Server ==== # # NETSERVER [ on | off ] on enables, off disables the network # information server. If netstatus is on, a network information # server process will be started for serving the STATUS and # EVENT data over the network (used by CGI programs). NETSERVER on # NISIP # IP address on which NIS server will listen for incoming connections. # This is useful if your server is multi-homed (has more than one # network interface and IP address). Default value is 0.0.0.0 which # means any incoming request will be serviced. Alternatively, you can # configure this setting to any specific IP address of your server and # NIS will listen for connections only on that interface. Use the # loopback address (127.0.0.1) to accept connections only from the # local machine. NISIP 0.0.0.0 # NISPORT default is 3551 as registered with the IANA # port to use for sending STATUS and EVENTS data over the network. # It is not used unless NETSERVER is on. If you change this port, # you will need to change the corresponding value in the cgi directory # and rebuild the cgi programs. NISPORT 3551 # If you want the last few EVENTS to be available over the network # by the network information server, you must define an EVENTSFILE. EVENTSFILE @LOGDIR@\apcupsd.events # EVENTSFILEMAX # By default, the size of the EVENTSFILE will be not be allowed to exceed # 10 kilobytes. When the file grows beyond this limit, older EVENTS will # be removed from the beginning of the file (first in first out). The # parameter EVENTSFILEMAX can be set to a different kilobyte value, or set # to zero to allow the EVENTSFILE to grow without limit. EVENTSFILEMAX 10 # # ========== Configuration statements used if sharing ============= # a UPS with more than one machine # # Remaining items are for ShareUPS (APC expansion card) ONLY # # UPSCLASS [ standalone | shareslave | sharemaster ] # Normally standalone unless you share an UPS using an APC ShareUPS # card. UPSCLASS standalone # UPSMODE [ disable | share ] # Normally disable unless you share an UPS using an APC ShareUPS card. UPSMODE disable # # ===== Configuration statements to control apcupsd system logging ======== # # Time interval in seconds between writing the STATUS file; 0 disables STATTIME 0 # Location of STATUS file (written to only if STATTIME is non-zero) STATFILE @LOGDIR@\apcupsd.status # LOGSTATS [ on | off ] on enables, off disables # Note! This generates a lot of output, so if # you turn this on, be sure that the # file defined in syslog.conf for LOG_NOTICE is a named pipe. # You probably do not want this on. LOGSTATS off # Time interval in seconds between writing the DATA records to # the log file. 0 disables. DATATIME 0 # FACILITY defines the logging facility (class) for logging to syslog. # If not specified, it defaults to "daemon". This is useful # if you want to separate the data logged by apcupsd from other # programs. #FACILITY DAEMON # # ========== Configuration statements used in updating the UPS EPROM ========= # # # These statements are used only by apctest when choosing "Set EEPROM with conf # file values" from the EEPROM menu. THESE STATEMENTS HAVE NO EFFECT ON APCUPSD. # # UPS name, max 8 characters #UPSNAME UPS_IDEN # Battery date - 8 characters #BATTDATE mm/dd/yy # Sensitivity to line voltage quality (H cause faster transfer to batteries) # SENSITIVITY H M L (default = H) #SENSITIVITY H # UPS delay after power return (seconds) # WAKEUP 000 060 180 300 (default = 0) #WAKEUP 60 # UPS Grace period after request to power off (seconds) # SLEEP 020 180 300 600 (default = 20) #SLEEP 180 # Low line voltage causing transfer to batteries # The permitted values depend on your model as defined by last letter # of FIRMWARE or APCMODEL. Some representative values are: # D 106 103 100 097 # M 177 172 168 182 # A 092 090 088 086 # I 208 204 200 196 (default = 0 => not valid) #LOTRANSFER 208 # High line voltage causing transfer to batteries # The permitted values depend on your model as defined by last letter # of FIRMWARE or APCMODEL. Some representative values are: # D 127 130 133 136 # M 229 234 239 224 # A 108 110 112 114 # I 253 257 261 265 (default = 0 => not valid) #HITRANSFER 253 # Battery charge needed to restore power # RETURNCHARGE 00 15 50 90 (default = 15) #RETURNCHARGE 15 # Alarm delay # 0 = zero delay after pwr fail, T = power fail + 30 sec, L = low battery, N = never # BEEPSTATE 0 T L N (default = 0) #BEEPSTATE T # Low battery warning delay in minutes # LOWBATT 02 05 07 10 (default = 02) #LOWBATT 2 # UPS Output voltage when running on batteries # The permitted values depend on your model as defined by last letter # of FIRMWARE or APCMODEL. Some representative values are: # D 115 # M 208 # A 100 # I 230 240 220 225 (default = 0 => not valid) #OUTPUTVOLTS 230 # Self test interval in hours 336=2 weeks, 168=1 week, ON=at power on # SELFTEST 336 168 ON OFF (default = 336) #SELFTEST 336 apcupsd-3.14.14/platforms/mingw/apcupsd.inf000066400000000000000000000112101274230402600206030ustar00rootroot00000000000000[Version] Signature = "$Chicago$" provider = %manufacturer% DriverVer = 09/17/2006,0.1.12.0 CatalogFile = apcupsd.cat CatalogFile.NT = apcupsd.cat CatalogFile.NTAMD64 = apcupsd_x64.cat Class = LibUsbDevices ClassGUID = {EB781AAF-9C70-4523-A5DF-642A87ECA567} [ClassInstall] AddReg=libusb_class_install_add_reg [ClassInstall32] AddReg=libusb_class_install_add_reg [libusb_class_install_add_reg] HKR,,,,"LibUSB-Win32 Devices" HKR,,Icon,,"-20" [Manufacturer] %manufacturer%=Devices,NT,NTAMD64 ;-------------------------------------------------------------------------- ; Files ;-------------------------------------------------------------------------- [SourceDisksNames] 1 = "Libusb-Win32 Driver Installation Disk",, [SourceDisksFiles] libusb0.sys = 1,, libusb0.dll = 1,, libusb0_x64.sys = 1,, libusb0_x64.dll = 1,, [DestinationDirs] libusb_files_sys = 10,system32\drivers libusb_files_sys_x64 = 10,system32\drivers libusb_files_dll = 10,system32 libusb_files_dll_wow64 = 10,syswow64 libusb_files_dll_x64 = 10,system32 [libusb_files_sys] libusb0.sys [libusb_files_sys_x64] libusb0.sys,libusb0_x64.sys [libusb_files_dll] libusb0.dll [libusb_files_dll_wow64] libusb0.dll [libusb_files_dll_x64] libusb0.dll,libusb0_x64.dll ;-------------------------------------------------------------------------- ; Device driver ;-------------------------------------------------------------------------- [LIBUSB_DEV] CopyFiles = libusb_files_sys, libusb_files_dll AddReg = libusb_add_reg [LIBUSB_DEV.NT] CopyFiles = libusb_files_sys, libusb_files_dll [LIBUSB_DEV.NTAMD64] CopyFiles = libusb_files_sys_x64, libusb_files_dll_wow64, libusb_files_dll_x64 [LIBUSB_DEV.HW] DelReg = libusb_del_reg_hw AddReg = libusb_add_reg_hw [LIBUSB_DEV.NT.HW] DelReg = libusb_del_reg_hw AddReg = libusb_add_reg_hw [LIBUSB_DEV.NTAMD64.HW] DelReg = libusb_del_reg_hw AddReg = libusb_add_reg_hw [LIBUSB_DEV.NT.Services] AddService = libusb0, 0x00000002, libusb_add_service [LIBUSB_DEV.NTAMD64.Services] AddService = libusb0, 0x00000002, libusb_add_service [libusb_add_reg] HKR,,DevLoader,,*ntkern HKR,,NTMPDriver,,libusb0.sys ; Older versions of this .inf file installed filter drivers. They are not ; needed any more and must be removed [libusb_del_reg_hw] HKR,,LowerFilters HKR,,UpperFilters ; Device properties [libusb_add_reg_hw] HKR,,SurpriseRemovalOK, 0x00010001, 1 ;-------------------------------------------------------------------------- ; Services ;-------------------------------------------------------------------------- [libusb_add_service] DisplayName = "LibUsb-Win32 - Kernel Driver 09/17/2006, 0.1.12.0" ServiceType = 1 StartType = 3 ErrorControl = 0 ServiceBinary = %12%\libusb0.sys ;-------------------------------------------------------------------------- ; Devices ;-------------------------------------------------------------------------- [Devices] ; Normal APC UPSes use PID 0x0002 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0002 ; APC9620 Legacy Communications Card uses PID 0x0003 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0003 ; Early production and prototype units of AP9620 erroneously have ; 0x0001 or 0xffff "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0001 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_ffff [Devices.NT] ; Normal APC UPSes use PID 0x0002 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0002 ; APC9620 Legacy Communications Card uses PID 0x0003 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0003 ; Early production and prototype units of AP9620 erroneously have ; 0x0001 or 0xffff "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0001 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_ffff [Devices.NTAMD64] ; Normal APC UPSes use PID 0x0002 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0002 ; APC9620 Legacy Communications Card uses PID 0x0003 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0003 ; Early production and prototype units of AP9620 erroneously have ; 0x0001 or 0xffff "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_0001 "American Power Conversion USB UPS (Apcupsd)"=LIBUSB_DEV, USB\VID_051d&PID_ffff ;-------------------------------------------------------------------------- ; Strings ;-------------------------------------------------------------------------- [Strings] manufacturer = "APCUPSD" apcupsd-3.14.14/platforms/mingw/apcupsd_x64.cat000066400000000000000000000002501274230402600213010ustar00rootroot00000000000000This file will contain the digital signature of the files to be installed on the system. This file will be provided by Microsoft upon certification of your drivers. apcupsd-3.14.14/platforms/mingw/build-win32-cross-tools000077500000000000000000000307411274230402600227320ustar00rootroot00000000000000#!/bin/sh # This is my script for building a complete MinGW cross-compiler toolchain # that runs under Linux to produce executables that run under Windows. It # probably works (or can easily be adapted to work) under any unix system. # # It is based in large part on Sam Lantinga's script, which in turn was # based partly on Ray Kelm's script, which in turn was built on # Mo Dejong's script for doing the same, but with some added fixes. # # NOTE: If you choose a destination directory for the installation (set # in the macro PREFIX) for which you do not have write access, you will # need to run this script with root (or equivalent) privileges. # # # Updated by Igor Mikolic-Torreira # Updated by Adam Kropelin #----------------------------------------------------- # # BEGIN USER SETTINGS # # You need to review and adjust the macros that follow # #----------------------------------------------------- # Directory where cross-tools directory will be placed TOPDIR=../../.. # Cross tools directory name under TOPDIR CROSSTOOLS=cross-tools # What flavor of GCC cross-compiler are we building? under CROSSTOOLS TARGET=mingw32 cwd=`pwd` cd ${TOPDIR} # Make TOPDIR absolute TOPDIR=`pwd` BUILDDIR=${TOPDIR}/${CROSSTOOLS} cd ${cwd} # Where does the cross-compiler go? # This should be the directory into which your cross-compiler # will be installed. Remember that if you set this to a directory # that only root has write access to, you will need to run this # script as root. PREFIX=${BUILDDIR}/${TARGET} mkdir -p ${BUILDDIR} mkdir -p ${BUILDDIR}/${TARGET} echo "Building cross tools in ${BUILDDIR} ..." echo " " # Purge anything and everything already in the $PREFIX #(also known as the destination or installation) directory? # Set to "Y" to purge, any other value omits the purge step. PURGE_DIR="Y" # Set the following to the files from the current MinGW release # (or whichever MinGW release you wish to build and install) # You need to set both the URL they will be downloaded from # and the exact name of the individual component files. MINGW_URL="http://heanet.dl.sourceforge.net/sourceforge/mingw" MINGW_ARCHIVE="mingwrt-3.20-mingw32-dev.tar.gz" MINGW_DLL_ARCHIVE="mingwrt-3.20-mingw32-dll.tar.gz" W32API_ARCHIVE="w32api-3.17-2-mingw32-dev.tar.lzma" # GCC_CORE is required; the other components are optional. # Set any you don't want to "". You need binutils, # mingw runtime and w32api; do not ever set those to "". GNU_URL="ftp://ftp.gnu.org/gnu" GCC_VER="4.2.4" BINUTILS_VER="2.23.1" BINUTILS_URL="$GNU_URL/binutils" BINUTILS_ARCHIVE="binutils-$BINUTILS_VER.tar.bz2" GCC_URL="$GNU_URL/gcc/gcc-$GCC_VER" GCC_CORE_ARCHIVE="gcc-core-$GCC_VER.tar.bz2" GCC_GPP_ARCHIVE="gcc-g++-$GCC_VER.tar.bz2" GCC_G77_ARCHIVE="" GCC_OBJC_ARCHIVE="" GCC_JAVA_ARCHIVE="" GCC_ADA_ARCHIVE="" GCC_PATCH="" # These are the files from the SDL website # These are optional, set them to "" if you don't want them) SDL_URL="http://www.libsdl.org/extras/win32/common" OPENGL_ARCHIVE="" DIRECTX_ARCHIVE="" # These are the files from NSIS at sf.net NSIS_URL="http://heanet.dl.sourceforge.net/sourceforge/nsis" NSIS_ARCHIVE=nsis-2.46-src.tar.bz2 #----------------------------------------------------- # # END USER SETTINGS # # The remainder of the script should not neet any edits # #----------------------------------------------------- # Make sure these are initialized as we want them GCC_CORE="" BINUTILS="" GCC_LANGS="c" # Set our build directory and where our sources will go if [ "x$BUILDDIR" = "x" ]; then # Default to the current directory BUILDDIR=$(pwd) fi SRCDIR="$BUILDDIR/source" # Need install directory first on the path so gcc can find binutils PATH="$PREFIX/bin:$PATH" #----------------------------------------------------- # # Functions that do most of the work # #----------------------------------------------------- function download_files { # Download a file from a given url, only if it is not present mkdir -p "$SRCDIR" # Make sure wget is installed if test "x`which wget`" = "x" ; then echo "You need to install wget." exit 1 fi download_file "$GCC_CORE_ARCHIVE" "$GCC_URL" if [ "x$GCC_GPP_ARCHIVE" != "x" ]; then download_file "$GCC_GPP_ARCHIVE" "$GCC_URL" fi if [ "x$GCC_G77_ARCHIVE" != "x" ]; then download_file "$GCC_G77_ARCHIVE" "$GCC_URL" fi if [ "x$GCC_OBJC_ARCHIVE" != "x" ]; then download_file "$GCC_OBJC_ARCHIVE" "$GCC_URL" fi if [ "x$GCC_JAVA_ARCHIVE" != "x" ]; then download_file "$GCC_JAVA_ARCHIVE" "$GCC_URL" fi if [ "x$GCC_ADA_ARCHIVE" != "x" ]; then download_file "$GCC_ADA_ARCHIVE" "$GCC_URL" fi download_file "$BINUTILS_ARCHIVE" "$BINUTILS_URL" download_file "$MINGW_ARCHIVE" "$MINGW_URL" download_file "$MINGW_DLL_ARCHIVE" "$MINGW_URL" download_file "$W32API_ARCHIVE" "$MINGW_URL" if [ "x$OPENGL_ARCHIVE" != "x" ]; then download_file "$OPENGL_ARCHIVE" "$SDL_URL" fi if [ "x$DIRECTX_ARCHIVE" != "x" ]; then download_file "$DIRECTX_ARCHIVE" "$SDL_URL" fi } function download_file { cd "$SRCDIR" if test ! -f $1 ; then echo "Downloading $1" wget "$2/$1" if test ! -f $1 ; then echo "Could not download $1" exit 1 fi else echo "Found $1 in the srcdir $SRCDIR" fi cd "$BUILDDIR" } function purge_existing_install { echo "Purging the existing files in $PREFIX" if cd "$PREFIX"; then rm -rf * fi cd "$BUILDDIR" } function install_libs { echo "Installing cross libs and includes" mkdir -p "$PREFIX/$TARGET" cd "$PREFIX/$TARGET" tar -xzf "$SRCDIR/$MINGW_ARCHIVE" tar -xzf "$SRCDIR/$MINGW_DLL_ARCHIVE" lzma -dc "$SRCDIR/$W32API_ARCHIVE" | tar -x if [ "x$OPENGL_ARCHIVE" != "x" ]; then tar -xzf "$SRCDIR/$OPENGL_ARCHIVE" fi if [ "x$DIRECTX_ARCHIVE" != "x" ]; then tar -xzf "$SRCDIR/$DIRECTX_ARCHIVE" fi cd "$BUILDDIR" } function extract_binutils { cd "$SRCDIR" BINUTILS="binutils-$BINUTILS_VER" rm -rf "$BINUTILS" echo "Extracting binutils" tar -xjf "$SRCDIR/$BINUTILS_ARCHIVE" cd "$BUILDDIR" } function configure_binutils { cd "$BUILDDIR" rm -rf "binutils-$TARGET" mkdir "binutils-$TARGET" cd "binutils-$TARGET" echo "Configuring binutils" "$SRCDIR/$BINUTILS/configure" --prefix="$PREFIX" --target=$TARGET --disable-nls \ --with-gcc --with-gnu-as --with-gnu-ld --disable-shared &> configure.log cd "$BUILDDIR" } function build_binutils { cd "$BUILDDIR/binutils-$TARGET" echo "Building binutils" make CFLAGS="-O2 -fno-exceptions" LDFLAGS="-s" &> make.log if test $? -ne 0; then echo "make of binutils failed - log available: binutils-$TARGET/make.log" exit 1 fi cd "$BUILDDIR" } function install_binutils { cd "$BUILDDIR/binutils-$TARGET" echo "Installing binutils" make install &> make-install.log if test $? -ne 0; then echo "install of binutils failed - log available: binutils-$TARGET/make-install.log" exit 1 fi cd "$BUILDDIR" } function extract_gcc { cd "$SRCDIR" GCC="gcc-$GCC_VER" rm -rf "$GCC" echo "====== GCC ${GCC} =========" echo "Extracting gcc" tar -xjf "$SRCDIR/$GCC_CORE_ARCHIVE" if [ "x$GCC_GPP_ARCHIVE" != "x" ]; then GCC_LANGS=${GCC_LANGS}",c++" tar -xjf "$SRCDIR/$GCC_GPP_ARCHIVE" fi if [ "x$GCC_G77_ARCHIVE" != "x" ]; then GCC_LANGS=${GCC_LANGS}",f77" tar -xjf "$SRCDIR/$GCC_G77_ARCHIVE" fi if [ "x$GCC_OBJC_ARCHIVE" != "x" ]; then GCC_LANGS=${GCC_LANGS}",objc" tar -xjf "$SRCDIR/$GCC_OBJC_ARCHIVE" fi if [ "x$GCC_JAVA_ARCHIVE" != "x" ]; then GCC_LANGS=${GCC_LANGS}",java" tar -xjf "$SRCDIR/$GCC_JAVA_ARCHIVE" fi if [ "x$GCC_ADA_ARCHIVE" != "x" ]; then GCC_LANGS=${GCC_LANGS}",ada" tar -xjf "$SRCDIR/$GCC_ADA_ARCHIVE" fi cd "$BUILDDIR" } function patch_gcc { if [ "$GCC_PATCH" != "" ]; then echo "Patching gcc" cd "$SRCDIR/$GCC" patch -p1 < "$SRCDIR/$GCC_PATCH" cd "$BUILDDIR" fi } function configure_gcc { cd "$BUILDDIR" rm -rf "gcc-$TARGET" mkdir "gcc-$TARGET" cd "gcc-$TARGET" echo "Configuring gcc" "$SRCDIR/$GCC/configure" -v \ --prefix="$PREFIX" --target=$TARGET \ --with-headers="$PREFIX/$TARGET/include" \ --with-gcc --with-gnu-ld --with-gnu-as \ --enable-threads --disable-nls --enable-languages=$GCC_LANGS \ --disable-win32-registry --disable-shared --enable-sjlj-exceptions --enable-libgcj \ --disable-java-awt --without-x --enable-java-gc=boehm --disable-libgcj-debug \ --enable-interpreter --enable-hash-synchronization --enable-libstdcxx-debug \ &> configure.log cd "$BUILDDIR" } function build_gcc { cd "$BUILDDIR/gcc-$TARGET" echo "Building gcc" make CFLAGS="-O2" CXXFLAGS="-O2" GCJFLAGS="-O2" LDFLAGS="-s" DEBUG_FLAGS="-g0" &> make.log if test $? -ne 0; then echo "make of gcc failed - log available: gcc-$TARGET/make.log" exit 1 fi if [ "x$GCC_ADA" != "x" ]; then cd gcc make "CFLAGS=-O2" "LDFLAGS=-s" gnatlib_and_tools &> make-gnatlib.log if test $? -ne 0; then echo "make of gnatlib and tools failed - log available: gcc-$TARGET/make-gnatlib.log" exit 1 fi fi cd "$BUILDDIR" } function install_gcc { cd "$BUILDDIR/gcc-$TARGET" echo "Installing gcc" make install &> make-install.log if test $? -ne 0; then echo "install of gcc failed - log available: gcc-$TARGET/make-install.log" exit 1 fi cd "$BUILDDIR" } function do_nsis { echo Checking for SCons scons --version > /dev/null 2>&1 if [ $? -ne 0 ]; then echo Native SCons not found. echo It is required for building NSIS. echo Skipping NSIS. else echo Downloading NSIS download_file "$NSIS_ARCHIVE" "$NSIS_URL" cd "$BUILDDIR" NSIS=`tar -tjf "$SRCDIR/$NSIS_ARCHIVE" | head -n 1` echo "====== NSIS ${NSIS} =========" echo "Extracting NSIS" tar xjf "$SRCDIR/$NSIS_ARCHIVE" echo Building and Installing NSIS cd "$NSIS" scons PREFIX=$PREFIX install &> scons.log if test $? -ne 0; then echo "make of nsis failed - log available: $NSIS/scons.log" exit 1 fi fi } function final_tweaks { echo "Finalizing installation" # remove gcc build headers rm -rf "$PREFIX/$TARGET/sys-include" # Add extra binary links if [ ! -f "$PREFIX/$TARGET/bin/objdump" ]; then ln "$PREFIX/bin/$TARGET-objdump" "$PREFIX/$TARGET/bin/objdump" fi # make cc and c++ symlinks to gcc and g++ if [ ! -f "$PREFIX/$TARGET/bin/g++" ]; then ln "$PREFIX/bin/$TARGET-g++" "$PREFIX/$TARGET/bin/g++" fi if [ ! -f "$PREFIX/$TARGET/bin/cc" ]; then ln -s "gcc" "$PREFIX/$TARGET/bin/cc" fi if [ ! -f "$PREFIX/$TARGET/bin/c++" ]; then ln -s "g++" "$PREFIX/$TARGET/bin/c++" fi # strip all the binaries ls "$PREFIX"/bin/* "$PREFIX/$TARGET"/bin/* | egrep -v '.dll$' | egrep -v 'gccbug$' | while read file; do strip "$file" done echo "Installation complete!" } # # Main part of the script # download_files if [ "x$PURGE_DIR" = "xY" ]; then purge_existing_install fi install_libs extract_binutils configure_binutils build_binutils install_binutils extract_gcc patch_gcc configure_gcc build_gcc install_gcc do_nsis final_tweaks # # End # apcupsd-3.14.14/platforms/mingw/commfailure.vbs000077500000000000000000000074311274230402600215020ustar00rootroot00000000000000'///Wriiten by Ed Dondlinger 1/23/2009 - edondlinger@thepylegroup.com /// '/// MODIFY THE VARIABLES LISTED BELOW IN THE "USER VARIABLES" SECTION. '/// THEN RENAME FILE WITHOUT THE ".example" SUFFIX. '///Comment out the next line when testing, then change back when done. /// On Error Resume Next 'Get Time Zone info from local windows registry set oShell = CreateObject("WScript.Shell") atb = "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation\StandardName" TZInfo = oShell.RegRead(atb) 'XXXXXXXXXXXXXXXXXXXX USER VARIABLES XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX MyLocation = "home" MyEmailSubject = "COMMUNICATION FAILURE at: " & MyLocation MyEmailFromAddress = "xxx@zzz.com" 'you could also use this format to display the common name: """Me"" " MyEmailToAddress = "xxx@zzz.com" MyTextBody = "The APCUPS program has lost communication with the UPS at: " & MyLocation & "." & _ vbCRLF & "Reported by the APCUPS Server at: " & dateAdd("H",0,Now) & " " & TZInfo MySMTPServer = "localhost" 'or use a IP address i.e. "10.x.x.x" MyMailServerUserName = "MyUserName" MyMailServerPW = "mypassword" MySMTPServerPort = 25 MySMTPServerSSL = False 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX '////////// Email Section ////////// '*** NOTE: MSDN CDO Library can be referenced at: http://msdn.microsoft.com/en-us/library/ms872853(EXCHG.65).aspx Const cdoSendUsingPickup = 1 'Send message using the local SMTP service pickup directory. Const cdoSendUsingPort = 2 'Send the message using the network (SMTP over the network). Const cdoSendUsingExchange = 3 'Send the message using MS Exchange Mail Server. Const cdoAnonymous = 0 'Do not authenticate Const cdoBasic = 1 'basic (clear-text) authentication Const cdoNTLM = 2 'NTLM Const cdoURL = "http://schemas.microsoft.com/cdo/configuration/" Set objMessage = CreateObject("CDO.Message") '/// Set the message properties. /// With objMessage .Subject = MyEmailSubject .From = MyEmailFromAddress .To = MyEmailToAddress .TextBody = MyTextBody 'Set Mail Importance level, you can set [high,normal,low] .fields.Item("urn:schemas:mailheader:importance").Value = "high" 'Set Mail priority level, you can set [1=urgent, 0=normal, -1=nonurgent] .fields.Item("urn:schemas:mailheader:priority").Value = 1 .fields.Update() End with '/// This section provides the configuration information for the remote SMTP server. /// with objMessage.Configuration.Fields 'Send Using method (1 = local smtp, 2 = remote network smtp, 3 = MS Exchange) .Item(cdoURL & "sendusing") = 2 'Name or IP of Remote SMTP Server .Item(cdoURL & "smtpserver") = MySMTPServer 'Type of authentication, NONE, Basic (Base64 encoded), NTLM .Item(cdoURL & "smtpauthenticate") = cdoBasic 'Your UserID on the SMTP server .Item(cdoURL & "sendusername") = MyMailServerUserName 'Your password on the SMTP server .Item(cdoURL & "sendpassword") = MyMailServerPW 'Server port (typically 25) .Item(cdoURL & "smtpserverport") = MySMTPServerPort 'Use SSL for the connection (False or True) .Item(cdoURL & "smtpusessl") = MySMTPServerSSL 'Connection Timeout in seconds (the maximum time CDO will try to establish a connection to the SMTP server) .Item(cdoURL & "smtpconnectiontimeout") = 60 'Update the config. .Update end with '/// End remote SMTP server configuration section /// objMessage.Send '/// Clean-up /// Set objMessage = nothing set oShell = nothing '/// Exit with a 0 error level to ensure the apccontrol.bat continues /// Wscript.Quit 0 apcupsd-3.14.14/platforms/mingw/install.txt000066400000000000000000000073531274230402600206720ustar00rootroot00000000000000INSTALLING APCUPSD WINDOWS USB DRIVER USB connected UPSes on Windows require a special driver. In most cases, this driver is automatically installed when you install Apcupsd. However, if you unchecked the USB driver package during installation or if you're running Windows 98, 98SE, or ME, you will need to install the driver by hand. Follow the relevant instructions for your OS below to install the driver. WINDOWS NT, 2000, 2003, XP a. Plug in your USB UPS and wait for Windows to recognize it. b. Open the Windows Device Manager and locate the "Human Interface Devices" section c. Locate "American Power Conversion USB UPS" under the HID section. d. Right-click "American Power Conversion USB UPS" and select "Update driver..." e. (Abbreviated) Do not allow Windows to search for a driver, specify one yourself. Depending on your version of Windows, the exact sequence of dialogs and options is different, but essentially you need to get to the list of devices with the "Have Disk..." button. When you get there, choose "Have Disk..." f. Browse to "C:\apcupsd\driver" and hit Open g. Select "American Power Conversion USB UPS (Apcupsd)" and hit Next. h. The driver should be installed. i. If you examine the Device Manager tree again, you should see a "LibUSB-Win32 Devices" section, under which is listed "American Power Conversion USB UPS (Apcupsd)". You should NOT see "HID UPS Battery" under the "Batteries" section. Future plugging/unplugging of the UPS will be handled automatically. The driver only needs to be installed once. To UNINSTALL the driver and return to the Windows standard driver, go into Device Manager and do an "Update Driver..." on "American Power Conversion USB UPS (Apcupsd)". Select the "American Power Conversion USB UPS (Microsoft)" driver from the list. After that you should be back where you started. The "Batteries -> HID UPS Battery" entry should be back and the LibUSB section should be gone. WINDOWS 98, 98SE, ME a. Plug in your USB UPS and wait for Windows to recognize it. b. Open the Windows Device Manager and locate the "Human Interface Devices" section c. Locate "USB Human Interface Device" under the HID section. d. Right-click "USB Human Interface Device" and select "Properties" e. Select the "Driver" tab and click the "Update Driver..." button. f. (Abbreviated) Do not allow Windows to search for a driver, specify one yourself. Depending on your version of Windows, the exact sequence of dialogs and options is different, but essentially you need to get to the list of devices with the "Have Disk..." button. When you get there, choose "Have Disk..." g. Browse to "C:\apcupsd\driver" and hit Open h. Select "American Power Conversion USB UPS (Apcupsd)" and hit Next. i. The driver should be installed. j. If you examine the Device Manager tree again, you should see a "LibUSB-Win32 Devices" section, under which is listed "American Power Conversion USB UPS (Apcupsd)". Future plugging/unplugging of the UPS will be handled automatically. The driver only needs to be installed once. To UNINSTALL the driver and return to the Windows standard driver, go into Device Manager and do an "Update Driver..." on "American Power Conversion USB UPS (Apcupsd)". Select the "USB Human Interface Device" driver from the list. After that you should be back where you started. The "HID" -> "USB Human Interface Device" entry should be back and the LibUSB section should be gone. apcupsd-3.14.14/platforms/mingw/installer/000077500000000000000000000000001274230402600204505ustar00rootroot00000000000000apcupsd-3.14.14/platforms/mingw/installer/Apctray.ini000066400000000000000000000005621274230402600225570ustar00rootroot00000000000000[Settings] NumFields=2 BackEnabled=0 [Field 1] Type=Label Left=10 Right=-10 Top=10 Bottom=26 Text=Check this box to install the Apctray status icon in the system tray. The icon will be present for all users who log into this machine. [Field 2] Type=checkbox Text=Install icon in System Tray Left=10 Right=-10 Top=35 Bottom=45 State=1 Flags=NOTIFY apcupsd-3.14.14/platforms/mingw/installer/DrvSetup.nsh000066400000000000000000000067331274230402600227470ustar00rootroot00000000000000; ; Written by Kuba Ober ; Copyright (c) 2004 Kuba Ober ; ; Permission is hereby granted, free of charge, to any person obtaining a ; copy of this software and associated documentation files (the "Software"), ; to deal in the Software without restriction, including without limitation ; the rights to use, copy, modify, merge, publish, distribute, sublicense, ; and/or sell copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following conditions: ; ; The above copyright notice and this permission notice shall be included in ; all copies or substantial portions of the Software. ; ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ; DEALINGS IN THE SOFTWARE. ; ; U S A G E ; ; Push "c:\program files\yoursoftware\driver" ; -- the directory of the .inf file ; Push "c:\program files\yoursoftware\driver\driver.inf" ; -- the filepath of the .inf file (directory + filename) ; Push "USB\VID_1234&PID_5678" ; -- the HID (Hardware ID) of your device ; Call InstallUpgradeDriver ; ; Your driver (minimally the .inf and .sys files) should already by installed ; by your NSIS script. ; ; Typically, you would put the driver either in $INSTDIR or $INSTDIR\Driver ; It's up to you, of course. ; ; The driver (i.e. .inf, .sys and related files) must be present for the ; lifetime of your application, you shouldn't remove them after calling ; this function! ; ; You DON'T want to put the driver in any of system directories. Windows ; will do it when the device is first plugged in. !define InstallUpgradeDriver '!insertmacro "_installUpgradeDriverConstructor"' !macro _installUpgradeDriverConstructor PATH INF HID Push "${PATH}" Push "${INF}" Push "${HID}" Call InstallUpgradeDriver !macroend ; BOOL UpdateDriverForPlugAndPlayDevices(HWND, PSTR, PSTR, DWORD, PBOOL); !define sysUpdateDriverForPlugAndPlayDevices "newdev::UpdateDriverForPlugAndPlayDevices(i, t, t, i, *i) i" ; the masked value of ERROR_NO_SUCH_DEVINST is 523 !define ERROR_NO_SUCH_DEVINST -536870389 !define INSTALLFLAG_FORCE 1 Function InstallUpgradeDriver Pop $R0 ; HID Pop $R1 ; INFPATH Pop $R2 ; INFDIR ; Check Windows version ${If} ${AtLeastWin2000} Goto lbl_upgrade ${EndIf} DetailPrint "This version of Windows does not support driver updates." Goto lbl_done ; Upgrade the driver if the device is already plugged in lbl_upgrade: System::Get '${sysUpdateDriverForPlugAndPlayDevices}' Pop $0 StrCmp $0 'error' lbl_noapi DetailPrint "Updating the USB driver..." ; 0, HID, INFPATH, 0, 0 Push $INSTDIR ; Otherwise this function will swallow it, dunno why System::Call '${sysUpdateDriverForPlugAndPlayDevices}?e (0, R0, R1, ${INSTALLFLAG_FORCE}, 0) .r0' Pop $1 ; last error Pop $INSTDIR IntCmp $0 1 lbl_done IntCmp $1 ${ERROR_NO_SUCH_DEVINST} lbl_notplugged DetailPrint "Driver update failed: ($0,$1)" Goto lbl_done lbl_notplugged: DetailPrint "The device is not plugged in, cannot update the driver." Goto lbl_done lbl_noapi: DetailPrint "This version of Windows does not support driver updates." lbl_done: FunctionEnd apcupsd-3.14.14/platforms/mingw/installer/EditApcupsdConf.ini000066400000000000000000000004041274230402600241620ustar00rootroot00000000000000[Settings] NumFields=2 [Field 1] Type=Label Left=10 Right=-10 Top=10 Bottom=74 Text=Actual text set at runtime [Field 2] Type=checkbox Text=Edit client configuration file (apcupsd.conf) Left=10 Right=-10 Top=95 Bottom=105 State=1 Flags= apcupsd-3.14.14/platforms/mingw/installer/InstallService.ini000066400000000000000000000011401274230402600240740ustar00rootroot00000000000000[Settings] NumFields=4 BackEnabled=0 [Field 1] Type=Label Left=10 Right=-10 Top=10 Bottom=26 Text=Check this box to install Apcupsd as a service so it will automatically start each time this machine boots. Uncheck the box if you plan to start Apcupsd by hand. [Field 2] Type=checkbox Text=Install Apcupsd as a Service Left=10 Right=-10 Top=35 Bottom=45 State=1 Flags= [Field 3] Type=Label Left=10 Right=-10 Top=74 Bottom=90 Text=Check this box to start Apcupsd now. [Field 4] Type=checkbox Text=Start Apcupsd now Left=10 Right=-10 Top=91 Bottom=101 State=1 Flags= apcupsd-3.14.14/platforms/mingw/installer/StrReplace.nsh000066400000000000000000000031571274230402600232340ustar00rootroot00000000000000; StrReplace ; Replaces all ocurrences of a given needle within a haystack with another string ; Written by dandaman32 Var STR_REPLACE_VAR_0 Var STR_REPLACE_VAR_1 Var STR_REPLACE_VAR_2 Var STR_REPLACE_VAR_3 Var STR_REPLACE_VAR_4 Var STR_REPLACE_VAR_5 Var STR_REPLACE_VAR_6 Var STR_REPLACE_VAR_7 Var STR_REPLACE_VAR_8 Function StrReplace Exch $STR_REPLACE_VAR_2 Exch 1 Exch $STR_REPLACE_VAR_1 Exch 2 Exch $STR_REPLACE_VAR_0 StrCpy $STR_REPLACE_VAR_3 -1 StrLen $STR_REPLACE_VAR_4 $STR_REPLACE_VAR_1 StrLen $STR_REPLACE_VAR_6 $STR_REPLACE_VAR_0 loop: IntOp $STR_REPLACE_VAR_3 $STR_REPLACE_VAR_3 + 1 StrCpy $STR_REPLACE_VAR_5 $STR_REPLACE_VAR_0 $STR_REPLACE_VAR_4 $STR_REPLACE_VAR_3 StrCmp $STR_REPLACE_VAR_5 $STR_REPLACE_VAR_1 found StrCmp $STR_REPLACE_VAR_3 $STR_REPLACE_VAR_6 done Goto loop found: StrCpy $STR_REPLACE_VAR_5 $STR_REPLACE_VAR_0 $STR_REPLACE_VAR_3 IntOp $STR_REPLACE_VAR_8 $STR_REPLACE_VAR_3 + $STR_REPLACE_VAR_4 StrCpy $STR_REPLACE_VAR_7 $STR_REPLACE_VAR_0 "" $STR_REPLACE_VAR_8 StrCpy $STR_REPLACE_VAR_0 $STR_REPLACE_VAR_5$STR_REPLACE_VAR_2$STR_REPLACE_VAR_7 StrLen $STR_REPLACE_VAR_6 $STR_REPLACE_VAR_0 Goto loop done: Pop $STR_REPLACE_VAR_1 ; Prevent "invalid opcode" errors and keep the Pop $STR_REPLACE_VAR_1 ; stack as it was before the function was called Exch $STR_REPLACE_VAR_0 FunctionEnd !macro _strReplaceConstructor OUT NEEDLE NEEDLE2 HAYSTACK Push "${HAYSTACK}" Push "${NEEDLE}" Push "${NEEDLE2}" Call StrReplace Pop "${OUT}" !macroend !define StrReplace '!insertmacro "_strReplaceConstructor"' apcupsd-3.14.14/platforms/mingw/installer/params.nsh000066400000000000000000000041761274230402600224550ustar00rootroot00000000000000; ; -- written by Alexis de Valence -- ; GetONEParameter ; Usage: ; Push 3 ; to get the 3rd parameter of the command line ; Call GetONEParameter ; Pop $R0 ; saves the result in $R0 ; returns an empty string if not found Function GetONEParameter Exch $R0 Push $R1 Push $R2 Push $R3 Push $R4 Push $R5 Push $R6 ; init variables IntOp $R5 $R0 + 1 StrCpy $R2 0 StrCpy $R4 1 StrCpy $R6 0 loop3: ; looking for a char that's not a space IntOp $R2 $R2 + 1 StrCpy $R0 $CMDLINE 1 $R2 StrCmp $R0 " " loop3 StrCpy $R3 $R2 ; found the begining of the current parameter loop: ; scanning for the end of the current parameter StrCpy $R0 $CMDLINE 1 $R2 StrCmp $R0 " " loop2 StrCmp $R0 "" last IntOp $R2 $R2 + 1 Goto loop last: ; there will be no other parameter to extract StrCpy $R6 1 loop2: ; found the end of the current parameter IntCmp $R4 $R5 0 NextParam end StrCpy $R6 1 ; to quit after this process IntOp $R1 $R2 - $R3 ;number of letter of current parameter StrCpy $R0 $CMDLINE $R1 $R3 ; stores the result in R0 NextParam: IntCmp $R6 1 end ; leave if found or if not enough parameters ; process the next parameter IntOp $R4 $R4 + 1 Goto loop3 end: Pop $R6 ; restore R0 - R6 to their initial value Pop $R5 Pop $R4 Pop $R3 Pop $R2 Pop $R1 Exch $R0 ;Puts the result on the stack FunctionEnd ; -- written by Michel Meyers -- ; ParameterGiven - checks first 9 parameters on the command line ; Usage: ; Push "/parameter" ; to check command line for /parameter ; Call ParameterGiven ; Pop $R0 ; saves the result in $R0 (result = true or false) Function ParameterGiven Exch $R0 Push $R1 Push $R2 Push $R3 StrCpy $R1 0 StrCpy $R3 0 loopme: StrCmp $R1 9 AllChecked IntOp $R1 $R1 + 1 Push $R1 Call GetONEParameter Pop $R2 ; saves the result in $R2 StrCmp $R0 $R2 Found Goto loopme Found: StrCpy $R3 1 Goto loopme AllChecked: Exch $R3 FunctionEnd apcupsd-3.14.14/platforms/mingw/installer/winapcupsd.nsi000066400000000000000000000476651274230402600233620ustar00rootroot00000000000000; winapcupsd.nsi ; ; Adapted by Kern Sibbald for apcupsd from Bacula code ; Further modified by Adam Kropelin ; ; ; Basics ; Name "Apcupsd" OutFile "winapcupsd-${VERSION}.exe" SetCompressor lzma InstallDir "c:\apcupsd" ; ; Include files ; !include "MUI.nsh" !include "LogicLib.nsh" !include "StrReplace.nsh" !include "WinVer.nsh" !include "DrvSetup.nsh" !include "FileFunc.nsh" ; Global variables Var ExistingConfig Var MainInstalled Var TrayInstalled Var OrigInstDir ; Paths !define WINDIR ${TOPDIR}/src/win32 ; Icon indexes in shell32.dll !define START_ICON_INDEX 137 !define STOP_ICON_INDEX 131 !define CONFIG_ICON_INDEX 21 !define HELP_ICON_INDEX 23 !define MANUAL_ICON_INDEX 23 ; ; Pull in pages ; !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE ${TOPDIR}/COPYING !insertmacro MUI_PAGE_COMPONENTS !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES Page custom EditApcupsdConfEnter EditApcupsdConfExit "" Page custom InstallServiceEnter InstallServiceExit "" Page custom ApctrayEnter ApctrayExit "" !define MUI_FINISHPAGE_SHOWREADME !define MUI_FINISHPAGE_SHOWREADME_TEXT "View the ReleaseNotes" !define MUI_FINISHPAGE_SHOWREADME_FUNCTION "ShowReadme" !define MUI_FINISHPAGE_LINK "Visit Apcupsd Website" !define MUI_FINISHPAGE_LINK_LOCATION "http://www.apcupsd.org" !define MUI_PAGE_CUSTOMFUNCTION_SHOW DisableBackButton !insertmacro MUI_PAGE_FINISH !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_UNPAGE_FINISH !define MUI_ABORTWARNING !insertmacro MUI_LANGUAGE "English" DirText "Setup will install Apcupsd ${VERSION} to the directory \ specified below." ; Disable back button !define FINISH_BUTTON_ID 3 Function DisableBackButton GetDlgItem $R1 $HWNDPARENT ${FINISH_BUTTON_ID} EnableWindow $R1 0 FunctionEnd ; Post-process apcupsd.conf.in by replacing @FOO@ tokens ; with proper values. Function PostProcConfig FileOpen $0 "$INSTDIR\etc\apcupsd\apcupsd.conf.in" "r" FileOpen $1 "$INSTDIR\etc\apcupsd\apcupsd.conf.new" "w" ClearErrors FileRead $0 $2 ${DoUntil} ${Errors} ${StrReplace} $2 "@VERSION@" "${VERSION}" $2 ${StrReplace} $2 "@sysconfdir@" "$INSTDIR\etc\apcupsd" $2 ${StrReplace} $2 "@PWRFAILDIR@" "$INSTDIR\etc\apcupsd" $2 ${StrReplace} $2 "@LOGDIR@" "$INSTDIR\etc\apcupsd" $2 ${StrReplace} $2 "@nologdir@" "$INSTDIR\etc\apcupsd" $2 FileWrite $1 $2 FileRead $0 $2 ${Loop} FileClose $0 FileClose $1 Delete "$INSTDIR\etc\apcupsd\apcupsd.conf.in" FunctionEnd Function ShowReadme ExecShell "open" "$INSTDIR\ReleaseNotes.txt" FunctionEnd Function EditApcupsdConfEnter ; Skip this page if config file was preexisting ${If} $ExistingConfig == 1 Abort ${EndIf} ; Also skip if apcupsd main package was not installed ${If} $MainInstalled != 1 Abort ${EndIf} ; Configure header text and instantiate the page !insertmacro MUI_HEADER_TEXT "Edit Configuration File" "Configure Apcupsd for your UPS." !insertmacro MUI_INSTALLOPTIONS_INITDIALOG "EditApcupsdConf.ini" Pop $R0 ;HWND of dialog ; Set contents of text field !insertmacro MUI_INSTALLOPTIONS_READ $R0 "EditApcupsdConf.ini" "Field 1" "HWND" SendMessage $R0 ${WM_SETTEXT} 0 \ "STR:The default configuration is suitable for UPSes connected with a USB cable. \ All other types of connections require editing the client configuration file, \ apcupsd.conf.$\r$\r\ Please edit $INSTDIR\etc\apcupsd\apcupsd.conf to fit your installation. \ When you click the Next button, Wordpad will open to allow you to do this.$\r$\r\ Be sure to save your changes before closing Wordpad and before continuing \ with the installation." ; Display the page !insertmacro MUI_INSTALLOPTIONS_SHOW FunctionEnd Function EditApcupsdConfExit ; Launch wordpad to edit apcupsd.conf if checkbox is checked !insertmacro MUI_INSTALLOPTIONS_READ $R1 "EditApcupsdConf.ini" "Field 2" "State" ${If} $R1 == 1 ExecWait 'notepad "$INSTDIR\etc\apcupsd\apcupsd.conf"' ${EndIf} FunctionEnd Function InstallServiceEnter ; Skip if apcupsd main package was not installed ${If} $MainInstalled != 1 Abort ${EndIf} ; Configure header text and instantiate the page !insertmacro MUI_HEADER_TEXT "Install/Start Service" "Install Apcupsd Service and start it." !insertmacro MUI_INSTALLOPTIONS_DISPLAY "InstallService.ini" FunctionEnd Function InstallServiceExit ; Create Start Menu Directory CreateDirectory "$SMPROGRAMS\Apcupsd" ; Create start menu link for configuring apcupsd CreateShortCut "$SMPROGRAMS\Apcupsd\Edit Configuration File.lnk" "notepad" "$INSTDIR\etc\apcupsd\apcupsd.conf" "$SYSDIR\shell32.dll" ${CONFIG_ICON_INDEX} ; If installed as a service already, remove it ReadRegDWORD $R0 HKLM "Software\Apcupsd" "InstalledService" ${If} $R0 == 1 ExecWait '"$INSTDIR\bin\apcupsd.exe" /quiet /remove' Sleep 1000 ${EndIf} ; Install as service and create start menu shortcuts !insertmacro MUI_INSTALLOPTIONS_READ $R1 "InstallService.ini" "Field 2" "State" ${If} $R1 == 1 ; Install service ExecWait '"$INSTDIR\bin\apcupsd.exe" /install' ${If} ${IsNT} ; Installed as a service and we're on NT CreateShortCut "$SMPROGRAMS\Apcupsd\Start Apcupsd.lnk" "$SYSDIR\net.exe" "start apcupsd" "$SYSDIR\shell32.dll" ${START_ICON_INDEX} CreateShortCut "$SMPROGRAMS\Apcupsd\Stop Apcupsd.lnk" "$SYSDIR\net.exe" "stop apcupsd" "$SYSDIR\shell32.dll" ${STOP_ICON_INDEX} ${Else} ; Installed as a service, but not on NT CreateShortCut "$SMPROGRAMS\Apcupsd\Start Apcupsd.lnk" "$INSTDIR\bin\apcupsd.exe" "/service" "$SYSDIR\shell32.dll" ${START_ICON_INDEX} CreateShortCut "$SMPROGRAMS\Apcupsd\Stop Apcupsd.lnk" "$INSTDIR\bin\apcupsd.exe" "/kill" "$SYSDIR\shell32.dll" ${STOP_ICON_INDEX} ${EndIf} ${Else} ; Not installed as a service CreateShortCut "$SMPROGRAMS\Apcupsd\Start Apcupsd.lnk" "$INSTDIR\bin\apcupsd.exe" "" "$SYSDIR\shell32.dll" ${START_ICON_INDEX} CreateShortCut "$SMPROGRAMS\Apcupsd\Stop Apcupsd.lnk" "$INSTDIR\bin\apcupsd.exe" "/kill" "$SYSDIR\shell32.dll" ${STOP_ICON_INDEX} ${EndIf} ; Start Apcupsd now, if so requested !insertmacro MUI_INSTALLOPTIONS_READ $R2 "InstallService.ini" "Field 4" "State" ${If} $R2 == 1 ExecShell "" "$SMPROGRAMS\Apcupsd\Start Apcupsd.lnk" "" SW_HIDE ${Endif} FunctionEnd Function ApctrayEnter ; Skip if apctray package was not installed ${If} $TrayInstalled != 1 Abort ${EndIf} ; If Apctray is already configured to start automatically, start it now ; and skip this page ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "Apctray" ${If} $R0 != "" Exec $R0 Abort ${EndIf} ; Configure header text and instantiate the page !insertmacro MUI_HEADER_TEXT "Configure Tray Icon" "Configure Apctray icon for your preferences." !insertmacro MUI_INSTALLOPTIONS_DISPLAY "Apctray.ini" FunctionEnd Function ApctrayExit ; We get called when checkbox changes or next button is pressed ; Figure out which this is. !insertmacro MUI_INSTALLOPTIONS_READ $R1 "Apctray.ini" "Settings" "State" ${If} $R1 == 2 ; Return to the page Abort ${EndIf} ; Regular exit due to Next button press... ; (Un)Install apctray !insertmacro MUI_INSTALLOPTIONS_READ $R1 "Apctray.ini" "Field 2" "State" ${If} $R1 == 1 ; Install and start ExecWait '"$INSTDIR\bin\apctray.exe" $R0 /install' Exec '"$INSTDIR\bin\apctray.exe" $R0' ${EndIf} FunctionEnd Section "-Startup" SetShellVarContext all ; Check for existing config file ${If} ${FileExists} "$INSTDIR\etc\apcupsd\apcupsd.conf" StrCpy $ExistingConfig 1 ${Else} StrCpy $ExistingConfig 0 ${EndIf} ; Save the new install path in the registry WriteRegStr HKLM "Software\Apcupsd\" "InstDir" "$INSTDIR" ; Create base installation directory CreateDirectory "$INSTDIR" ; Install common files SetOutPath "$INSTDIR" File COPYING.txt File ChangeLog.txt File ReleaseNotes.txt ; Clean up old non-txt versions of these files Delete /REBOOTOK "$INSTDIR\COPYING" Delete /REBOOTOK "$INSTDIR\ChangeLog" Delete /REBOOTOK "$INSTDIR\ReleaseNotes" SectionEnd Section "Apcupsd Service" SecService ; We're installing the main package StrCpy $MainInstalled 1 ; Shutdown any apcupsd or apctray that might be running ExecWait '"$OrigInstDir\bin\apctray.exe" /kill' ExecWait '"$OrigInstDir\bin\apcupsd.exe" /kill' DetailPrint "Waiting for apcupsd and apctray to exit..." Sleep 3000 ; Create installation directories CreateDirectory "$INSTDIR\bin" CreateDirectory "$INSTDIR\driver" CreateDirectory "$INSTDIR\etc" CreateDirectory "$INSTDIR\etc\apcupsd" CreateDirectory "c:\tmp" ; ; NOTE: If you add new files here, be sure to remove them ; in the uninstaller! ; SetOutPath "$INSTDIR\bin" File ${CROSSTOOLS}\mingw32\mingw32\bin\mingwm10.dll File ${DEPKGS}\libroot\lib\pthreadGCE.dll File ${TOPDIR}\src\apcupsd.exe File ${TOPDIR}\src\smtp.exe File ${TOPDIR}\src\apcaccess.exe File ${TOPDIR}\src\apctest.exe File ${WINDIR}\popup.exe File ${WINDIR}\shutdown.exe File ${WINDIR}\email.exe File ${WINDIR}\background.exe SetOutPath "$INSTDIR\driver" File ${TOPDIR}\platforms\mingw\winusb\install.txt File ${TOPDIR}\platforms\mingw\winusb\apcupsd.inf File ${TOPDIR}\platforms\mingw\winusb\apcupsd.cat SetOutPath "$INSTDIR\driver\i386" File ${DEPKGS}\winddk\redist\wdf\x86\*.dll File ${DEPKGS}\winddk\redist\winusb\x86\*.dll SetOutPath "$INSTDIR\driver\amd64" File ${DEPKGS}\winddk\redist\wdf\amd64\*.dll File ${DEPKGS}\winddk\redist\winusb\amd64\*.dll SetOutPath "$INSTDIR\etc\apcupsd" File ${TOPDIR}\platforms\mingw\apccontrol.bat File ${TOPDIR}\platforms\mingw\apcupsd.conf.in File /oname=onbattery.vbs.example ${TOPDIR}\platforms\mingw\onbattery.vbs File /oname=offbattery.vbs.example ${TOPDIR}\platforms\mingw\offbattery.vbs File /oname=commfailure.vbs.example ${TOPDIR}\platforms\mingw\commfailure.vbs ; Post-process apcupsd.conf.in into apcupsd.conf.new Call PostProcConfig ; Rename apcupsd.conf.new to apcupsd.conf if it does not already exist ${Unless} ${FileExists} "$INSTDIR\etc\apcupsd\apcupsd.conf" Rename apcupsd.conf.new apcupsd.conf ${EndUnless} SectionEnd Section "Tray Applet" SecApctray ; We're installing the apctray package StrCpy $TrayInstalled 1 ; Shut down any running copy ${If} $MainInstalled != 1 ExecWait '"$OrigInstDir\bin\apctray.exe" /kill' DetailPrint "Waiting for apctray to exit..." Sleep 2000 ${EndIf} ; Install files CreateDirectory "$INSTDIR" CreateDirectory "$INSTDIR\bin" SetOutPath "$INSTDIR\bin" File ${WINDIR}\apctray.exe File ${CROSSTOOLS}\mingw32\mingw32\bin\mingwm10.dll File ${DEPKGS}\libroot\lib\pthreadGCE.dll ; Create start menu link for apctray CreateDirectory "$SMPROGRAMS\Apcupsd" CreateShortCut "$SMPROGRAMS\Apcupsd\Apctray.lnk" "$INSTDIR\bin\apctray.exe" SectionEnd Section "Multimon CGI programs" SecMultimon CreateDirectory "$INSTDIR" CreateDirectory "$INSTDIR\cgi" CreateDirectory "$INSTDIR\etc" CreateDirectory "$INSTDIR\etc\apcupsd" SetOutPath "$INSTDIR\cgi" File ${TOPDIR}\src\cgi\multimon.cgi File ${TOPDIR}\src\cgi\upsstats.cgi File ${TOPDIR}\src\cgi\upsfstats.cgi File ${TOPDIR}\src\cgi\upsimage.cgi File ${CROSSTOOLS}\mingw32\mingw32\bin\mingwm10.dll SetOutPath "$INSTDIR\etc\apcupsd" File ${TOPDIR}\src\cgi\apcupsd.css File /oname=hosts.conf.new ${TOPDIR}\platforms\etc\hosts.conf ; Rename hosts.conf.new to hosts.conf if it does not already exist ${Unless} ${FileExists} "$INSTDIR\etc\apcupsd\hosts.conf" Rename hosts.conf.new hosts.conf ${EndUnless} SectionEnd Section "USB Driver" SecUsbDrv ${InstallUpgradeDriver} "$INSTDIR\driver" $INSTDIR\driver\apcupsd.inf "USB\VID_051d&PID_0002" ${If} $0 != 1 MessageBox MB_OK|MB_ICONEXCLAMATION \ "The USB driver could not be automatically installed. You can ignore \ this if you do not plan to use Apcupsd with a USB UPS. Otherwise, please \ see $INSTDIR\driver\install.txt for instructions on installing the \ USB driver by hand." ${EndIf} SectionEnd Section "Documentation" SecDoc SetOutPath "$INSTDIR\doc" CreateDirectory "$INSTDIR\doc" File ${TOPDIR}\doc\manual\manual.html File ${TOPDIR}\doc\manual\*.png File *.man.txt ; Create Start Menu entry CreateDirectory "$SMPROGRAMS\Apcupsd\Documentation" CreateShortCut "$SMPROGRAMS\Apcupsd\Documentation\Apcupsd User Manual.lnk" "$INSTDIR\doc\manual.html" "" "$SYSDIR\shell32.dll" ${MANUAL_ICON_INDEX} CreateShortCut "$SMPROGRAMS\Apcupsd\Documentation\apcupsd Reference.lnk" "$INSTDIR\doc\apcupsd.man.txt" "" "$SYSDIR\shell32.dll" ${HELP_ICON_INDEX} CreateShortCut "$SMPROGRAMS\Apcupsd\Documentation\apcaccess Reference.lnk" "$INSTDIR\doc\apcaccess.man.txt" "" "$SYSDIR\shell32.dll" ${HELP_ICON_INDEX} CreateShortCut "$SMPROGRAMS\Apcupsd\Documentation\apctest Reference.lnk" "$INSTDIR\doc\apctest.man.txt" "" "$SYSDIR\shell32.dll" ${HELP_ICON_INDEX} CreateShortCut "$SMPROGRAMS\Apcupsd\Documentation\apccontrol Reference.lnk" "$INSTDIR\doc\apccontrol.man.txt" "" "$SYSDIR\shell32.dll" ${HELP_ICON_INDEX} CreateShortCut "$SMPROGRAMS\Apcupsd\Documentation\Configuration Reference.lnk" "$INSTDIR\doc\apcupsd.conf.man.txt" "" "$SYSDIR\shell32.dll" ${HELP_ICON_INDEX} SectionEnd !define UNINSTREG "Software\Microsoft\Windows\CurrentVersion\Uninstall\Apcupsd" Section "-Finish" ; Write the uninstall keys for Windows & create Start Menu entry SetShellVarContext all WriteRegStr HKLM "${UNINSTREG}" "DisplayName" "Apcupsd" WriteRegStr HKLM "${UNINSTREG}" "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "${UNINSTREG}" "DisplayVersion" "${VERSION}" WriteRegStr HKLM "${UNINSTREG}" "Version" "${VERSION}" WriteRegStr HKLM "${UNINSTREG}" "Publisher" "apcupsd.org" WriteRegStr HKLM "${UNINSTREG}" "URLInfoAbout" "http://apcupsd.org" WriteRegDWord HKLM "${UNINSTREG}" "NoRepair" 1 WriteRegDWord HKLM "${UNINSTREG}" "NoModify" 1 ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 IntFmt $0 "0x%08X" $0 WriteRegDWORD HKLM "${UNINSTREG}" "EstimatedSize" "$0" WriteUninstaller "$INSTDIR\Uninstall.exe" CreateShortCut "$SMPROGRAMS\Apcupsd\Uninstall Apcupsd.lnk" "$INSTDIR\Uninstall.exe" SectionEnd ; ; Initialization Callback ; Function .onInit ; If there is an existing installation, default INSTDIR to location of that ; install. Otherwise, if user did not specify INSTDIR on cmdline (using /D), ; default it to %SystemDrive%\apcupsd. ReadRegStr $0 HKLM "Software\Apcupsd" "InstDir" ${If} $0 != '' StrCpy $INSTDIR $0 ${ElseIf} "$INSTDIR" == '' ReadEnvStr $0 SystemDrive ${If} $0 == '' StrCpy $0 'c:' ${EndIf} StrCpy $INSTDIR $0\apcupsd ${EndIf} ; Preserve a copy of original install dir string before user possibly ; changes it. This will be used to run existing apcupsd and apctray exes ; with /kill switch to shut down running instances. StrCpy $OrigInstDir $INSTDIR ; Extract custom pages. Automatically deleted when installer exits. !insertmacro MUI_INSTALLOPTIONS_EXTRACT "EditApcupsdConf.ini" !insertmacro MUI_INSTALLOPTIONS_EXTRACT "InstallService.ini" !insertmacro MUI_INSTALLOPTIONS_EXTRACT "Apctray.ini" ; Nothing installed yet StrCpy $MainInstalled 0 StrCpy $TrayInstalled 0 FunctionEnd ; ; Extra Page descriptions ; LangString DESC_SecService ${LANG_ENGLISH} "Install Apcupsd on this system." LangString DESC_SecApctray ${LANG_ENGLISH} "Install Apctray. Shows status icon in the system tray." LangString DESC_SecUsbDrv ${LANG_ENGLISH} "Install USB driver. Required if you have a USB UPS. Not available on Windows 95 or NT." LangString DESC_SecDoc ${LANG_ENGLISH} "Install Documentation on this system." LangString DESC_SecMultimon ${LANG_ENGLISH} "Install MULTIMON cgi scripts for web-based monitoring." !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecService} $(DESC_SecService) !insertmacro MUI_DESCRIPTION_TEXT ${SecApctray} $(DESC_SecApctray) !insertmacro MUI_DESCRIPTION_TEXT ${SecMultimon} $(DESC_SecMultimon) !insertmacro MUI_DESCRIPTION_TEXT ${SecUsbDrv} $(DESC_SecUsbDrv) !insertmacro MUI_DESCRIPTION_TEXT ${SecDoc} $(DESC_SecDoc) !insertmacro MUI_FUNCTION_DESCRIPTION_END ; Uninstall section UninstallText "This will uninstall Apcupsd. Hit next to continue." Section "Uninstall" ; Shutdown any apcupsd & apctray that might be running ExecWait '"$INSTDIR\bin\apctray.exe" /kill' ExecWait '"$INSTDIR\bin\apcupsd.exe" /kill' DetailPrint "Waiting for apcupsd and apctray to exit..." Sleep 3000 ; Remove apcuspd service, if needed ReadRegDWORD $R0 HKLM "Software\Apcupsd" "InstalledService" ${If} $R0 == 1 ExecWait '"$INSTDIR\bin\apcupsd.exe" /quiet /remove' ${EndIf} ; Remove apctray autorun, if needed ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "Apctray" ${If} $R0 != "" ExecWait '"$INSTDIR\bin\apctray.exe" /quiet /remove' ${EndIf} ; remove registry keys DeleteRegKey HKLM "${UNINSTREG}" DeleteRegKey HKLM "Software\Apcupsd" DeleteRegValue HKLM "Software\Microsoft\Windows\CurrentVersion\Run" "Apctray" ; remove start menu items SetShellVarContext all RMDir /r /REBOOTOK "$SMPROGRAMS\Apcupsd" ; remove files and uninstaller (preserving config for now) Delete /REBOOTOK "$INSTDIR\bin\mingwm10.dll" Delete /REBOOTOK "$INSTDIR\bin\pthreadGCE.dll" Delete /REBOOTOK "$INSTDIR\bin\libusb0.dll" Delete /REBOOTOK "$INSTDIR\bin\apcupsd.exe" Delete /REBOOTOK "$INSTDIR\bin\smtp.exe" Delete /REBOOTOK "$INSTDIR\bin\apcaccess.exe" Delete /REBOOTOK "$INSTDIR\bin\apctest.exe" Delete /REBOOTOK "$INSTDIR\bin\popup.exe" Delete /REBOOTOK "$INSTDIR\bin\shutdown.exe" Delete /REBOOTOK "$INSTDIR\bin\email.exe" Delete /REBOOTOK "$INSTDIR\bin\background.exe" Delete /REBOOTOK "$INSTDIR\bin\apctray.exe" Delete /REBOOTOK "$INSTDIR\driver\libusb0.dll" Delete /REBOOTOK "$INSTDIR\driver\libusb0_x64.dll" Delete /REBOOTOK "$INSTDIR\driver\libusb0.sys" Delete /REBOOTOK "$INSTDIR\driver\libusb0_x64.sys" Delete /REBOOTOK "$INSTDIR\driver\apcupsd.inf" Delete /REBOOTOK "$INSTDIR\driver\apcupsd.cat" Delete /REBOOTOK "$INSTDIR\driver\apcupsd_x64.cat" Delete /REBOOTOK "$INSTDIR\driver\install.txt" Delete /REBOOTOK "$INSTDIR\driver\i386\*.dll" Delete /REBOOTOK "$INSTDIR\driver\amd64\*.dll" Delete /REBOOTOK "$INSTDIR\README*" Delete /REBOOTOK "$INSTDIR\COPYING*" Delete /REBOOTOK "$INSTDIR\ChangeLog*" Delete /REBOOTOK "$INSTDIR\ReleaseNotes*" Delete /REBOOTOK "$INSTDIR\Uninstall.exe" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\apccontrol.bat" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\apcupsd.conf.new" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\hosts.conf.new" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\onbattery.vbs.example" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\offbattery.vbs.example" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\commfailure.vbs.example" Delete /REBOOTOK "$INSTDIR\doc\*" Delete /REBOOTOK "$INSTDIR\cgi\multimon.cgi" Delete /REBOOTOK "$INSTDIR\cgi\upsstats.cgi" Delete /REBOOTOK "$INSTDIR\cgi\upsfstats.cgi" Delete /REBOOTOK "$INSTDIR\cgi\upsimage.cgi" Delete /REBOOTOK "$INSTDIR\cgi\mingwm10.dll" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\apcupsd.css" ; Delete conf if user approves ${If} ${FileExists} "$INSTDIR\etc\apcupsd\apcupsd.conf" ${OrIf} ${FileExists} "$INSTDIR\etc\apcupsd\apcupsd.events" ${If} ${Cmd} 'MessageBox MB_YESNO|MB_ICONQUESTION "Would you like to delete the current configuration and events files?" /SD IDYES IDYES' Delete /REBOOTOK "$INSTDIR\etc\apcupsd\apcupsd.conf" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\apcupsd.events" Delete /REBOOTOK "$INSTDIR\etc\apcupsd\hosts.conf" ${EndIf} ${EndIf} ; remove directories used RMDir "$INSTDIR\bin" RMDir "$INSTDIR\cgi" RMDir "$INSTDIR\driver\i386" RMDir "$INSTDIR\driver\amd64" RMDir "$INSTDIR\driver" RMDir "$INSTDIR\etc\apcupsd" RMDir "$INSTDIR\etc" RMDir "$INSTDIR\doc" RMDir "$INSTDIR\examples" RMDir "$INSTDIR" RMDir "C:\tmp" SectionEnd ; eof apcupsd-3.14.14/platforms/mingw/offbattery.vbs000077500000000000000000000100241274230402600213340ustar00rootroot00000000000000'///Wriiten by Ed Dondlinger 1/23/2009 - edondlinger@thepylegroup.com /// '/// MODIFY THE VARIABLES LISTED BELOW IN THE "USER VARIABLES" SECTION. '/// THEN RENAME FILE WITHOUT THE ".example" SUFFIX. '///Comment out the next line when testing, then change back when done. /// On Error Resume Next Dim Get_Status Dim oShell set oShell = CreateObject("WScript.Shell") '/// Get APCUPS Status Report /// set Get_Status = oShell.exec("%comspec% /c c:\Progra~1\apcupsd\bin\apcaccess.exe status") UPS_Status = Get_Status.StdOut.readall '/// Get Time Zone info from local windows registry /// atb = "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation\StandardName" TZInfo = oShell.RegRead(atb) 'XXXXXXXXXXXXXXXXXXXX USER VARIABLES XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX MyLocation = "Home" MyEmailSubject = "POWER RESTORED at: " & MyLocation MyEmailFromAddress = "xxx@zzz.com" 'you could also use this format to display the common name: """Me"" " MyEmailToAddress = "xxx@zzz.com" MyTextBody = "The power has been restored at: " & MyLocation & " and the UPS is running on utility power." & _ vbCRLF & "Reported by the APCUPS Server at: " & dateAdd("H",0,Now) & " " & _ TZInfo & vbcrlf & vbcrlf & UPS_Status MySMTPServer = "smtp.gmail.com" 'or use a IP address i.e. "10.x.x.x" MyMailServerUserName = "UName" MyMailServerPW = "Password" MySMTPServerPort = 465 MySMTPServerSSL = True 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX '////////// Email Section ////////// '*** NOTE: MSDN CDO Library can be referenced at: http://msdn.microsoft.com/en-us/library/ms872853(EXCHG.65).aspx Const cdoSendUsingPickup = 1 'Send message using the local SMTP service pickup directory. Const cdoSendUsingPort = 2 'Send the message using the network (SMTP over the network). Const cdoSendUsingExchange = 3 'Send the message using MS Exchange Mail Server. Const cdoAnonymous = 0 'Do not authenticate Const cdoBasic = 1 'basic (clear-text) authentication Const cdoNTLM = 2 'NTLM Const cdoURL = "http://schemas.microsoft.com/cdo/configuration/" Set objMessage = CreateObject("CDO.Message") '/// Set the message properties. /// With objMessage .Subject = MyEmailSubject .From = MyEmailFromAddress .To = MyEmailToAddress .TextBody = MyTextBody 'Set Mail Importance level, you can set [high,normal,low] .fields.Item("urn:schemas:mailheader:importance").Value = "high" 'Set Mail priority level, you can set [1=urgent, 0=normal, -1=nonurgent] .fields.Item("urn:schemas:mailheader:priority").Value = 1 .fields.Update() End with '/// This section provides the configuration information for the remote SMTP server. /// with objMessage.Configuration.Fields 'Send Using method (1 = local smtp, 2 = remote network smtp, 3 = MS Exchange) .Item(cdoURL & "sendusing") = 2 'Name or IP of Remote SMTP Server .Item(cdoURL & "smtpserver") = MySMTPServer 'Type of authentication, NONE, Basic (Base64 encoded), NTLM .Item(cdoURL & "smtpauthenticate") = cdoBasic 'Your UserID on the SMTP server .Item(cdoURL & "sendusername") = MyMailServerUserName 'Your password on the SMTP server .Item(cdoURL & "sendpassword") = MyMailServerPW 'Server port (typically 25) .Item(cdoURL & "smtpserverport") = MySMTPServerPort 'Use SSL for the connection (False or True) .Item(cdoURL & "smtpusessl") = MySMTPServerSSL 'Connection Timeout in seconds (the maximum time CDO will try to establish a connection to the SMTP server) .Item(cdoURL & "smtpconnectiontimeout") = 60 'Update the config. .Update end with '/// Send the message /// objMessage.Send '/// Clean-up /// Set objMessage = nothing set oShell = nothing set Get_Status = nothing '/// Exit with a 0 error level to ensure the apccontrol.bat continues /// Wscript.Quit 0apcupsd-3.14.14/platforms/mingw/onbattery.vbs000077500000000000000000000100171274230402600212000ustar00rootroot00000000000000'///Wriiten by Ed Dondlinger 1/23/2009 - edondlinger@thepylegroup.com /// '/// MODIFY THE VARIABLES LISTED BELOW IN THE "USER VARIABLES" SECTION. '/// THEN RENAME FILE WITHOUT THE ".example" SUFFIX. '///Comment out the next line when testing, then change back when done. /// On Error Resume Next Dim Get_Status Dim oShell set oShell = CreateObject("WScript.Shell") '/// Get APCUPS Status Report /// set Get_Status = oShell.exec("%comspec% /c c:\Progra~1\apcupsd\bin\apcaccess.exe status") UPS_Status = Get_Status.StdOut.readall '/// Get Time Zone info from local windows registry /// atb = "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\TimeZoneInformation\StandardName" TZInfo = oShell.RegRead(atb) 'XXXXXXXXXXXXXXXXXXXX USER VARIABLES XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX MyLocation = "Home" MyEmailSubject = "POWER FAILURE at: " & MyLocation MyEmailFromAddress = "xxx@zzz.com" 'you could also use this format to display the common name: """Me"" " MyEmailToAddress = "xxx@zzz.com" MyTextBody = "The utility power has failed at " & MyLocation & " and the UPS is running on batteries." & _ vbCRLF & "Reported by the APCUPS Server at: " & dateAdd("H",0,Now) & " " & _ TZInfo & vbcrlf & vbcrlf & UPS_Status MySMTPServer = "smtp.gmail.com" 'or use a IP address i.e. "10.x.x.x" MyMailServerUserName = "UName" MyMailServerPW = "password" MySMTPServerPort = 465 MySMTPServerSSL = True 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXxXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX '////////// Email Section ////////// '*** NOTE: MSDN CDO Library can be referenced at: http://msdn.microsoft.com/en-us/library/ms872853(EXCHG.65).aspx Const cdoSendUsingPickup = 1 'Send message using the local SMTP service pickup directory. Const cdoSendUsingPort = 2 'Send the message using the network (SMTP over the network). Const cdoSendUsingExchange = 3 'Send the message using MS Exchange Mail Server. Const cdoAnonymous = 0 'Do not authenticate Const cdoBasic = 1 'basic (clear-text) authentication Const cdoNTLM = 2 'NTLM Const cdoURL = "http://schemas.microsoft.com/cdo/configuration/" Set objMessage = CreateObject("CDO.Message") '/// Set the message properties. /// With objMessage .Subject = MyEmailSubject .From = MyEmailFromAddress .To = MyEmailToAddress .TextBody = MyTextBody 'Set Mail Importance level, you can set [high,normal,low] .fields.Item("urn:schemas:mailheader:importance").Value = "high" 'Set Mail priority level, you can set [1=urgent, 0=normal, -1=nonurgent] .fields.Item("urn:schemas:mailheader:priority").Value = 1 .fields.Update() End with '/// This section provides the configuration information for the remote SMTP server. /// with objMessage.Configuration.Fields 'Send Using method (1 = local smtp, 2 = remote network smtp, 3 = MS Exchange) .Item(cdoURL & "sendusing") = 2 'Name or IP of Remote SMTP Server .Item(cdoURL & "smtpserver") = MySMTPServer 'Type of authentication, NONE, Basic (Base64 encoded), NTLM .Item(cdoURL & "smtpauthenticate") = cdoBasic 'Your UserID on the SMTP server .Item(cdoURL & "sendusername") = MyMailServerUserName 'Your password on the SMTP server .Item(cdoURL & "sendpassword") = MyMailServerPW 'Server port (typically 25) .Item(cdoURL & "smtpserverport") = MySMTPServerPort 'Use SSL for the connection (False or True) .Item(cdoURL & "smtpusessl") = MySMTPServerSSL 'Connection Timeout in seconds (the maximum time CDO will try to establish a connection to the SMTP server) .Item(cdoURL & "smtpconnectiontimeout") = 60 'Update the config. .Update end with '/// Send the message /// objMessage.Send '/// Clean-up /// Set objMessage = nothing set oShell = nothing set Get_Status = nothing '/// Exit with a 0 error level to ensure the apccontrol.bat continues /// Wscript.Quit 0apcupsd-3.14.14/platforms/mingw/winusb/000077500000000000000000000000001274230402600177625ustar00rootroot00000000000000apcupsd-3.14.14/platforms/mingw/winusb/apcupsd.cat000066400000000000000000000254101274230402600221140ustar00rootroot000000000000000+ *H *0*1 0 +0h +7 Y0U0  +7 [A-Mњ\y 150120073313Z0 +7 00R056399FAACB9FC49F3CF78BFC3D9F2F463E5012E1_0M +71?0=0 +70 0!0 +cIxc.0R +7 1D0BFile0wdfcoinstaller01009.dll0V +7 1H0F OSAttr02:5.1,2:5.2,2:6.0,2:6.10b +7 1T0RL{C689AAB8-8E78-11D0-8C47-00C04FC295EE}0R7D665D64A923FD5C1CC7A2A8B48E4A63C06DAEFA1]0M +71?0=0 +70 0!0 +}f]d#\ǢJcm0P +7 1B0@File.winusbcoinstaller2.dll0V +7 1H0F OSAttr02:5.1,2:5.2,2:6.0,2:6.10b +7 1T0RL{C689AAB8-8E78-11D0-8C47-00C04FC295EE}0R97D0A58BF744016DB52A699C26327D636E9B8B181?0: +7 1,0*Fileapcupsd.inf0E +717050 +70!0 +ХDm*i&2}cn0V +7 1H0F OSAttr02:5.1,2:5.2,2:6.0,2:6.10b +7 1T0RL{DE351A42-8E59-11D0-8C47-00C04FC295EE}0RA0D03C75D36F1FF227B262BC3AA08777E73512F01_0M +71?0=0 +70 0!0 +0Erm96ʹO1ab@.YxwRkP)͓e`a"2Q0 lzb'_om8tL酲}J&VϒSth` t)bGS.;p~%00U0U00UF>􅛰j0GU @0>0<U 0402+&https://www.globalsign.com/repository/03U,0*0(&$"http://crl.globalsign.net/root.crl0U#0`{fE ʉP/}4K0  *H N^VFI19(A o֙.@U? vӆ4U:ǂ墨P{R:x\K:$ڬX0۰^1Hp:^V= 헝ۥ'85D ;mj ((̈] ;!/5l4E35~˚EM?يen~e,1'6H&o;Mvy5-QԳDFdOc1Kc0(0 /N5\0  *H 0W1 0 UBE10U GlobalSign nv-sa10U Root CA10UGlobalSign Root CA0 110413100000Z 190413100000Z0Q1 0 UBE10U GlobalSign nv-sa1'0%UGlobalSign CodeSigning CA - G20"0  *H 0 O&r6SB^Xъ(CFo~(DP u]< D jEJ7`n?mFj '(W(Pa9U%R<׳$1Iբӑ> PI8ҨȌ+'~*ީ8"\avD ~/mt@;sT00U0U00Unض>t]̀/Pz0GU @0>0<U 0402+&https://www.globalsign.com/repository/03U,0*0(&$"http://crl.globalsign.net/root.crl0U% 0 +0U#0`{fE ʉP/}4K0  *H "\= pŎ 6\ZǨDIQ%z ;ϹB&;lmhڍmSMT8aȂvi2 1lɞ X/H~HCXsT1x ;p=~׽/* kȾh^]mxҾIx4Ⱦ{<>!?`izjJ(,0^&rBmdքKgA|x 㭨-~OkZF,p-I`rRpC^Fh$J %$$0Z0B!`E| 'F 0  *H 0Q1 0 UBE10U GlobalSign nv-sa1'0%UGlobalSign CodeSigning CA - G20 120703082439Z 150803082439Z0'1 0 USI10UJernej Simoncic0"0  *H 0 >Tߕe)SwG8]N))ZNGU>o'SUB8wa!Cv2 M8-5n#f|/ߔޥB}hvPP3Ȉ[T$n|K5ϠLtʔEUy8xC7S%`*qq2ICޭuq ʴF6(ً9ql(XXV3">݁N5>w]ěT0P0U0LU E0C0A +220402+&https://www.globalsign.com/repository/0 U00U% 0 +0>U705031/-http://crl.globalsign.com/gs/gscodesigng2.crl0P+D0B0@+04http://secure.globalsign.com/cacert/gscodesigng2.crt0U@'ĴOPQb0U#0nض>t]̀/Pz0  *H  NFP5 D|2r!իc9NE}2zblI)*E-|C}1j*$Mj S鲬eԼ]vn ~ݧ] Ӱ5TÐ߮Dm.umo m9L]с􅛰j0  *H 1.XWdAu<^,^re<]+ĹU Cɲ(SG9d40v!=2n<; ˸*&Y&4! 8EĬma\00g a k0  *H 01 0 UUS10U Washington10URedmond10U Microsoft Corporation1)0'U Microsoft Code Verification Root0 060523170051Z 160523171051Z0W1 0 UBE10U GlobalSign nv-sa10U Root CA10UGlobalSign Root CA0"0  *H 0 晍ΣO~%kH*cgfH+)e-˫Lp= 0OԌPP.R}m50^CsAj㲉:V98o:-7o캬j<ߋ%笼bE1ݤ rxC̺9]Z^FQ3զXgfXʭ!ښn t(_M]%i%TDÛ)3<S*'3.|XmN_󚝌Q:Z\/5T5R34:j :e3N&I끒M2K#3qk漷lA:q3Pt;]>L&86 cyԮ/a6JK3rA~F9{uAYBGpwKF#rտiX<\FՁneYw2ddSɠ(*l8сΘ@,C&_D0S /z`'RB7(yH0] R-g f(o$a100g0Q1 0 UBE10U GlobalSign nv-sa1'0%UGlobalSign CodeSigning CA - G2!`E| 'F 0 +o0 +7 100 *H  1  +7 0 +7 10  +70# *H  1OK&n҆i~9z0  *H N6B;c cywpls vŻDY9yv_AXoVQd?5Gj'Q!,ʡ(%#^XDΦj;8`oʚo';ɤ%XG{ݳHUc妑= !y뢑UYM_"rIO o|ko6, Xovb`WX4IhT$y F#7Z}Ρ0 *H  100h0R1 0 UBE10U GlobalSign nv-sa1(0&UGlobalSign Timestamping CA - G2!@\X+ME0 +0 *H  1  *H 0 *H  1 150120073612Z0# *H  1WՍ jyiMֺ\98_0 *H   1000PѨ9^.1+;4;0l0VT0R1 0 UBE10U GlobalSign nv-sa1(0&UGlobalSign Timestamping CA - G2!@\X+ME0  *H " {,u>^;PÞڸ568T75(RCn$na7nyy>JG:]H%{g#=F8لcMjCZ͟6/c{gc$mwŏ/t<*0&B'g}샃^S%Tqvӿ^.w>M(1!wWcS%ƙ w-)L>)T$%5LA?8נ"SY0apcupsd-3.14.14/platforms/mingw/winusb/apcupsd.inf000066400000000000000000000117021274230402600221200ustar00rootroot00000000000000[Version] Signature = "$Windows NT$" Class = Battery ClassGuid={72631e54-78a4-11d0-bcf7-00aa00b7b32a} Provider = %ProviderName% DriverVer = 01/19/2015,1.0.0.1 CatalogFile = apcupsd.cat ; ================== Class section ================== [ClassInstall32] Addreg=MyDeviceClassReg [MyDeviceClassReg] HKR,,,0,%ClassName% HKR,,Icon,,-1 ; ========== Manufacturer/Models sections =========== [Manufacturer] %ProviderName% = Apcupsd_WinUSB,NTx86,NTamd64,NTia64 [Apcupsd_WinUSB.NTx86] ; Older APC UPSes use PID 0x0002 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0002 ; AP9620 Legacy Communications Card and newer UPSes use PID 0x0003 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0003 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0004 ; Early production and prototype units of AP9620 erroneously have ; 0x0001 or 0xffff %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0001 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_ffff ; An SMX750 appears to use PID 5 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0005 ; The HP T1500 G3 has been shown to work well with apcupsd %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_03f0&PID_1fe3 ; APC and Schneider VIDs (for future use, as of Jan 2015) %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c801 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c802 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c803 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c804 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c805 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c801 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c802 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c803 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c804 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c805 [Apcupsd_WinUSB.NTamd64] ; Older APC UPSes use PID 0x0002 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0002 ; AP9620 Legacy Communications Card and newer UPSes use PID 0x0003 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0003 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0004 ; Early production and prototype units of AP9620 erroneously have ; 0x0001 or 0xffff %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0001 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_ffff ; An SMX750 appears to use PID 5 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_0005 ; The HP T1500 G3 has been shown to work well with apcupsd %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_03f0&PID_1fe3 ; APC and Schneider VIDs (for future use, as of Jan 2015) %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c801 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c802 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c803 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c804 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_051d&PID_c805 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c801 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c802 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c803 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c804 %USB\MyDevice.DeviceDesc% =ApcupsdUSBDriver, USB\VID_16de&PID_c805 ; =================== Installation =================== [ApcupsdUSBDriver] Include=winusb.inf Needs=WINUSB.NT [ApcupsdUSBDriver.Services] Include=winusb.inf AddService=WinUSB,0x00000002,WinUSB_ServiceInstall [WinUSB_ServiceInstall] DisplayName = %WinUSB_SvcDesc% ServiceType = 1 StartType = 3 ErrorControl = 1 ServiceBinary = %12%\WinUSB.sys [ApcupsdUSBDriver.Wdf] KmdfService=WINUSB, WinApcupsdUSBDriver [WinApcupsdUSBDriver] KmdfLibraryVersion=1.9 [ApcupsdUSBDriver.HW] AddReg=Dev_AddReg [Dev_AddReg] HKR,,DeviceInterfaceGUIDs,0x10000,"{8c534620-f7e6-11de-8a39-0800200c9a66}" [ApcupsdUSBDriver.CoInstallers] AddReg=CoInstallers_AddReg CopyFiles=CoInstallers_CopyFiles [CoInstallers_AddReg] HKR,,CoInstallers32,0x00010000,"WdfCoInstaller01009.dll,WdfCoInstaller","WinUSBCoInstaller2.dll" [CoInstallers_CopyFiles] WinUSBCoInstaller2.dll WdfCoInstaller01009.dll [DestinationDirs] CoInstallers_CopyFiles=11 ; ================= Source Media Section ===================== [SourceDisksNames] 1 = %DISK_NAME%,,,\i386 2 = %DISK_NAME%,,,\amd64 [SourceDisksFiles.x86] WinUSBCoInstaller2.dll=1 WdfCoInstaller01009.dll=1 [SourceDisksFiles.amd64] WinUSBCoInstaller2.dll=2 WdfCoInstaller01009.dll=2 ; =================== Strings =================== [Strings] ProviderName="Apcupsd (www.apcupsd.org)" USB\MyDevice.DeviceDesc="American Power Conversion USB UPS (Apcupsd)" WinUSB_SvcDesc="WinUSB" DISK_NAME="Apcupsd Driver Folder" ClassName="Battery" apcupsd-3.14.14/platforms/mingw/winusb/install.txt000066400000000000000000000111301274230402600221650ustar00rootroot00000000000000INSTALLING APCUPSD WINDOWS USB DRIVER USB connected UPSes on Windows require a special driver. In most cases, this driver is automatically installed when you install Apcupsd. However, in some cases, you will need to install the driver by hand. SUPPORTED OPERATING SYSTEMS The USB driver supports the following operating systems: - Windows XP Service Pack 2 - Windows 2003 Service Service Pack 2 - Windows Vista (including 64 bit) - Windows 7 (including 64 bit) - Windows 2008 Server (including 64 bit) - Windows 8 (including 64 bit) - Windows 8.1 (including 64 bit) Notably, Windows 2000, Windows 98, and Windows ME are NOT supported. TROUBLESHOOTING - If the driver fails to start and Windows gives an "Error Code 10" this is most likely because you updated the driver on "Batteries / HID UPS Battery" instead of "Human Interface Devices / American Power Conversion USB UPS". To fix this, uninstall the driver from the device that is giving the error code, then do an update driver on the correct device. - The driver INF has now been signed with Authenticode thanks to Jernej Simoncic . During driver installation you will be asked to approve the signature. INSTALLATION Follow these instructions to install the Apcupsd USB driver. If you have the old LibUSB driver installed already, go to the UPGRADE section below instead. a. Plug in your USB UPS and wait for Windows to recognize it. b. Open the Windows Device Manager and locate the "Human Interface Devices" section c. Locate "American Power Conversion USB UPS" under the HID section. d. Right-click "American Power Conversion USB UPS" and select "Update driver..." e. (Abbreviated) Do not allow Windows to search for a driver, specify one yourself. Depending on your version of Windows, the exact sequence of dialogs and options is different, but essentially you need to get to the list of devices with the "Have Disk..." button. When you get there, choose "Have Disk..." f. Browse to "C:\apcupsd\driver" and hit Open g. Select "American Power Conversion USB UPS (Apcupsd)" and hit Next. h. The driver should be installed. i. If you examine the Device Manager tree again, you should see "American Power Conversion USB UPS (Apcupsd)" listed in the "Batteries" section. Future plugging/unplugging of the UPS will be handled automatically. The driver only needs to be installed once. To UNINSTALL the driver and return to the Windows standard driver, go into Device Manager and do an "Update Driver..." on "American Power Conversion USB UPS (Apcupsd)". Select the "American Power Conversion USB UPS (Microsoft)" driver from the list. After that you should be back where you started. The "Batteries -> HID UPS Battery" entry should be back. UPGRADING FROM LIBUSB DRIVER If you are upgrading from the older Apcupsd libusb-based driver, follow these instructions. a. Plug in your USB UPS and wait for Windows to recognize it. b. Open the Windows Device Manager and locate the section entitled "LibUSB-Win32 Devices". c. Locate "American Power Conversion USB UPS (Apcupsd)" d. Right-click "American Power Conversion USB UPS" and select "Update driver..." e. (Abbreviated) Do not allow Windows to search for a driver, specify one yourself. Depending on your version of Windows, the exact sequence of dialogs and options is different, but essentially you need to get to the list of devices with the "Have Disk..." button. When you get there, choose "Have Disk..." f. Browse to "C:\apcupsd\driver" and hit Open g. Select "American Power Conversion USB UPS (Apcupsd)" and hit Next. h. The driver should be installed. i. If you examine the Device Manager tree again, you should see "American Power Conversion USB UPS (Apcupsd)" listed in the "Batteries" section. The "LibUSB-Win32 Devices" section should be gone. Future plugging/unplugging of the UPS will be handled automatically. The driver only needs to be installed once. To UNINSTALL the driver and return to the Windows standard driver, go into Device Manager and do an "Update Driver..." on "American Power Conversion USB UPS (Apcupsd)". Select the "American Power Conversion USB UPS (Microsoft)" driver from the list. After the standard "Batteries -> HID UPS Battery" entry should be back. apcupsd-3.14.14/platforms/netbsd/000077500000000000000000000000001274230402600166115ustar00rootroot00000000000000apcupsd-3.14.14/platforms/netbsd/Makefile000066400000000000000000000046441274230402600202610ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-netbsd all-uninstall: uninstall-netbsd install-netbsd: $(call DISTINST,NetBSD) $(call MKDIR,/etc) $(call INSTPROG,744,apcupsd,/etc/rc.apcupsd) $(VV)-today="`date +%Y%m%d%H%M`"; \ grep -q '# TAG_APCUPSD' /etc/rc.shutdown; \ if [ $$? -ne 0 ]; then \ echo " PATCH $(DESTDIR)/etc/rc.shutdown"; \ rm -f $(DESTDIR)/etc/rc.shutdown.$$today; \ cp -p /etc/rc.shutdown $(DESTDIR)/etc/rc.shutdown.$$today; \ ( echo "# Do not remove the 'TAG_APCUPSD' text, below"; \ echo "if [ -f $(PWRFAILDIR)/powerfail ]; then # TAG_APCUPSD";\ echo " powerdown=YES # TAG_APCUPSD"; \ echo " echo '' # TAG_APCUPSD"; \ echo " echo 'Please ensure that the UPS has powered off before' # TAG_APCUPSD"; \ echo " echo 'rebooting. Otherwise, the UPS may cut the power' # TAG_APCUPSD"; \ echo " echo 'during the reboot.' # TAG_APCUPSD"; \ echo " echo '' # TAG_APCUPSD"; \ echo "fi # TAG_APCUPSD"; \ ) >> $(DESTDIR)/etc/rc.shutdown; \ fi; \ grep -q /etc/rc.apcupsd /etc/rc.local; \ if [ $$? -ne 0 ]; then \ echo " PATCH $(DESTDIR)/etc/rc.local"; \ rm -f $(DESTDIR)/etc/rc.local.$$today; \ cp -p /etc/rc.local $(DESTDIR)/etc/rc.local.$$today; \ ( echo "# Start the UPS daemon. Do not remove the 'TAG_APCUPSD' text"; \ echo "# if [ -x /etc/rc.apcupsd ]; then # TAG_APCUPSD"; \ echo "# /etc/rc.apcupsd start # TAG_APCUPSD"; \ echo "# fi # TAG_APCUPSD"; \ ) >> $(DESTDIR)/etc/rc.local; \ echo ""; \ ( echo "While /etc/rc.local has been patched to run apcupsd,";\ echo "the commands are currently commented out. You should"; \ echo "examine the $(sysconfdir)/apcupsd.conf file to ensure"; \ echo "that it is suitable for your site. Then run"; \ echo "/etc/rc.apcupsd manually to ensure sane operation."; \ echo "Once you are satisfied, uncomment the appropriate"; \ echo "lines in /etc/rc.local" ) | /usr/bin/fmt; \ fi uninstall-netbsd: $(call DISTUNINST,NetBSD) -$(call UNINST,/etc/rc.apcupsd) $(VV)-today="`date +%Y%m%d%H%M`"; \ for f in $(DESTDIR)/etc/rc.local $(DESTDIR)/etc/rc.shutdown; do \ grep -q '# TAG_APCUPSD' $$f; \ if [ $$? -eq 0 ]; then \ echo " PATCH $$f"; \ rm -f $$f.$$today; \ cp -p $$f $$f.$$today; \ $(SED) -e '/TAG_APCUPSD/d;' \ < $$f.$$today > $$f; \ chmod 644 $$f; \ fi; \ done apcupsd-3.14.14/platforms/netbsd/apcupsd.in000066400000000000000000000017071274230402600206050ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid APCLOCK=@PIDDIR@/apcupsd.lock DISTVER="@DISTVER@" return=" Done." case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting apcupsd power management" @sbindir@/apcupsd --kill-on-powerfail || return=" Failed." touch $APCLOCK echo -e "$return" ;; stop) echo -n "Stopping apcupsd power management" if [ -f ${APCPID} ]; then THEPID=`cat ${APCPID}` kill ${THEPID} || return=" Failed." rm -f ${APCPID} else return=" Failed." fi rm -f $APCLOCK echo -e "$return" ;; restart) $0 stop $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/openbsd/000077500000000000000000000000001274230402600167645ustar00rootroot00000000000000apcupsd-3.14.14/platforms/openbsd/Makefile000066400000000000000000000046521274230402600204330ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-openbsd all-uninstall: uninstall-openbsd install-openbsd: $(call DISTINST,OpenBSD) $(call MKDIR,/etc) $(call INSTPROG,744,apcupsd,/etc/rc.apcupsd) $(VV)-today="`date +%Y%m%d%H%M`"; \ grep -q '# TAG_APCUPSD' /etc/rc.shutdown; \ if [ $$? -ne 0 ]; then \ echo " PATCH $(DESTDIR)/etc/rc.shutdown"; \ rm -f $(DESTDIR)/etc/rc.shutdown.$$today; \ cp -p /etc/rc.shutdown $(DESTDIR)/etc/rc.shutdown.$$today; \ ( echo "# Do not remove the 'TAG_APCUPSD' text, below"; \ echo "if [ -f $(PWRFAILDIR)/powerfail ]; then # TAG_APCUPSD";\ echo " powerdown=YES # TAG_APCUPSD"; \ echo " echo '' # TAG_APCUPSD"; \ echo " echo 'Please ensure that the UPS has powered off before' # TAG_APCUPSD"; \ echo " echo 'rebooting. Otherwise, the UPS may cut the power' # TAG_APCUPSD"; \ echo " echo 'during the reboot.' # TAG_APCUPSD"; \ echo " echo '' # TAG_APCUPSD"; \ echo "fi # TAG_APCUPSD"; \ ) >> $(DESTDIR)/etc/rc.shutdown; \ fi; \ grep -q /etc/rc.apcupsd /etc/rc.local; \ if [ $$? -ne 0 ]; then \ echo " PATCH $(DESTDIR)/etc/rc.local"; \ rm -f $(DESTDIR)/etc/rc.local.$$today; \ cp -p /etc/rc.local $(DESTDIR)/etc/rc.local.$$today; \ ( echo "# Start the UPS daemon. Do not remove the 'TAG_APCUPSD' text"; \ echo "# if [ -x /etc/rc.apcupsd ]; then # TAG_APCUPSD"; \ echo "# /etc/rc.apcupsd start # TAG_APCUPSD"; \ echo "# fi # TAG_APCUPSD"; \ ) >> $(DESTDIR)/etc/rc.local; \ echo ""; \ ( echo "While /etc/rc.local has been patched to run apcupsd,";\ echo "the commands are currently commented out. You should"; \ echo "examine the $(sysconfdir)/apcupsd.conf file to ensure"; \ echo "that it is suitable for your site. Then run"; \ echo "/etc/rc.apcupsd manually to ensure sane operation."; \ echo "Once you are satisfied, uncomment the appropriate"; \ echo "lines in /etc/rc.local" ) | /usr/bin/fmt; \ fi uninstall-openbsd: $(call DISTUNINST,OpenBSD) -$(call UNINST,/etc/rc.apcupsd) $(VV)-today="`date +%Y%m%d%H%M`"; \ for f in $(DESTDIR)/etc/rc.local $(DESTDIR)/etc/rc.shutdown; do \ grep -q '# TAG_APCUPSD' $$f; \ if [ $$? -eq 0 ]; then \ echo " PATCH $$f"; \ rm -f $$f.$$today; \ cp -p $$f $$f.$$today; \ $(SED) -e '/TAG_APCUPSD/d;' \ < $$f.$$today > $$f; \ chmod 644 $$f; \ fi; \ done apcupsd-3.14.14/platforms/openbsd/README000066400000000000000000000140651274230402600176520ustar00rootroot00000000000000Distribution: OpenBSD Maintainer: Devin Reade $Id: README,v 1.2 2004-08-26 09:20:07 kerns Exp $ ======================================================= MAKE SURE YOU READ THE "IMPORTANT NOTE" SECTION, BELOW! ======================================================= Your DEVICE should normally be set to /dev/cuaa0 for the first serial port. Overview -------- The OpenBSD distribution of apcupsd operates a bit differently from the other distributions; the shutdown sequence (once the UPS can no longer sustain the dependent servers) has been modified. For most operating systems, the following sequence occurs: 1. mains power loss 2. warning messages are sent from the master at various intervals 3. minimum battery level or max run time is reached 4. apcupsd invokes the control script with 'doshutdown' argument, then exits 5. the control script initiates a system shutdown 6. as part of the system shutdown sequence, apcupsd is called in a "one shot" mode in order to send a message to the UPS telling it to kill the power in a configurable number of seconds 7. the system finishes its halt sequence 8. the UPS kills power to the system until mains power returns During the OpenBSD shutdown sequence, however, the second "one shot" call to apcupsd will fail because after the shutdown sequence has started, the serial port cannot be reopened. Therefore, the OpenBSD sequence has been modified to the following: 1. mains power loss 2. warning messages are sent from the master at various intervals 3. minimum battery level or max run time is reached 4. apcupsd sends message to UPS to power off after a configurable number of seconds 5. apcupsd invokes the control script with 'doshutdown' argument, then exits 5. the control script initiates a system shutdown 6. the system finishes its halt sequence 7. the UPS kills power to the system until mains power returns vvvvvvvvvvvvvv --> IMPORTANT NOTE <-- ^^^^^^^^^^^^^^ Because of the modified shutdown sequence, the default number of seconds that the UPS will run after being given its "power off" message may not be sufficient to properly halt the system. Therefore, it is critical that this interval be verified and probably modified. See the section below on "Modifying the Power Off Interval" for details on how this is done. As a consequence of the above, another difference is that once the shutdown sequence has been initiated, it cannot be cancelled even if mains power returns. This has implications for a hetrogeneous environment: If the OpenBSD server is running in apcupsd networked mode with another machine such as a Linux server, it is possible for the former to complete the shutdown and the latter to cancel it. Depending on which machine is the master and which is the slave, this could either result in one machine remaining in a halted state indefinitely, or (worse) the other machine losing power while not in a halted state. Therefore, it is strongly recommended that when running in network mode, that shutdown cancellation be disabled on all machines. To date, the OpenBSD code has only been tested in standalone mode and as a net master, with a Slackware Linux machine as the net slave. Modifying the Power Off Interval -------------------------------- [The information in this section is already available in the primary apcupsd documents -- this section merely makes things a bit more explicit in the context of OpenBSD.] Once you have run the commands configure make make install in the apcupsd source tree and verified the values (most notably, the "DEVICE" value) in the /etc/apcupsd/apcupsd.conf file, you should be able to manually start apcupsd by executing the following: /etc/rc.apcupsd start After the daemon starts, you should be able to get your current configuration by issuing the command: /etc/rc.apcupsd status Since the daemon prints status to stderr, you may have to redirect the output to a file in order to view it. It will also take a few seconds before you can get the status. If you either see a message about "UPS not ready to report" or if the BCHARGE value is "000.0 Percent", then you have to wait a few seconds a try again. Once you have good status data, look for the value of the "DSHUTD" parameter. This is the interval between the time the UPS receives a shutdown request and the time the power is killed. If the value is 20 (seconds), then you have to modify it. My OpenBSD machine shuts down fairly quickly, so I find a value of 180 seconds to be suitable. Note that there are only a few discrete values which are permissable. See the apcupsd.conf file for details. If you need to change this value, edit the "SLEEP" parameter in your apcupsd.conf file and set it to the appropriate value. That parameter is grouped, in the configuration file, with a bunch of other parameters used for programming the UPS EEPROM. Make sure all the other parameters are commented out (you only want to change one at a time). Before you can reset the EPROM, shut down the running apcupsd: /etc/rc.apcupsd stop Make sure there are no apcupsd processes left running before you continue: ps auxww | grep apc Now you can modifiy the EPROM with the new configuration file: /sbin/apcupsd -c That will take about 30 or 45 seconds to complete. You should see messages regarding which EPROM values have been changed (and what the old values were). Read them to ensure that you didn't change something that you hadn't intended to change. You should probably ensure that the "MINUTES" parameter in your configuration file makes sense given the value you selected for "SLEEP" -- chances are that you want "MINUTES" to be at least as long as "SLEEP". Remember that one is specified in minutes, and the other in seconds. The "MINUTES" parameter is used whenever apcupsd starts up; you don't need to reset the EPROM when "MINUTES" is changed. apcupsd-3.14.14/platforms/openbsd/apccontrol.in000066400000000000000000000062121274230402600214610ustar00rootroot00000000000000#!@SCRIPTSHELL@ # # Copyright (C) 1999-2002 Riccardo Facchetti # # for apcupsd release @VERSION@ (@DATE@) - @DISTNAME@ # # @configure_input@ # # # These variables are needed for set up the autoconf other variables. # prefix=@prefix@ exec_prefix=@exec_prefix@ APCPID=@PIDDIR@/apcupsd.pid APCUPSD=@sbindir@/apcupsd SHUTDOWN=@SHUTDOWN@ SCRIPTSHELL=@SCRIPTSHELL@ SCRIPTDIR=@sysconfdir@ export SYSADMIN=root export APCUPSD_MAIL="@APCUPSD_MAIL@" if [ -f $SCRIPTDIR/config ]; then . $SCRIPTDIR/config ; fi # # This piece is to substitute the default behaviour with your own script, # perl, or C program. # You can customize every single command creating an executable file (may be a # script or a compiled program) and calling it the same as the $1 parameter # passed by apcupsd to this script. # # After executing your script, apccontrol continues with the default action. # If you do not want apccontrol to continue, exit your script with exit # code 99. E.g. "exit 99". # # WARNING: the apccontrol file will be overwritten every time you update your # apcupsd, doing `make install'. Your own customized scripts will _not_ be # overwritten. If you wish to make changes to this file (discouraged), you # should change apccontrol.sh.in and then rerun the configure process. # if [ -f ${SCRIPTDIR}/${1} -a -x ${SCRIPTDIR}/${1} ] then ${SCRIPTDIR}/${1} ${2} ${3} ${4} # exit code 99 means he does not want us to do default action if [ $? = 99 ] ; then exit 0 fi fi case "$1" in killpower) printf "UPS now committed to shut down" | wall # echo "Apccontrol doing: ${APCUPSD} --killpower" # sleep 10 # ${APCUPSD} --killpower ;; commfailure) printf "Communications with UPS lost." | wall ;; commok) printf "Communciations with UPS restored." | wall ;; powerout) ;; onbattery) printf "Power failure. Running on UPS batteries." | wall ;; offbattery) printf "Power has returned..." | wall ;; mainsback) if [ -f @PWRFAILDIR@/powerfail ] ; then printf "Continuing with shutdown." | wall fi ;; failing) printf "UPS battery power exhausted. Doing shutdown.\n" | wall ;; timeout) printf "UPS battery runtime limit exceeded. Doing shutdown.\n" | wall ;; loadlimit) printf "UPS battery discharge limit reached. Doing shutdown.\n" | wall ;; runlimit) printf "UPS battery runtime percent reached. Doing shutdown.\n" \ | wall ;; doreboot) printf "Beginning Reboot Sequence" | wall ${SHUTDOWN} -r now "apcupsd initiated reboot" ;; doshutdown) printf "Beginning Shutdown Sequence" | wall ${SHUTDOWN} -h now "apcupsd initiated shutdown" ;; annoyme) printf "Power problems please logoff." | wall ;; emergency) printf "Emergency Shutdown. Possible UPS battery failure." \ | wall ;; changeme) printf "Emergency! UPS batteries have failed\nChange them NOW" \ | wall ;; remotedown) printf "Remote Shutdown.\nBeginning Shutdown Sequence." | wall ;; startselftest) ;; endselftest) ;; battdetach) ;; battattach) ;; *) echo "Usage: ${0##*/} command" echo " warning: this script is intended to be launched by" echo " apcupsd and should never be launched by users." exit 1 ;; esac apcupsd-3.14.14/platforms/openbsd/apcupsd.in000066400000000000000000000022401274230402600207510ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid DISTVER="@DISTVER@" return=" Done." case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting apcupsd power management" @sbindir@/apcupsd --kill-on-powerfail || return=" Failed." echo -e "$return" ;; stop) echo -n "Stopping apcupsd power management" if [ -f ${APCPID} ]; then THEPID=`cat ${APCPID}` kill ${THEPID} || return=" Failed." rm -f ${APCPID} else return=" Failed." fi echo -e "$return" ;; restart) if [ -f $APCPID ]; then pid="`cat $APCPID`" else pid='' fi $0 stop if [ "x$pid" != "x" ]; then echo "waiting for apcupsd to exit " while true; do ps auxww | awk '{ print $2; }' | egrep -qe "^$pid\$" if [ $? -ne 0 ]; then echo break fi echo -n . sleep 1 done fi $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/qnx/000077500000000000000000000000001274230402600161405ustar00rootroot00000000000000apcupsd-3.14.14/platforms/qnx/Makefile000066400000000000000000000011501274230402600175750ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-qnx all-uninstall: uninstall-qnx install-qnx: $(call DISTINST,QNX) @echo "You have to manually install apcupsd boot script and" @echo "halt script for clean emergency shutdown." @echo "Please contribute your distribution install to apcupsd team." @echo "I'm sorry: you are on your own." uninstall-qnx: $(call DISTUNINST,QNX) @echo "You have to manually uninstall apcupsd boot script and" @echo "halt script." @echo "Please contribute your distribution install to apcupsd team." @echo "I'm sorry: you are on your own." apcupsd-3.14.14/platforms/qnx/apccontrol.in000066400000000000000000000075051274230402600206430ustar00rootroot00000000000000#!@SCRIPTSHELL@ # # Copyright (C) 1999-2002 Riccardo Facchetti # # for apcupsd release @VERSION@ (@DATE@) - @DISTNAME@ # # @configure_input@ # # Note, this is a generic file that can be used by most # systems. If a particular system needs to have something # special, start with this file, and put a copy in the # platform subdirectory. # # # These variables are needed for set up the autoconf other variables. # prefix=@prefix@ exec_prefix=@exec_prefix@ APCPID=@PIDDIR@/apcupsd.pid APCUPSD=@sbindir@/apcupsd SHUTDOWN=@SHUTDOWN@ SCRIPTSHELL=@SCRIPTSHELL@ SCRIPTDIR=@sysconfdir@ WALL=wall export SYSADMIN=root export APCUPSD_MAIL="@APCUPSD_MAIL@" if [ -f $SCRIPTDIR/config ]; then . $SCRIPTDIR/config ; fi # # Concatenate all output from this script to the events file # Note, the following kills the script in a power fail situation # where the disks are mounted read-only. # exec >>@LOGDIR@/apcupsd.events 2>&1 # # This piece is to substitute the default behaviour with your own script, # perl, or C program. # You can customize every single command creating an executable file (may be a # script or a compiled program) and calling it the same as the $1 parameter # passed by apcupsd to this script. # # After executing your script, apccontrol continues with the default action. # If you do not want apccontrol to continue, exit your script with exit # code 99. E.g. "exit 99". # # WARNING: the apccontrol file will be overwritten every time you update your # apcupsd, doing `make install'. Your own customized scripts will _not_ be # overwritten. If you wish to make changes to this file (discouraged), you # should change apccontrol.sh.in and then rerun the configure process. # if [ -f ${SCRIPTDIR}/${1} -a -x ${SCRIPTDIR}/${1} ] then ${SCRIPTDIR}/${1} ${2} ${3} ${4} # exit code 99 means he does not want us to do default action if [ $? = 99 ] ; then exit 0 fi fi case "$1" in killpower) echo "Apccontrol doing: ${APCUPSD} --killpower on UPS ${2}" sleep 10 ${APCUPSD} --killpower echo "Apccontrol has done: ${APCUPSD} --killpower on UPS ${2}" | ${WALL} ;; commfailure) echo "Warning communications lost with UPS ${2}" | ${WALL} ;; commok) echo "Communications restored with UPS ${2}" | ${WALL} ;; # # powerout, onbattery, offbattery, mainsback events occur # in that order. # powerout) ;; onbattery) echo "Power failure on UPS ${2}. Running on batteries." | ${WALL} ;; offbattery) echo "Power has returned on UPS ${2}..." | ${WALL} ;; mainsback) if [ -f @PWRFAILDIR@/powerfail ] ; then printf "Continuing with shutdown." | ${WALL} fi ;; failing) echo "Battery power exhausted on UPS ${2}. Doing shutdown." | ${WALL} ;; timeout) echo "Battery time limit exceeded on UPS ${2}. Doing shutdown." | ${WALL} ;; loadlimit) echo "Remaining battery charge below limit on UPS ${2}. Doing shutdown." | ${WALL} ;; runlimit) echo "Remaining battery runtime below limit on UPS ${2}. Doing shutdown." | ${WALL} ;; doreboot) echo "UPS ${2} initiating Reboot Sequence" | ${WALL} ${SHUTDOWN} ;; doshutdown) echo "UPS ${2} initiated Shutdown Sequence" | ${WALL} ${SHUTDOWN} -b ;; annoyme) echo "Power problems with UPS ${2}. Please logoff." | ${WALL} ;; emergency) echo "Emergency Shutdown. Possible battery failure on UPS ${2}." | ${WALL} ;; changeme) echo "Emergency! Batteries have failed on UPS ${2}. Change them NOW" | ${WALL} ;; remotedown) echo "Remote Shutdown. Beginning Shutdown Sequence." | ${WALL} ;; startselftest) ;; endselftest) ;; battdetach) ;; battattach) ;; *) echo "Usage: ${0##*/} command" echo " warning: this script is intended to be launched by" echo " apcupsd and should never be launched by users." exit 1 ;; esac apcupsd-3.14.14/platforms/qnx/apcupsd.in000066400000000000000000000016671274230402600201410ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid DISTVER="@DISTVER@" return=" Done." case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting apcupsd power management" @sbindir@/apcupsd || return=" Failed." # touch @LOCKDIR@/subsys/apcupsd echo -e "$return" ;; stop) echo -n "Stopping apcupsd power management" if [ -f ${APCPID} ]; then THEPID=`cat ${APCPID}` kill ${THEPID} || return=" Failed." rm -f ${APCPID} else return=" Failed." fi # rm -f @LOCKDIR@/subsys/apcupsd echo -e "$return" ;; restart) $0 stop $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/redhat/000077500000000000000000000000001274230402600166015ustar00rootroot00000000000000apcupsd-3.14.14/platforms/redhat/Makefile000066400000000000000000000037071274230402600202500ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-redhat all-uninstall: uninstall-redhat install-redhat: $(call DISTINST,RedHat) # unlink old rc script (if not doing a DESTDIR install) $(call CHKCFG,del,/etc/rc.d/init.d/apcupsd) # install new rc script $(call MKDIR,/etc/rc.d/init.d) $(call INSTDATA,744,apcupsd,/etc/rc.d/init.d) # link new rc script (if not doing a DESTDIR install) $(call CHKCFG,add,/etc/rc.d/init.d/apcupsd) $(V)if cp -fR /etc/rc.d/init.d/halt $(DESTDIR)/etc/rc.d/init.d/halt.old && \ awk -f awkhaltprog $(DESTDIR)/etc/rc.d/init.d/halt.old >$(DESTDIR)/etc/rc.d/init.d/halt && \ chmod 744 $(DESTDIR)/etc/rc.d/init.d/halt ; then true ; else \ echo "================================================="; \ echo "WARNING: UNABLE TO UPDATE /etc/rc.d/init.d/halt" ; \ echo "You must manually arrange for killpower during OS shutdown." ; \ echo "================================================="; \ fi @echo "=================================================" @echo " " @echo "apcupsd script installation for RedHat $(DISTVER) complete." @echo " " @echo "You should now edit /etc/apcupsd/apcupsd.conf to correspond" @echo "to your setup then start the apcupsd daemon with:" @echo " " @echo "/etc/rc.d/init.d/apcupsd start" @echo " " @echo "thereafter when you reboot, it will be stopped and started" @echo "automatically." @echo " " @echo "Please check that your halt script in:" @echo " /etc/rc.d/init.d/halt" @echo "was properly updated (see installation section of manual)" @echo " " @echo "=================================================" uninstall-redhat: $(call DISTUNINST,RedHat) # unlink old rc script (if not doing a DESTDIR install) -$(call CHKCFG,del,/etc/rc.d/init.d/apcupsd) -$(call UNINST,/etc/rc.d/init.d/apcupsd) -$(call COPY,$(DESTDIR)/etc/rc.d/init.d/halt.old,/etc/rc.d/init.d/halt) -$(call UNINST,/etc/rc.d/init.d/halt.old) apcupsd-3.14.14/platforms/redhat/apcupsd.in000066400000000000000000000022621274230402600205720ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 60 99 # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid # Source function libarary . /etc/rc.d/init.d/functions case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting UPS monitoring:" daemon @sbindir@/apcupsd -f @sysconfdir@/apcupsd.conf RETVAL=$? echo [ $RETVAL -eq 0 ] && touch @LOCKDIR@/subsys/apcupsd ;; stop) echo -n "Shutting down UPS monitoring:" killproc apcupsd echo rm -f $APCPID rm -f @LOCKDIR@/subsys/apcupsd ;; restart|force-reload) $0 stop sleep 15 $0 start ;; reload) echo "$0: reload not implemented" exit 3 ;; status) status apcupsd RETVAL=$? if [ $RETVAL -eq 0 ] then @sbindir@/apcaccess status else exit $RETVAL fi ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0 apcupsd-3.14.14/platforms/redhat/apcupsd.spec.in000066400000000000000000000433611274230402600215300ustar00rootroot00000000000000# Platform configuration # # Select the platform by setting the define below either by command # line arguments, # e.g. rpmbuild -ba --define "build_suse 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define suse 1 # # If you want the gapcmon package, use: # e.g. rpmbuild -ba --define "build_gapcmon 1" --define "build_suse 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define gapcmon 1 # # Note, to build, you need: # Release_Notes-%{version}-%{release}.tar.gz in your # rpm SOURCES directory, and the tar file must contain # Release_Notes-%{version}-%{release}.txt # # basic defines for every build %define _version @VERSION@ %define _release 1 #-------------------------------------------------------------------------- # it should not be necessary to change anything below here for a release # except for patch macros in the setup section if used #-------------------------------------------------------------------------- %define pwrfaildir @PWRFAILDIR@ %define halpolicydir /usr/share/hal/fdi/policy/20thirdparty # third party packagers %define _packager D. Scott Barninger %{?contrib_packager:%define _packager %{contrib_packager}} %define rh7 0 %{?build_rh7:%define rh7 1} %define rh8 0 %{?build_rh8:%define rh8 1} %define rh9 0 %{?build_rh9:%define rh9 1} # all FC releases to date %define fedora_core 0 %{?build_fedora_core:%define fedora_core 1} # RedHat Enterprise and all clones %define rhel3 0 %{?build_rhel3:%define rhel3 1} %define rhel4 0 %{?build_rhel4:%define rhel4 1} %define rhel5 0 %{?build_rhel5:%define rhel5 1} %define rhel6 0 %{?build_rhel6:%define rhel6 1} # SuSE 9.x and 10.x %define suse 0 %{?build_suse:%define suse 1} # Mandrake and Mandriva %define mdk 0 %{?build_mdk:%define mdk 1} %if ! %{suse} %define suse_version 0 %endif %if %{suse} %define initdir /etc/rc.d %else %define initdir /etc/rc.d/init.d %endif # set destination directories for multimon %define cgidir /var/www/cgi-bin %if %{suse} %define cgidir /srv/www/cgi-bin %endif # set ownership of files %define binowner root %define bingroup root %define dataowner apache %define datagroup apache %if %{suse} %define dataowner wwwrun %define datagroup www %endif # should we build gapcmon, requires gtk2 >= 2.4 %define gapcmon 0 %{?build_gapcmon:%define gapcmon 1} Summary: APC UPS Power Control Daemon for Linux Name: apcupsd Version: %{_version} Release: %{_release} Vendor: APC UPS Daemon Team Distribution: The apcupsd Team Packager: %{_packager} URL: http://www.apcupsd.com Source0: http://www.spcupsd.com/%{name}-%{version}.tar.gz Source1: Release_Notes-%{version}-%{release}.tar.gz Group: System Environment/Daemons License: GPL v2 BuildRoot: %{_tmppath}/%{name}-root BuildRequires: gd-devel, ncurses-devel, ghostscript, libstdc++-devel %if %{rh7} BuildRequires: glibc-devel >= 2.2, libjpeg-devel, libpng-devel, zlib-devel, freetype-devel %else BuildRequires: glibc-devel >= 2.3 %endif %if %{gapcmon} BuildRequires: glibc-devel, gtk2-devel >= 2.4, glib2-devel, atk-devel BuildRequires: ORBit2, pango-devel, pkgconfig %endif %if %{suse} && %{gapcmon} BuildRequires: bonobo-activation, freetype2-devel, cairo-devel, fontconfig-devel BuildRequires: gconf2-devel, gnome-vfs2-devel, libpng-devel, xorg-x11-libs BuildRequires: libbonobo-devel, libbonoboui-devel %endif %if %{fedora_core} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif %if %{mdk} && %{gapcmon} BuildRequires: libbonobo2_0-devel, libbonoboui2_0-devel, freetype2-devel, libGConf2_4-devel %endif %if %{rhel4} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif %if %{rhel5} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif %if %{rhel6} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif Provides: apcupsd Obsoletes: apcupsd-std apcupsd-usb Requires: perl, ncurses %if %{rh7} Requires: glibc >= 2.2 %else Requires: glibc >= 2.3 %endif %description Apcupsd can be used for controlling most APC UPSes. During a power failure, apcupsd will inform the users about the power failure and that a shutdown may occur. If power is not restored, a system shutdown will follow when the battery is exausted, a timeout (seconds) expires, or the battery runtime expires based on internal APC calculations determined by power consumption rates. If the power is restored before one of the above shutdown conditions is met, apcupsd will inform users about this fact. Some features depend on what UPS model you have (simple or smart). This package is configured for USB but can be reconfigured for standard serial port UPS models. See the manual. %package multimon Summary: APC UPS Power Control Daemon for Linux Group: Applications/Internet Requires: libstdc++ %if %{fedora_core} || %{suse} || %{mdk} || %{rhel4} || %{rhel5} || %{rhel6} Requires: gd >= 2.0 %else Requires: gd < 2.0 %endif %if %{rh7} Requires: glibc >= 2.2, libjpeg, libpng, zlib, freetype %else Requires: glibc >= 2.3 %endif %description multimon apcupsd Network Monitoring (CGI) Programs which will give you the status of your UPS or UPSes over the network. %if %{gapcmon} %package gapcmon Summary: APC UPS Power Control Daemon for Linux Group: Applications/System Requires: glibc, gtk2 >= 2.4, glib2, atk, libbonobo, libbonoboui, ORBit2, pango %endif %if %{suse} && %{gapcmon} Requires: bonobo-activation, freetype2, cairo, fontconfig, gconf2, gnome-vfs2, libpng, xorg-x11-libs %endif %if %{fedora_core} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{mdk} && %{gapcmon} Requires: freetype2, GConf2 %endif %if %{rhel4} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{rhel5} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{rhel6} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{gapcmon} %description gapcmon A Gnome application to monitor the status of your UPS. %endif # SuSE turns off stripping of binaries by default. In order to get # stripped packages we must generate debug package. RedHat and Mandriva # turn debug packages on by default but strip binaries regardless. %if %{suse} %debug_package %endif %prep %setup -b 1 %build %configure \ --prefix=%{_prefix} \ --sbindir=/sbin \ --sysconfdir=%{_sysconfdir}/apcupsd \ --with-cgi-bin=%{cgidir} \ --enable-cgi \ --enable-net \ --enable-pcnet \ --enable-apcsmart \ --enable-dumb \ --enable-usb \ --enable-modbus-usb \ --enable-snmp \ %if %{gapcmon} --enable-gapcmon \ %endif --with-serial-dev= \ --with-upstype=usb \ --with-halpolicydir=%{halpolicydir} \ --with-upscable=usb make cd examples make hid-ups cd ../ %install [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{initdir} mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/cgi make \ DESTDIR=$RPM_BUILD_ROOT \ install install -m744 platforms/apccontrol \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/apccontrol %if ! %{suse} && ! %{mdk} install -m755 platforms/redhat/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if %{suse} install -m755 platforms/suse/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if %{mdk} install -m755 platforms/mandrake/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if ! %{mdk} rm $RPM_BUILD_ROOT%{initdir}/halt rm $RPM_BUILD_ROOT%{initdir}/halt.old %endif install -m744 examples/hid-ups \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/hid-ups install -m744 examples/make-hiddev \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/make-hiddev %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT rm -f $RPM_BUILD_DIR/Release_Notes-%{version}-%{release}.txt %files %defattr(-,root,root) %{_sysconfdir}/apcupsd/make-hiddev %{_sysconfdir}/apcupsd/hid-ups %{halpolicydir}/80-apcupsd-ups-policy.fdi %doc COPYING DISCLAIMER ReleaseNotes ChangeLog ../Release_Notes-%{version}-%{release}.txt doc/manual/manual.html doc/manual/*.png %dir %{_sysconfdir}/apcupsd %{initdir}/apcupsd %config(noreplace) %{_sysconfdir}/apcupsd/apccontrol %config(noreplace) %{_sysconfdir}/apcupsd/changeme %config(noreplace) %{_sysconfdir}/apcupsd/commfailure %config(noreplace) %{_sysconfdir}/apcupsd/commok %config(noreplace) %{_sysconfdir}/apcupsd/onbattery %config(noreplace) %{_sysconfdir}/apcupsd/offbattery %config(noreplace) %{_sysconfdir}/apcupsd/apcupsd.conf /sbin/* %attr(-,root,man) %{_mandir}/*/* %files multimon %defattr(-,root,root) %dir %{_sysconfdir}/apcupsd %dir %{cgidir} %attr(-,%{dataowner},%{datagroup}) %{_sysconfdir}/apcupsd/apcupsd.css %attr(-,%{binowner},%{bingroup}) %{cgidir}/* %attr(-,%{dataowner},%{datagroup}) %config(noreplace) %{_sysconfdir}/apcupsd/hosts.conf %attr(-,%{dataowner},%{datagroup}) %config(noreplace) %{_sysconfdir}/apcupsd/multimon.conf %if %{gapcmon} %files gapcmon %defattr(-,root,root) %{_prefix}/bin/gapcmon %{_prefix}/share/applications/gapcmon.desktop %{_prefix}/share/pixmaps/apcupsd.png %{_prefix}/share/pixmaps/charging.png %{_prefix}/share/pixmaps/gapc_prefs.png %{_prefix}/share/pixmaps/onbatt.png %{_prefix}/share/pixmaps/online.png %{_prefix}/share/pixmaps/unplugged.png %endif %post # get rid of any 3.6.2 stuff rm -f /etc/rc.d/rc[0-6].d/[KS]20apcups rm -f %{initdir}/apcups # add our links if [ "$1" -ge 1 ] ; then /sbin/chkconfig --add apcupsd fi # are we Red Hat or SuSE? # Mandrake already handles apcupsd if [ -s /etc/redhat-release -o -s /etc/SuSE-release -o -s /etc/whitebox-release ]; then cp -f %{initdir}/halt %{initdir}/halt.old awk '# Stuff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert the new apcupsd code just before the following line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f %{pwrfaildir}/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " %{pwrfaildir}/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # Everything else is duplicated { print } ' %{initdir}/halt.old > %{initdir}/halt chmod 744 %{initdir}/halt fi # restart the daemon if we are upgrading if [ "$1" -ge "2" ] ; then %{initdir}/apcupsd restart fi # Undo things a bit %preun if [ "$1" = 0 ] ; then # remove startup links /sbin/chkconfig --del apcupsd # are we Red Hat or SuSE? # Mandrake already handles apcupsd if [ -s /etc/redhat-release -o -s /etc/SuSE-release -o -s /etc/whitebox-release ]; then cp -f %{initdir}/halt %{initdir}/halt.old awk '# Stuff added by apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # Everything else is duplicated { print } ' %{initdir}/halt.old > %{initdir}/halt chmod 744 %{initdir}/halt fi fi %changelog * Sun Oct 4 2015 David Ranch - Updated to support Centos and RHEL 6 * Fri Sep 30 2011 D. Scott Barninger - remove glitz-devel build requirement for suse (obsoleted) - builds for older suse versions should make sure that glitz packages are installed * Sun Jan 10 2010 Adam Kropelin - changes for new snmp driver * Sat Aug 01 2009 D. Scott Barninger - fix restart on upgrade using $1 variable. remove previously commented out code * Sat May 16 2009 D. Scott Barninger - comment out latex build * Fri May 15 2009 Adam Kropelin - changes for new user manual location and format * Sat May 31 2008 D. Scott Barninger - add check for upgrade and restart daemon * Sun May 11 2008 Adam Kropelin - remove powerflute * Sun Feb 03 2008 D. Scott Barninger - add debug package to strip suse * Sat Nov 17 2007 D. Scott Barninger - add hal policy file * Sat Nov 10 2007 D. Scott Barninger - SuSE 10.3 replaces tetex with texlive-latex package * Sun May 27 2007 Adam Kropelin - add support for rhel5 * Sun Jan 28 2007 D. Scott Barninger - remove /etc/apcupsd/masterconnect and mastertimeout files * Sat Jan 27 2007 D. Scott Barninger - add snmp build - fix location of Requires for base package * Sun Jan 21 2007 D. Scott Barninger - correct gapcmon dependancies * Sat Jan 20 2007 D. Scott Barninger - restructure for 3.14 release - merge std and ups packages - remove --enable-pthreads and --enable-master-slave - add --enable-pcnet - break out multimon into separate package - add gapcmon package * Sat Aug 19 2006 D. Scott Barninger - add third party packager tag * Fri May 05 2006 D. Scott Barninger - update build requirments to include ghostscript - update fedora_core build requirements to include latex2html * Sun Apr 23 2006 D. Scott Barninger - add pdf manual to doc package - remove redundant code for std and usb packages - add powerflute * Sat Apr 22 2006 D. Scott Barninger - clean up build defines, add rhel4 * Sat Jan 21 2006 D. Scott Barninger - release 3.12.2 update docs * Sun Sep 18 2005 D. Scott Barninger - Change deprecated Copyright tag to License * Tue Jun 07 2005 Adam Kropelin - Rename mainsback.in to offbattery.in so default power loss/return actions - are symmetrical. * Sat Apr 30 2005 D. Scott Barninger - fix typo in rh7 dependencies * Sat Mar 12 2005 D. Scott Barninger - clean up halt insertion code, add check for whitebox-release - remove cruft that has been commented out for a long time - add pwrfaildir as variable - correct SuSE initdir - add libjpeg libpng zlib freetype dependencies for RH7 * Sun Nov 28 2004 D. Scott Barninger - correct awk insertion in halt script for SuSE * Fri Nov 05 2004 D. Scott Barninger - change Mandrake logic in preun and post scriptlets to if;then;fi * Sun Oct 31 2004 D. Scott Barninger - add Mandrake support * Wed Aug 04 2004 D. Scott Barninger - changed location of apcupsd.css to /etc/apcupsd from /etc/apcupsd/cgi - corrected typo introduced in SuSE configuration for initdir definition * Sun Apr 25 2004 D. Scott Barninger - add SuSE configuration * Sat Apr 24 2004 D. Scott Barninger - tidy up doc includes, add release notes * Mon Mar 08 2004 D. Scott Barninger - added additional clean of buildroot to beginning of install section - corrected post install routines for nicer chkconfig * Sat Jan 17 2004 D. Scott Barninger - added build of net driver to configure - moved usb driver build into both packages - set --with-serial-dev= to blank so will find any device and removed rh7 patch * Sat Jan 10 2004 D. Scott Barninger - added build tags for rh8 rh9 fedora_core and wb3 - cleaned up dependancies and Requires by platform * Thu Jan 1 2004 D. Scott Barninger - removed rh_version from package names - added platform build configuration section to beginning of file * Sat Nov 08 2003 Scott at fairfieldcomputers dot com - expanded usb devices from 0-9 to 0-15 * Fri Nov 07 2003 Scott at fairfieldcomputers dot com - corrected device path for usb devices to /dev/usb and added patch for - rh7 builds to make it /dev/usb/hid in /etc/apcupsd/apcupsd.conf * Sat Oct 18 2003 Scott at fairfieldcomputers dot com - added master-slave, apcsmart and dumb to configure options * Sun Sep 14 2003 Scott at fairfieldcomputers dot com - added rm commands during install to remove halt scripts created - in the build root * Mon May 11 2003 Scott at fairfieldcomputers dot com - combined layout for usb/serial builds * Thu Jan 16 2003 Scott at fairfieldcomputers dot com - Update spec to new source layout - Added masterconnect and mastertimout to files section - Changed make install-apcupsd and make install-cgi to make install * Wed Sep 05 2001 kern at sibbald dot com - Applied very nice patch to this spec by Giulio Orsero * Thu Sep 14 2000 kern at sibbald dot com - Many thanks to Fredrik Persson and Neil Darlow for helping me write this spec file. - Basic spec by Kern Sibbald apcupsd-3.14.14/platforms/redhat/awkhaltprog.in000066400000000000000000000020451274230402600214550ustar00rootroot00000000000000# # Awk program to insert the necessary apcupsd script in # to a halt script. # # Suff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert our code just before this line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " @sysconfdir@/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # everything else is duplicated { print } apcupsd-3.14.14/platforms/slackware/000077500000000000000000000000001274230402600173065ustar00rootroot00000000000000apcupsd-3.14.14/platforms/slackware/Makefile000066400000000000000000000032471274230402600207540ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-slackware all-uninstall: uninstall-slackware install-slackware: $(call DISTINST,Slackware) $(call MKDIR,/etc/rc.d) $(call INSTPROG,744,apcupsd,/etc/rc.d/rc.apcupsd) $(call MKDIR,$(LOCKDIR)) $(VV)-rcfile=/etc/rc.d/rc.6; \ grep -q $(sysconfdir)/apccontrol $$rcfile; \ if [ $$? -ne 0 ]; then \ echo " PATCH $(DESTDIR)$$rcfile"; \ cp -p $$rcfile $(DESTDIR)$$rcfile.`date +%Y%m%d%M%S`; \ patch -s $(DESTDIR)$$rcfile rc6.patch; \ if [ $$? -ne 0 ]; then \ echo "Patches could not be properly applied. Please check"; \ echo "$(DESTDIR)$$rcfile and edit it manually."; \ fi; \ fi @( echo ''; \ echo "The apcupsd boot script has been installed to"; \ echo "/etc/rc.d/rc.apcupsd and the halt script /etc/rc.d/rc.6 has"; \ echo "been patched. You must still call /etc/rc.d/rc.apcupsd"; \ echo "during the boot process after you have tested your"; \ echo "installation. One way to do this is from the"; \ echo "/etc/rc.d/rc.local file."; \ echo "See the distributions/slackware/README file."; \ echo ) | /usr/bin/fmt uninstall-slackware: $(call DISTUNINST,Slackware) -$(call UNINST,/etc/rc.d/rc.apcupsd) $(VV)-rcfile=/etc/rc.d/rc.6; \ grep -q $(sysconfdir)/apccontrol $$rcfile; \ if [ $$? -eq 0 ]; then \ echo " PATCH $(DESTDIR)$$rcfile"; \ cp -p $(DESTDIR)$$rcfile $(DESTDIR)$$rcfile.`date +%Y%m%d%M%S`; \ patch -s -R $(DESTDIR)$$rcfile rc6.patch; \ if [ $$? -ne 0 ]; then \ echo "Patches could not be properly removed. Please check"; \ echo "$(DESTDIR)$$rcfile and edit it manually."; \ fi; \ fi; apcupsd-3.14.14/platforms/slackware/README000066400000000000000000000046521274230402600201750ustar00rootroot00000000000000Distribution: Linux Slackware Maintainer: Devin Reade $Id: README,v 1.1.1.1 2002-05-28 13:34:06 kerns Exp $ The Slackware installation of apcupsd no longer replaces the /etc/rc.d/rc6 (halt) script, but rather attempts to patch it. This should be more portable across Slackware versions. It has been tested with Slackware 7. If the rc6 script appears to have been previously patched for apcupsd, it will not be touched. When it is patched, a copy of the rc6 script will be saved in the /etc/rc.d; that copy will have a timestamp as a suffix. Once 'make install' has been run, there are still two steps which must be carried out in order to complete the installation: 1. You must create/edit the file apcupsd.conf file (by default, it belongs in the /etc/apcupsd directory). Some examples of this file are given in the directories: contrib/apcupsdconf/cfgfiles examples The installation process will install a default one for you if you don't already have one from a previous version of apcupsd. 2. Test your installation, as described in the apcupsd manual. The rc.apcupsd script that should be used to start, stop, and obtain the status of the apcupsd daemon is located in /etc/rc.d. 3. Once you are satisfied that the installation is sane, you need to configure your system to start apcupsd automatically. The recommended way to do this is by adding the following lines to your /etc/rc.d/rc.local file: # Start the APC UPS control daemon. if [ -x /etc/rc.d/rc.apcupsd ]; then /etc/rc.d/rc.apcupsd start fi If you are running a version of Slackware earlier than v7 bring up X on boot, it is *possible* that rc.local is not being executed. You should verify whether or not this is the case and take appropriate remedial action. If there is reference to rc.local in the rc.M script, then you are probably safe. If you are using the network feature (master-slave) of apcupsd and are running a DNS server locally, make sure the name server is up and running before executing rc.apcupsd. Since named is normally started out of rc.inet2, this should be a non-issue. The deinstallation process ('make uninstall') will attempt to unpatch your rc6.d script. If it fails (which may happen if you have since edited that file), then you can manually remove references to apcupsd or just leave it as is; without apcupsd running, the patch is benign. The deinstallation process will not modify rc.local. apcupsd-3.14.14/platforms/slackware/apcupsd.in000066400000000000000000000020011274230402600212660ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid DISTVER="@DISTVER@" return=" Done." case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting apcupsd power management.." if [ -f ${APCPID} ]; then return=" Already running." else @sbindir@/apcupsd && touch @LOCKDIR@/apcupsd \ || return=" Failed." fi echo -e "$return" ;; stop) echo -n "Stopping apcupsd power management.." if [ -f ${APCPID} ]; then THEPID=`cat ${APCPID}` kill ${THEPID} || return=" Failed." rm -f ${APCPID} else return=" Nothing to stop." fi rm -f @LOCKDIR@/apcupsd echo -e "$return" ;; restart) $0 stop $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/slackware/rc6.patch.in000066400000000000000000000040301274230402600214230ustar00rootroot00000000000000--- rc.6.orig Sat Sep 11 14:38:33 1999 +++ rc.6 Sun Feb 27 13:22:11 2000 @@ -84,11 +84,31 @@ # This never hurts: sync + # This block was from the original Slackware distribution: # See if this is a powerfail situation. - if [ -x /sbin/genpowerd ]; then - # See if this is a powerfail situation: - if grep FAIL /etc/upsstatus 1> /dev/null 2> /dev/null ; then - # Signal UPS to shut off the inverter: - /sbin/genpowerd -k /dev/UPS apc-linux - if [ ! $? = 0 ]; then - echo - echo "There was an error signaling the UPS." - echo "Perhaps you need to edit /etc/rc.d/rc.6 to configure" - echo "the serial line and UPS type." - # Wasting 15 seconds of precious power: - sleep 15 - fi - fi + # if [ -x /sbin/genpowerd ]; then + # # See if this is a powerfail situation: + # if grep FAIL /etc/upsstatus 1> /dev/null 2> /dev/null ; then + # # Signal UPS to shut off the inverter: + # /sbin/genpowerd -k /dev/UPS apc-linux + # if [ ! $? = 0 ]; then + # echo + # echo "There was an error signaling the UPS." + # echo "Perhaps you need to edit /etc/rc.d/rc.6 to configure" + # echo "the serial line and UPS type." + # # Wasting 15 seconds of precious power: + # sleep 15 + # fi + # fi + # fi + + # This block was added in by the apcupsd installation process. This + # will cause the UPS to kill the power supply after a configurable number + # of seconds (see the apcupsd.conf file). This is important for situations + # where the mains power comes back before the UPS batteries are completely + # dead. + if [ -f @PWRFAILDIR@/powerfail ]; then + echo + echo "apcupsd will now power off the UPS" + echo + @sysconfdir@/apccontrol killpower + echo + echo "Please ensure that the UPS has powered off before rebooting." + echo "Otherwise, the UPS may cut the power during the reboot." + echo + halt -f -p # power down the system if the hardware is capable fi # Now halt (poweroff with APM kernels) or reboot. apcupsd-3.14.14/platforms/slackware/rc6.patch.in.old000066400000000000000000000023171274230402600222060ustar00rootroot00000000000000--- rc.6.orig Sat Sep 11 14:38:33 1999 +++ rc.6 Sun Feb 27 13:22:11 2000 @@ -84,11 +84,31 @@ # This never hurts: sync + # This block was from the original Slackware distribution: # See if this is a powerfail situation. - if [ -f /etc/power_is_failing ]; then - echo "Turning off UPS, bye." - /sbin/powerd -q - exit 1 + #if [ -f /etc/power_is_failing ]; then + # echo "Turning off UPS, bye." + # /sbin/powerd -q + # exit 1 + #fi + + # This block was added in by the apcupsd installation process. This + # will cause the UPS to kill the power supply after a configurable number + # of seconds (see the apcupsd.conf file). This is important for situations + # where the mains power comes back before the UPS batteries are completely + # dead. + if [ -f @PWRFAILDIR@/powerfail ]; then + echo + echo "apcupsd will now power off the UPS" + echo + @sysconfdir@/apccontrol killpower + echo + echo "Please ensure that the UPS has powered off before rebooting." + echo "Otherwise, the UPS may cut the power during the reboot." + echo + halt -f -p # power down the system if the hardware is capable fi # Now halt (poweroff with APM kernels) or reboot. apcupsd-3.14.14/platforms/sun/000077500000000000000000000000001274230402600161375ustar00rootroot00000000000000apcupsd-3.14.14/platforms/sun/Makefile000066400000000000000000000036061274230402600176040ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-sun $(if $(DESTDIR),,install-$(USBDRV)) all-uninstall: uninstall-sun $(if $(DESTDIR),,uninstall-$(USBDRV)) install-sun: $(call DISTINST,Sun) $(call MKDIR,/etc/rc0.d) $(call MKDIR,/etc/rc1.d) $(call MKDIR,/etc/rc2.d) $(call MKDIR,/etc/init.d) $(call INSTPROG,744,apcupsd,/etc/init.d/apcupsd) $(call SYMLINK,../init.d/apcupsd,/etc/rc0.d/K21apcupsd) $(call SYMLINK,../init.d/apcupsd,/etc/rc1.d/S89apcupsd) $(call SYMLINK,../init.d/apcupsd,/etc/rc2.d/S89apcupsd) @echo "=================================================" @echo "apcupsd script installation for Solaris $(DISTVER) complete." @echo "You should now edit $(sysconfdir)/apcupsd.conf to correspond" @echo "to your setup then start the apcupsd daemon with:" @echo @echo "/etc/init.d/apcupsd start" @echo @echo "Thereafter when you reboot, it will be stopped and started" @echo "automatically." @echo "=================================================" install-usb: @echo "Configuring ugen driver to match APC UPSes..." @echo $(V)-add_drv -f -i '"usbif51d,class3"' ugen || \ update_drv -a -i '"usbif51d,class3"' ugen @echo @echo "NOTE:" @echo " \"(usbif51d,class3) already in use\" and" @echo " \"Driver (ugen) is already installed\"" @echo " errors may be safely ignored." @echo @echo "=================================================" @echo "Driver configured. You must PERFORM A RECONFIGURE" @echo "BOOT \"reboot -- -r\" before running Apcupsd." @echo "=================================================" uninstall-sun: $(call DISTUNINST,Sun) -$(call UNINST,/etc/rc0.d/K21apcupsd) -$(call UNINST,/etc/rc1.d/S89apcupsd) -$(call UNINST,/etc/rc2.d/S89apcupsd) -$(call UNINST,/etc/init.d/apcupsd) uninstall-usb: @echo "Removing ugen binding (errors are safe to ignore)..." $(V)-update_drv -d -i '"usbif51d,class3"' ugen > /dev/null apcupsd-3.14.14/platforms/sun/apccontrol.in000066400000000000000000000064041274230402600206370ustar00rootroot00000000000000#!@SCRIPTSHELL@ # # Copyright (C) 1999-2002 Riccardo Facchetti # # for apcupsd release @VERSION@ (@DATE@) - @DISTNAME@ # # @configure_input@ # # Apccontrol for Sun Solaris provided by Carl Erhorn # # These variables are needed for set up the autoconf other variables. # Updated October 7th, 2001 - CPE # prefix=@prefix@ exec_prefix=@exec_prefix@ APCPID=@PIDDIR@/apcupsd.pid APCUPSD=@sbindir@/apcupsd SHUTDOWN=@SHUTDOWN@ SCRIPTSHELL=@SCRIPTSHELL@ SCRIPTDIR=@sysconfdir@ POWERFAILDIR=@PWRFAILDIR@ export SYSADMIN=root export APCUPSD_MAIL="@APCUPSD_MAIL@" if [ -f $SCRIPTDIR/config ]; then . $SCRIPTDIR/config ; fi # # This piece is to substitute the default behaviour with your own script, # perl, or C program. # You can customize every single command creating an executable file (may be a # script or a compiled program) and calling it the same as the $1 parameter # passed by apcupsd to this script. # # After executing your script, apccontrol continues with the default action. # If you do not want apccontrol to continue, exit your script with exit # code 99. E.g. "exit 99". # # WARNING: the apccontrol file will be overwritten every time you update your # apcupsd, doing `make install'. Your own customized scripts will _not_ be # overwritten. If you wish to make changes to this file (discouraged), you # should change apccontrol.sh.in and then rerun the configure process. # if [ -f ${SCRIPTDIR}/${1} -a -x ${SCRIPTDIR}/${1} ] then ${SCRIPTDIR}/${1} ${2} ${3} ${4} # exit code 99 means he does not want us to do default action if [ $? = 99 ] ; then exit 0 fi fi case "$1" in killpower) sleep 10 ${APCUPSD} --killpower ;; commfailure) printf "Communications with UPS lost." | wall -a ;; commok) printf "Communciations with UPS restored." | wall -a ;; powerout) ;; onbattery) printf "Power failure. Running on UPS batteries." | wall -a ;; offbattery) printf "Power has returned..." | wall -a ;; mainsback) ;; failing) printf "UPS battery power exhausted. Doing shutdown.\n" | wall -a ;; timeout) printf "UPS battery runtime limit exceeded. Doing shutdown.\n" | wall -a ;; loadlimit) printf "UPS battery discharge limit reached. Doing shutdown.\n" | wall -a ;; runlimit) printf "UPS battery runtime percent reached. Doing shutdown.\n" | wall -a ;; doreboot) printf "Beginning Reboot Sequence" | wall -a ${SHUTDOWN} -y -g0 -i6 "apcupsd initiated reboot" ;; doshutdown) printf "Beginning Shutdown Sequence" | wall -a ${SHUTDOWN} -y -g0 -i0 "apcupsd initiated shutdown" ;; annoyme) printf "Power problems please logoff." | wall -a ;; emergency) printf "Emergency Shutdown. Possible UPS battery failure." | wall -a ;; changeme) printf "Emergency! UPS batteries have failed\nChange them NOW" | wall -a ;; remotedown) printf "Remote Shutdown.\nBeginning Shutdown Sequence." | wall -a ;; startselftest) ;; endselftest) ;; battdetach) ;; battattach) ;; *) echo "Usage: ${0##*/} command" echo " warning: this script is intended to be launched by" echo " apcupsd and should never be launched by users." exit 1 ;; esac apcupsd-3.14.14/platforms/sun/apcupsd.in000066400000000000000000000017641274230402600201360ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # # Update October 7th, 2001 - CPE # APCPID=@PIDDIR@/apcupsd.pid DISTVER="@DISTVER@" POWERFAILDIR=@PWRFAILDIR@ LOCKDIR=@LOCKDIR@ SBINDIR=@sbindir@ return=" Done." case "$1" in start) rm -f ${POWERFAILDIR}/powerfail echo "Starting apcupsd power management ...\c" ${SBINDIR}/apcupsd || return=" Failed." touch ${LOCKDIR}/apcupsd echo "$return" ;; stop) echo "Stopping apcupsd power management ...\c" if [ -f ${APCPID} ]; then THEPID=`cat ${APCPID}` kill ${THEPID} || return=" Failed." rm -f ${APCPID} else return=" Failed." fi rm -f ${LOCKDIR}/apcupsd echo "$return" ;; restart) $0 stop $0 start ;; status) ${SBINDIR}/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/sun/rc0.solaris.in000077500000000000000000000006001274230402600206250ustar00rootroot00000000000000#see if this is a powerfail situation if [ -f @PWRFAILDIR@/powerfail ]; then echo echo "APCUPSD will power off the UPS" echo @sysconfdir@/apccontrol killpower echo echo "Please ensure that the UPS has powered off before rebooting" echo "Otherwise, the UPS may cut the power during the reboot!!!" echo exit 0 fi apcupsd-3.14.14/platforms/suse/000077500000000000000000000000001274230402600163115ustar00rootroot00000000000000apcupsd-3.14.14/platforms/suse/Makefile000066400000000000000000000030741274230402600177550ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-suse all-uninstall: uninstall-suse install-suse: $(call DISTINST,SuSE) # unlink old rc script (if not doing a DESTDIR install) $(call CHKCFG,del,/etc/rc.d/apcupsd) # install new rc script $(call MKDIR,/etc/rc.d) $(call INSTDATA,744,apcupsd,/etc/rc.d) # save old halt script $(call COPY,/etc/rc.d/halt,/etc/rc.d/halt.old) # insert apcupsd callout into halt script @echo " PATCH" $(DESTDIR)/etc/rc.d/halt $(V)awk -f awkhaltprog $(DESTDIR)/etc/rc.d/halt.old >$(DESTDIR)/etc/rc.d/halt $(V)chmod 744 $(DESTDIR)/etc/rc.d/halt # link new rc script (if not doing a DESTDIR install) $(call CHKCFG,add,/etc/rc.d/apcupsd) @echo "=================================================" @echo "apcupsd script installation for SuSE $(DISTVER) complete." @echo " " @echo "You should now edit /etc/apcupsd/apcupsd.conf to correspond" @echo "to your setup then start the apcupsd daemon with:" @echo " " @echo "/etc/rc.d/apcupsd start" @echo " " @echo "thereafter when you reboot, it will be stopped and started" @echo "automatically." @echo " " @echo "Please check that your halt script in:" @echo " /etc/rc.d/halt" @echo "was properly updated (see installation section of manual)" @echo "=================================================" uninstall-suse: # unlink old rc script (if not doing a DESTDIR install) -$(call CHKCFG,del,/etc/rc.d/apcupsd) -$(call UNINST,/etc/rc.d/apcupsd) -$(call COPY,$(DESTDIR)/etc/rc.d/halt.old,/etc/rc.d/halt) -$(call UNINST,/etc/rc.d/halt.old) apcupsd-3.14.14/platforms/suse/apcupsd.in000066400000000000000000000027101274230402600203000ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # Copyright (C) 2004 D. Scott Barninger # Copyright (C) 2004 Kern Sibbald # # chkconfig: 2345 60 99 # description: apcupsd monitors power and takes action if necessary # # 20 Aug 2004 DSB # 28 Nov 2004 DSB ### BEGIN INIT INFO # Provides: apcupsd # Required-Start: $network $syslog # Required-Stop: $network $syslog # Default-Start: 2 3 5 # Default-Stop: # Description: Start the apcupsd daemon ### END INIT INFO APCPID=@PIDDIR@/apcupsd.pid DISTVER=`cat /etc/SuSE-release | grep VERSION | cut -f 3 -d' '` # Source function libarary . /etc/rc.status RETVAL=0 case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting UPS monitoring:" /sbin/startproc @sbindir@/apcupsd -f @sysconfdir@/apcupsd.conf RETVAL=$? rc_status -v echo [ $RETVAL -eq 0 ] && touch @LOCKDIR@/apcupsd ;; stop) echo -n "Shutting down UPS monitoring:" /sbin/killproc apcupsd echo rc_status -v rm -f $APCPID rm -f @LOCKDIR@/apcupsd ;; restart) $0 stop sleep 15 $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0 apcupsd-3.14.14/platforms/suse/apcupsd.spec.in000066400000000000000000000426141274230402600212400ustar00rootroot00000000000000# Platform configuration # # Select the platform by setting the define below either by command # line arguments, # e.g. rpmbuild -ba --define "build_suse 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define suse 1 # # If you want the gapcmon package, use: # e.g. rpmbuild -ba --define "build_gapcmon 1" --define "build_suse 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define gapcmon 1 # # Note, to build, you need: # Release_Notes-%{version}-%{release}.tar.gz in your # rpm SOURCES directory, and the tar file must contain # Release_Notes-%{version}-%{release}.txt # # basic defines for every build %define _version @VERSION@ %define _release 1 #-------------------------------------------------------------------------- # it should not be necessary to change anything below here for a release # except for patch macros in the setup section if used #-------------------------------------------------------------------------- %define pwrfaildir @PWRFAILDIR@ %define halpolicydir /usr/share/hal/fdi/policy/20thirdparty # third party packagers %define _packager D. Scott Barninger %{?contrib_packager:%define _packager %{contrib_packager}} %define rh7 0 %{?build_rh7:%define rh7 1} %define rh8 0 %{?build_rh8:%define rh8 1} %define rh9 0 %{?build_rh9:%define rh9 1} # all FC releases to date %define fedora_core 0 %{?build_fedora_core:%define fedora_core 1} # RedHat Enterprise and all clones %define rhel3 0 %{?build_rhel3:%define rhel3 1} %define rhel4 0 %{?build_rhel4:%define rhel4 1} %define rhel5 0 %{?build_rhel5:%define rhel5 1} # SuSE 9.x and 10.x %define suse 0 %{?build_suse:%define suse 1} # Mandrake and Mandriva %define mdk 0 %{?build_mdk:%define mdk 1} %if ! %{suse} %define suse_version 0 %endif %if %{suse} %define initdir /etc/rc.d %else %define initdir /etc/rc.d/init.d %endif # set destination directories for multimon %define cgidir /var/www/cgi-bin %if %{suse} %define cgidir /srv/www/cgi-bin %endif # set ownership of files %define binowner root %define bingroup root %define dataowner apache %define datagroup apache %if %{suse} %define dataowner wwwrun %define datagroup www %endif # should we build gapcmon, requires gtk2 >= 2.4 %define gapcmon 0 %{?build_gapcmon:%define gapcmon 1} Summary: APC UPS Power Control Daemon for Linux Name: apcupsd Version: %{_version} Release: %{_release} Vendor: APC UPS Daemon Team Distribution: The apcupsd Team Packager: %{_packager} URL: http://www.apcupsd.com Source0: http://www.spcupsd.com/%{name}-%{version}.tar.gz Source1: Release_Notes-%{version}-%{release}.tar.gz Group: System Environment/Daemons License: GPL v2 BuildRoot: %{_tmppath}/%{name}-root BuildRequires: gd-devel, ncurses-devel, ghostscript, libstdc++-devel %if %{rh7} BuildRequires: glibc-devel >= 2.2, libjpeg-devel, libpng-devel, zlib-devel, freetype-devel %else BuildRequires: glibc-devel >= 2.3 %endif %if %{gapcmon} BuildRequires: glibc-devel, gtk2-devel >= 2.4, glib2-devel, atk-devel BuildRequires: ORBit2, pango-devel, pkgconfig %endif %if %{suse} && %{gapcmon} BuildRequires: bonobo-activation, freetype2-devel, cairo-devel, fontconfig-devel BuildRequires: gconf2-devel, gnome-vfs2-devel, libpng-devel, xorg-x11-libs BuildRequires: libbonobo-devel, libbonoboui-devel %endif %if %{fedora_core} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif %if %{mdk} && %{gapcmon} BuildRequires: libbonobo2_0-devel, libbonoboui2_0-devel, freetype2-devel, libGConf2_4-devel %endif %if %{rhel4} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif %if %{rhel5} && %{gapcmon} BuildRequires: libbonobo-devel, libbonoboui-devel, freetype-devel, GConf2-devel %endif Provides: apcupsd Obsoletes: apcupsd-std apcupsd-usb Requires: perl, ncurses %if %{rh7} Requires: glibc >= 2.2 %else Requires: glibc >= 2.3 %endif %description Apcupsd can be used for controlling most APC UPSes. During a power failure, apcupsd will inform the users about the power failure and that a shutdown may occur. If power is not restored, a system shutdown will follow when the battery is exausted, a timeout (seconds) expires, or the battery runtime expires based on internal APC calculations determined by power consumption rates. If the power is restored before one of the above shutdown conditions is met, apcupsd will inform users about this fact. Some features depend on what UPS model you have (simple or smart). This package is configured for USB but can be reconfigured for standard serial port UPS models. See the manual. %package multimon Summary: APC UPS Power Control Daemon for Linux Group: Applications/Internet Requires: libstdc++ %if %{fedora_core} || %{suse} || %{mdk} || %{rhel4} || %{rhel5} Requires: gd >= 2.0 %else Requires: gd < 2.0 %endif %if %{rh7} Requires: glibc >= 2.2, libjpeg, libpng, zlib, freetype %else Requires: glibc >= 2.3 %endif %description multimon apcupsd Network Monitoring (CGI) Programs which will give you the status of your UPS or UPSes over the network. %if %{gapcmon} %package gapcmon Summary: APC UPS Power Control Daemon for Linux Group: Applications/System Requires: glibc, gtk2 >= 2.4, glib2, atk, libbonobo, libbonoboui, ORBit2, pango %endif %if %{suse} && %{gapcmon} Requires: bonobo-activation, freetype2, cairo, fontconfig, gconf2, gnome-vfs2, libpng, xorg-x11-libs %endif %if %{fedora_core} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{mdk} && %{gapcmon} Requires: freetype2, GConf2 %endif %if %{rhel4} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{rhel5} && %{gapcmon} Requires: freetype, GConf2 %endif %if %{gapcmon} %description gapcmon A Gnome application to monitor the status of your UPS. %endif # SuSE turns off stripping of binaries by default. In order to get # stripped packages we must generate debug package. RedHat and Mandriva # turn debug packages on by default but strip binaries regardless. %if %{suse} %debug_package %endif %prep %setup -b 1 %build %configure \ --prefix=%{_prefix} \ --sbindir=/sbin \ --sysconfdir=%{_sysconfdir}/apcupsd \ --with-cgi-bin=%{cgidir} \ --enable-cgi \ --enable-net \ --enable-pcnet \ --enable-apcsmart \ --enable-dumb \ --enable-usb \ --enable-snmp \ %if %{gapcmon} --enable-gapcmon \ %endif --with-serial-dev= \ --with-upstype=usb \ --with-halpolicydir=%{halpolicydir} \ --with-upscable=usb make cd examples make hid-ups cd ../ %install [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{initdir} mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/cgi make \ DESTDIR=$RPM_BUILD_ROOT \ install install -m744 platforms/apccontrol \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/apccontrol %if ! %{suse} && ! %{mdk} install -m755 platforms/redhat/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if %{suse} install -m755 platforms/suse/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if %{mdk} install -m755 platforms/mandrake/apcupsd $RPM_BUILD_ROOT%{initdir} %endif %if ! %{mdk} rm $RPM_BUILD_ROOT%{initdir}/halt rm $RPM_BUILD_ROOT%{initdir}/halt.old %endif install -m744 examples/hid-ups \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/hid-ups install -m744 examples/make-hiddev \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/make-hiddev %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT rm -f $RPM_BUILD_DIR/Release_Notes-%{version}-%{release}.txt %files %defattr(-,root,root) %{_sysconfdir}/apcupsd/make-hiddev %{_sysconfdir}/apcupsd/hid-ups %{halpolicydir}/80-apcupsd-ups-policy.fdi %doc COPYING DISCLAIMER ReleaseNotes ChangeLog ../Release_Notes-%{version}-%{release}.txt doc/manual/manual.html doc/manual/*.png %dir %{_sysconfdir}/apcupsd %{initdir}/apcupsd %config(noreplace) %{_sysconfdir}/apcupsd/apccontrol %config(noreplace) %{_sysconfdir}/apcupsd/changeme %config(noreplace) %{_sysconfdir}/apcupsd/commfailure %config(noreplace) %{_sysconfdir}/apcupsd/commok %config(noreplace) %{_sysconfdir}/apcupsd/onbattery %config(noreplace) %{_sysconfdir}/apcupsd/offbattery %config(noreplace) %{_sysconfdir}/apcupsd/apcupsd.conf /sbin/* %attr(-,root,man) %{_mandir}/*/* %files multimon %defattr(-,root,root) %dir %{_sysconfdir}/apcupsd %dir %{cgidir} %attr(-,%{dataowner},%{datagroup}) %{_sysconfdir}/apcupsd/apcupsd.css %attr(-,%{binowner},%{bingroup}) %{cgidir}/* %attr(-,%{dataowner},%{datagroup}) %config(noreplace) %{_sysconfdir}/apcupsd/hosts.conf %attr(-,%{dataowner},%{datagroup}) %config(noreplace) %{_sysconfdir}/apcupsd/multimon.conf %if %{gapcmon} %files gapcmon %defattr(-,root,root) %{_prefix}/bin/gapcmon %{_prefix}/share/applications/gapcmon.desktop %{_prefix}/share/pixmaps/apcupsd.png %{_prefix}/share/pixmaps/charging.png %{_prefix}/share/pixmaps/gapc_prefs.png %{_prefix}/share/pixmaps/onbatt.png %{_prefix}/share/pixmaps/online.png %{_prefix}/share/pixmaps/unplugged.png %endif %post # get rid of any 3.6.2 stuff rm -f /etc/rc.d/rc[0-6].d/[KS]20apcups rm -f %{initdir}/apcups # add our links if [ "$1" -ge 1 ] ; then /sbin/chkconfig --add apcupsd fi # are we Red Hat or SuSE? # Mandrake already handles apcupsd if [ -s /etc/redhat-release -o -s /etc/SuSE-release -o -s /etc/whitebox-release ]; then cp -f %{initdir}/halt %{initdir}/halt.old awk '# Stuff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert the new apcupsd code just before the following line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f %{pwrfaildir}/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " %{pwrfaildir}/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # Everything else is duplicated { print } ' %{initdir}/halt.old > %{initdir}/halt chmod 744 %{initdir}/halt fi # restart the daemon if we are upgrading if [ "$1" -ge "2" ] ; then %{initdir}/apcupsd restart fi # Undo things a bit %preun if [ "$1" = 0 ] ; then # remove startup links /sbin/chkconfig --del apcupsd # are we Red Hat or SuSE? # Mandrake already handles apcupsd if [ -s /etc/redhat-release -o -s /etc/SuSE-release -o -s /etc/whitebox-release ]; then cp -f %{initdir}/halt %{initdir}/halt.old awk '# Stuff added by apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # Everything else is duplicated { print } ' %{initdir}/halt.old > %{initdir}/halt chmod 744 %{initdir}/halt fi fi %changelog * Fri Sep 30 2011 D. Scott Barninger - remove glitz-devel build requirement for suse (obsoleted) - builds for older suse versions should make sure that glitz packages are installed * Sun Jan 10 2010 Adam Kropelin - changes for new snmp driver * Sat Aug 01 2009 D. Scott Barninger - fix restart on upgrade using $1 variable. remove previously commented out code * Sat May 16 2009 D. Scott Barninger - comment out latex build * Fri May 15 2009 Adam Kropelin - changes for new user manual location and format * Sat May 31 2008 D. Scott Barninger - add check for upgrade and restart daemon * Sun May 11 2008 Adam Kropelin - remove powerflute * Sun Feb 03 2008 D. Scott Barninger - add debug package to strip suse * Sat Nov 17 2007 D. Scott Barninger - add hal policy file * Sat Nov 10 2007 D. Scott Barninger - SuSE 10.3 replaces tetex with texlive-latex package * Sun May 27 2007 Adam Kropelin - add support for rhel5 * Sun Jan 28 2007 D. Scott Barninger - remove /etc/apcupsd/masterconnect and mastertimeout files * Sat Jan 27 2007 D. Scott Barninger - add snmp build - fix location of Requires for base package * Sun Jan 21 2007 D. Scott Barninger - correct gapcmon dependancies * Sat Jan 20 2007 D. Scott Barninger - restructure for 3.14 release - merge std and ups packages - remove --enable-pthreads and --enable-master-slave - add --enable-pcnet - break out multimon into separate package - add gapcmon package * Sat Aug 19 2006 D. Scott Barninger - add third party packager tag * Fri May 05 2006 D. Scott Barninger - update build requirments to include ghostscript - update fedora_core build requirements to include latex2html * Sun Apr 23 2006 D. Scott Barninger - add pdf manual to doc package - remove redundant code for std and usb packages - add powerflute * Sat Apr 22 2006 D. Scott Barninger - clean up build defines, add rhel4 * Sat Jan 21 2006 D. Scott Barninger - release 3.12.2 update docs * Sun Sep 18 2005 D. Scott Barninger - Change deprecated Copyright tag to License * Tue Jun 07 2005 Adam Kropelin - Rename mainsback.in to offbattery.in so default power loss/return actions - are symmetrical. * Sat Apr 30 2005 D. Scott Barninger - fix typo in rh7 dependencies * Sat Mar 12 2005 D. Scott Barninger - clean up halt insertion code, add check for whitebox-release - remove cruft that has been commented out for a long time - add pwrfaildir as variable - correct SuSE initdir - add libjpeg libpng zlib freetype dependencies for RH7 * Sun Nov 28 2004 D. Scott Barninger - correct awk insertion in halt script for SuSE * Fri Nov 05 2004 D. Scott Barninger - change Mandrake logic in preun and post scriptlets to if;then;fi * Sun Oct 31 2004 D. Scott Barninger - add Mandrake support * Wed Aug 04 2004 D. Scott Barninger - changed location of apcupsd.css to /etc/apcupsd from /etc/apcupsd/cgi - corrected typo introduced in SuSE configuration for initdir definition * Sun Apr 25 2004 D. Scott Barninger - add SuSE configuration * Sat Apr 24 2004 D. Scott Barninger - tidy up doc includes, add release notes * Mon Mar 08 2004 D. Scott Barninger - added additional clean of buildroot to beginning of install section - corrected post install routines for nicer chkconfig * Sat Jan 17 2004 D. Scott Barninger - added build of net driver to configure - moved usb driver build into both packages - set --with-serial-dev= to blank so will find any device and removed rh7 patch * Sat Jan 10 2004 D. Scott Barninger - added build tags for rh8 rh9 fedora_core and wb3 - cleaned up dependancies and Requires by platform * Thu Jan 1 2004 D. Scott Barninger - removed rh_version from package names - added platform build configuration section to beginning of file * Sat Nov 08 2003 Scott at fairfieldcomputers dot com - expanded usb devices from 0-9 to 0-15 * Fri Nov 07 2003 Scott at fairfieldcomputers dot com - corrected device path for usb devices to /dev/usb and added patch for - rh7 builds to make it /dev/usb/hid in /etc/apcupsd/apcupsd.conf * Sat Oct 18 2003 Scott at fairfieldcomputers dot com - added master-slave, apcsmart and dumb to configure options * Sun Sep 14 2003 Scott at fairfieldcomputers dot com - added rm commands during install to remove halt scripts created - in the build root * Mon May 11 2003 Scott at fairfieldcomputers dot com - combined layout for usb/serial builds * Thu Jan 16 2003 Scott at fairfieldcomputers dot com - Update spec to new source layout - Added masterconnect and mastertimout to files section - Changed make install-apcupsd and make install-cgi to make install * Wed Sep 05 2001 kern at sibbald dot com - Applied very nice patch to this spec by Giulio Orsero * Thu Sep 14 2000 kern at sibbald dot com - Many thanks to Fredrik Persson and Neil Darlow for helping me write this spec file. - Basic spec by Kern Sibbald apcupsd-3.14.14/platforms/suse/awkhaltprog.in000066400000000000000000000020761274230402600211710ustar00rootroot00000000000000# # Awk program to insert the necessary apcupsd script in # to a halt script. # # Suff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert our code just before this line /^# Set system console back to intial value/ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " @sysconfdir@/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # everything else is duplicated { print } apcupsd-3.14.14/platforms/unifix/000077500000000000000000000000001274230402600166345ustar00rootroot00000000000000apcupsd-3.14.14/platforms/unifix/Makefile000066400000000000000000000007561274230402600203040ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-unifix all-uninstall: uninstall-unifix install-unifix: $(call DISTINST,Unifix) @echo "You have to manually install apcupsd boot script and" @echo "halt script for clean emergency shutdown." @echo "I'm sorry: you are on your own." uninstall-unifix: $(call DISTUNINST,Unifix) @echo "You have to manually uninstall apcupsd boot script and" @echo "halt script." @echo "I'm sorry: you are on your own." apcupsd-3.14.14/platforms/unifix/halt.sh000077500000000000000000000007021274230402600201220ustar00rootroot00000000000000#! /bin/sh # # /etc/init.d/shutdown (and symlinked to reboot) # # This umount is wrong here, but one tester reported data loss without it. # If your partition gets destroyed, try to uncomment the umount. echo "Unmounting file systems" umount -a #Powerfail situation, kill power if [ -f /etc/powerfail ]; then echo "APCUPSD to the Rescue!" echo /sbin/apccontrol killpower echo fi echo "Halting System" exec halt >/dev/console 2>&1 apcupsd-3.14.14/platforms/unknown/000077500000000000000000000000001274230402600170315ustar00rootroot00000000000000apcupsd-3.14.14/platforms/unknown/Makefile000066400000000000000000000012001274230402600204620ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-unknown all-uninstall: uninstall-unknown install-unknown: $(call DISTINST,Unknown) @echo "You have to manually install apcupsd boot script and" @echo "halt script for clean emergency shutdown." @echo "Please contribute your distribution install to apcupsd team." @echo "I'm sorry: you are on your own." uninstall-unknown: $(call DISTUNINST,Unknown) @echo "You have to manually uninstall apcupsd boot script and" @echo "halt script." @echo "Please contribute your distribution install to apcupsd team." @echo "I'm sorry: you are on your own." apcupsd-3.14.14/platforms/unknown/apcupsd.in000066400000000000000000000016651274230402600210300ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 20 99 # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid DISTVER="@DISTVER@" return=" Done." case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting apcupsd power management" @sbindir@/apcupsd || return=" Failed." touch @LOCKDIR@/subsys/apcupsd echo -e "$return" ;; stop) echo -n "Stopping apcupsd power management" if [ -f ${APCPID} ]; then THEPID=`cat ${APCPID}` kill ${THEPID} || return=" Failed." rm -f ${APCPID} else return=" Failed." fi rm -f @LOCKDIR@/subsys/apcupsd echo -e "$return" ;; restart) $0 stop $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 esac exit 0 apcupsd-3.14.14/platforms/unknown/halt.in000066400000000000000000000026021274230402600203110ustar00rootroot00000000000000#! /bin/sh # Copyright (c) 1996 S.u.S.E. GmbH Fuerth, Germany. All rights reserved. # # Author: Florian La Roche , 1996 # Werner Fink , 1996 # # Updated for "apcupsd" # Andre M. Hedrick , 1997 # # /sbin/init.d/halt (and symlinked to reboot) # . /etc/rc.config case "$0" in *halt) message="The system is halted." command="halt" ;; *reboot) message="Please stand by while rebooting the system..." command="reboot" ;; *) echo "$0: call me as \"halt\" or \"reboot\" please!" exit 1 ;; esac # Write to wtmp file before unmounting /var $command -w echo "Sending all processes the TERM signal..." killall5 -15 if [ "$1" = "fast" ]; then sleep 1 else sleep 5 fi echo "Sending all processes the KILL signal..." killall5 -9 echo "Turning off swap." sync ; sync swapoff -a echo "Unmounting file systems" umount -av # maybe we use Multiple devices if test -f /etc/mdtab -a -x /sbin/mdadd ; then echo -n "Disable Multiple Devices" /sbin/mdstop -a echo "." fi # See if this is a powerfail situation. if [ -f @PWRFAILDIR@/powerfail ]; then echo echo "Apcupsd will now power off the UPS!" echo @sysconfdir@/apccontrol killpower echo fi # on umsdos fs this would lead to an error message. so direct errors to # /dev/null mount -no remount,ro / 2> /dev/null sync echo $message exec $command -d -f apcupsd-3.14.14/platforms/unknown/lfs-install-hint.txt000066400000000000000000000161041274230402600227640ustar00rootroot00000000000000TITLE: Apcupsd LFS VERSION: any AUTHOR: John McSwain SYNOPSIS: Installing Apcupsd to protect an LFS system using APC UPS. HINT: version 1.0 (06/27/2001) ======================== TABLE OF CONTENTS ======================== 1 Introduction 2 Software 3 Installation 3.1 Generic 3.2 LFS specific 3.2.1 Boot script 3.2.2 Poweroff script 3.2.3 Symlink the scripts 4 Configuration 5 Conclusion ================= 1. Introduction ================= Apcupsd is useful for controlling American Power Conversion's (APC) uninterruptiple power supplies (UPS). Apcupsd monitors the UPS and during a power loss, informs the system users of the failure, and if power is not restored, safely shuts down the system. The Apcupsd manual (available on line at http://www.sibbald.com/apcupsd/manual/index.html or with the software) provides excellent instructions on installing and configuring the software. The configure script can identify several standard linux distributions and make the correct installation. However, as LFS is by design not standard this hint provides the information to protect an LFS system with an APC UPS using Apcupsd. The installation of Apcupsd is mostly straightforward until "make install" is completed. Then the LFS user will see the following series of messages: "Unknown distribution You have to manually install apcupsd boot script and halt script for clean emergency shutdown. Please contribute your distribution install to apcupsd team. I'm sorry: you are on your own." The purpose of this hint is to provide one method of accomplishing the above actions to get Apcupsd up and running on the LFS "unknown" distribution. ================= 2. Software ================= The Apcupsd software can be found at these sites: http://www.oasi.gpa.it/riccardo/linux/apcupsd/ http://www.sibbald.com/apcupsd/ ftp://ftp.oasi.gpa.it/pub/apcupsd/ As of this writing the latest stable release is Apcupsd-3.8.1. However Apcupsd-3.8.2Beta14 has been used with no problems by this author. =================== 3. Installation =================== Obtain the source and unpack it in a suitable place such as /usr/src/. Compiler optimizations can be used with Apcupsd. See Optimization.txt hint and the Apcupsd manual for more information. =================== 3.1 Generic =================== Run the following command: ./configure --prefix=/usr --sbindir=/sbin This is a basic installation. If you have a smartups and wish to have a web interface to the APC unit's status from your web server see the Apcupsd manual. You will probably want to run the above commands with additions: ./configure --prefix=/usr --sbindir=/sbin \ --with-cgi-bin=/home/httpd/cgi-bin --enable-cgi Now run: make && make install =================== 3.2 LFS specific =================== At the end of the make install you will get the messages listed above in the introduction. A bootscript and proper halt script must be manually installed. ================== 3.2.1 Bootscript ================== Use the template script in /etc/init.d as a guide to make the boot script. cd /etc/init.d cp template apcupsd Now edit the apcupsd file to make the following bootscript: #!/bin/sh # Begin /etc/init.d/apcupsd # # S200 in /etc/rc{2,3,4,5}.d and K990 /etc/rc{0,1,6}.d # source /etc/init.d/functions case "$1" in start) # House keeping if this were a restart from powerfail rm -f /etc/apcupsd/powerfail rm -f /etc/nologin # Start apcupsd echo -n "Starting apcupsd power management ..." loadproc /sbin/apcupsd ;; stop) echo -n "Stopping apcupsd power management..." killproc apcupsd ;; reload) echo -n "Reloading apcupsd power management ..." reloadproc apcupsd ;; restart) $0 stop sleep 1 $0 start ;; status) statusproc apcupsd ;; *) echo "Usage: $0 {start|stop|reload|restart|status}" exit 1 ;; esac # End /etc/init.d/apcupsd ===================== 3.2.2 Poweroff script ===================== This poweroff script is needed to shutdown the UPS after the system has halted. (Note: Depending on the UPS this could take a minute or two). Thus when the power returns the UPS will come back on and the system will power up (providing your atx bios supports powerup). Apcupsd for most distributions modifies the existing halt script. Rather than that route we are making a separate script called UPSdown. Using a text editor create UPSdown as follows in /etc/init.d: #!/bin/sh # Begin /etc/init.d/UPSdown # # Script to shutdown UPS after computer shutdown # # Symlink in rc0.d after umounting filesystems # # # See if this is a powerfail situation if [ -f /etc/apcupsd/powerfail ]; then echo echo "APCUPSD will now power off the UPS" echo /etc/apcupsd/apccontrol killpower echo echo "Verify the UPS shuts down or turn off the system" echo fi # # End /etc/init.d/UPSdown ========================= 3.2.3 Symlink the scripts ========================= The apcupsd daemon should be started fairly soon in the boot cycle to provide protection. Using three digit symlinks, S200 for my system seems appropriate. Use your own judgement here. Stopping the daemon should occur fairly late. I use K990. The UPSdown script should be run immediately prior to the halt script. If halt is S999 then UPSdown would be S998. Run the following: cd /etc/init.d && chmod 754 apcupsd UPSdown && cd ../rc0.d && ln -s ../init.d/apcupsd K990apcupsd && ln -s ../init.d/UPSdown S998UPSdown && cd ../rc1.d && ln -s ../init.d/apcupsd K990apcupsd && cd ../rc2.d && ln -s ../init.d/apcupsd S200apcupsd && cd ../rc3.d && ln -s ../init.d/apcupsd S200apcupsd && cd ../rc4.d && ln -s ../init.d/apcupsd S200apcupsd && cd ../rc5.d && ln -s ../init.d/apcupsd S200apcupsd && cd ../rc6.d && ln -s ../init.d/apcupsd K990apcupsd ================ 4. Configuration ================ Our generic configure in 3.1 above placed the configuration file in /etc/apcupsd. This file is called apcupsd.conf. Pleae consult the apcupsd manual to determine the settings for your system and APC model UPS. ================ 5. Conclusion ============== The above steps were an attempt to have you quickly provide APC UPS power protection to your system using Apcupsd software. The software allows the individual user a lot of options depending on his needs and desires. For example I use the cgi feature to be able to see the status of my UPS from a browser. I use the notification feature to mail the electric company that I have loss power. These and other features along with a description of the workings of Apcupsd are fully described in the Apcupsd manual. apcupsd-3.14.14/platforms/yellowdog/000077500000000000000000000000001274230402600173375ustar00rootroot00000000000000apcupsd-3.14.14/platforms/yellowdog/Makefile000066400000000000000000000034021274230402600207760ustar00rootroot00000000000000topdir:=../.. SUBDIRS = include $(topdir)/autoconf/targets.mak all-install: install-yellowdog all-uninstall: uninstall-yellowdog install-yellowdog: $(call DISTINST,Yellowdog) # unlink old rc script (if not doing a DESTDIR install) $(call CHKCFG,del,/etc/rc.d/init.d/apcupsd) # install new rc script $(call MKDIR,/etc/rc.d/init.d) $(call INSTDATA,744,apcupsd,/etc/rc.d/init.d) # link new rc script (if not doing a DESTDIR install) $(call CHKCFG,add,/etc/rc.d/init.d/apcupsd) # save old halt script $(call COPY,/etc/rc.d/init.d/halt,/etc/rc.d/init.d/halt.old) # insert apcupsd callout into halt script @echo " PATCH" $(DESTDIR)/etc/rc.d/init.d/halt $(V)awk -f awkhaltprog $(DESTDIR)/etc/rc.d/init.d/halt.old >$(DESTDIR)/etc/rc.d/init.d/halt $(V)chmod 744 $(DESTDIR)/etc/rc.d/init.d/halt @echo "=================================================" @echo " " @echo "apcupsd script installation for RedHat $(DISTVER) complete." @echo " " @echo "You should now edit /etc/apcupsd/apcupsd.conf to correspond" @echo "to your setup then start the apcupsd daemon with:" @echo " " @echo "/etc/rc.d/init.d/apcupsd start" @echo " " @echo "thereafter when you reboot, it will be stopped and started" @echo "automatically." @echo " " @echo "Please check that your halt script in:" @echo " /etc/rc.d/init.d/halt" @echo "was properly updated (see installation section of manual)" @echo " " @echo "=================================================" uninstall-yellowdog: $(call DISTUNINST,Yellowdog) # unlink old rc script (if not doing a DESTDIR install) -$(call CHKCFG,del,/etc/rc.d/init.d/apcupsd) -$(call UNINST,/etc/rc.d/init.d/apcupsd) -$(call COPY,$(DESTDIR)/etc/rc.d/init.d/halt.old,/etc/rc.d/init.d/halt) -$(call UNINST,/etc/rc.d/init.d/halt.old) apcupsd-3.14.14/platforms/yellowdog/apcupsd.in000066400000000000000000000020401274230402600213220ustar00rootroot00000000000000#! /bin/sh # # apcupsd This shell script takes care of starting and stopping # the apcupsd UPS monitoring daemon. # # chkconfig: 2345 60 99 # description: apcupsd monitors power and takes action if necessary # APCPID=@PIDDIR@/apcupsd.pid DISTVER=`cat /etc/yellowdog-release | grep release | cut -f 5 -d ' '` # Source function libarary . /etc/rc.d/init.d/functions case "$1" in start) rm -f @PWRFAILDIR@/powerfail rm -f @nologdir@/nologin echo -n "Starting UPS monitoring:" daemon @sbindir@/apcupsd -f @sysconfdir@/apcupsd.conf RETVAL=$? echo [ $RETVAL -eq 0 ] && touch @LOCKDIR@/subsys/apcupsd ;; stop) echo -n "Shutting down UPS monitoring:" killproc apcupsd echo rm -f $APCPID rm -f @LOCKDIR@/subsys/apcupsd ;; restart) $0 stop sleep 15 $0 start ;; status) @sbindir@/apcaccess status ;; *) echo "Usage: $0 {start|stop|restart|status}" exit 1 ;; esac exit 0 apcupsd-3.14.14/platforms/yellowdog/apcupsd.spec.in000066400000000000000000000315541274230402600222670ustar00rootroot00000000000000# Platform configuration # # Select the platform by setting the define below either by command # line arguments, # e.g. rpmbuild -ba --define "build_rh7 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define rh7 1 # # If you want the usb version, use: # e.g. rpmbuild -ba --define "build_usb 1" --define "build_rh7 1" apcupsd.spec # or by manually setting it to 1 in this file, # e.g. %define usb 1 %define rh7 0 %{?build_rh7:%define rh7 1} %define rh8 0 %{?build_rh8:%define rh8 1} %define rh9 0 %{?build_rh9:%define rh9 1} %define fc1 0 %{?build_fc1:%define fc1 1} %define wb3 0 %{?build_wb3:%define wb3 1} %define usb 0 %{?build_usb:%define usb 1} %define initdir /etc/rc.d/init.d Summary: APC UPS Power Control Daemon for Linux Name: apcupsd Version: @VERSION@ Release: 1 Vendor: APC UPS Daemon Team Distribution: The apcupsd Team Packager: D. Scott Barninger URL: http://www.sibbald.com/apcupsd/ Source: http://www.sibbald.com/apcupsd/%{name}-%{version}.tar.gz Group: System Environment/Daemons Copyright: GPL v2 BuildRoot: %{_tmppath}/%{name}-root BuildRequires: gd-devel %if %{rh7} BuildRequires: glibc-devel >= 2.2 %else BuildRequires: glibc-devel >= 2.3 %endif %description Apcupsd can be used for controlling most APC UPSes. During a power failure, apcupsd will inform the users about the power failure and that a shutdown may occur. If power is not restored, a system shutdown will follow when the battery is exausted, a timeout (seconds) expires, or the battery runtime expires based on internal APC calculations determined by power consumption rates. If the power is restored before one of the above shutdown conditions is met, apcupsd will inform users about this fact. Some features depend on what UPS model you have (simple or smart). %if %{usb} %package usb %else %package std %endif Provides: apcupsd Requires: perl %if %{fc1} Requires: gd >= 2.0 %else Requires: gd < 2.0 %endif %if %{rh7} Requires: glibc >= 2.2 %else Requires: glibc >= 2.3 %endif Summary: APC UPS Power Control Daemon for Linux Group: System Environment/Daemons %if %{usb} %description usb %else %description std %endif Apcupsd can be used for controlling most APC UPSes. During a power failure, apcupsd will inform the users about the power failure and that a shutdown may occur. If power is not restored, a system shutdown will follow when the battery is exausted, a timeout (seconds) expires, or the battery runtime expires based on internal APC calculations determined by power consumption rates. If the power is restored before one of the above shutdown conditions is met, apcupsd will inform users about this fact. Some features depend on what UPS model you have (simple or smart). %if %{usb} This package is built with USB support. %else This package is built with standard serial port support. %endif %prep %setup %build %configure \ --prefix=%{_prefix} \ --sbindir=/sbin \ --sysconfdir=%{_sysconfdir}/apcupsd \ --with-cgi-bin=%{_sysconfdir}/apcupsd/cgi \ --enable-cgi \ --enable-pthreads \ --enable-net \ --enable-master-slave \ --enable-apcsmart \ --enable-dumb \ --enable-usb \ %if %{usb} --with-serial-dev= \ --with-upstype=usb \ --with-upscable=usb %endif make %if %{usb} cd examples make hid-ups cd ../ %endif %install mkdir -p $RPM_BUILD_ROOT%{initdir} mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/cgi make \ DESTDIR=$RPM_BUILD_ROOT \ install # This should no longer be necessary - see Jan 17 2004 changelog note below # RedHat 7 put usb hid devices in /dev/usd/hid directory rather than /dev/usb # which follows usb standard. This was corrected with RedHat 8 so we patch the # apcupsd.conf file as created by our configure statement above for rh7 builds. #%if %{usb} && %{rh7} #patch $RPM_BUILD_ROOT/etc/apcupsd/apcupsd.conf platforms/redhat/apcupsd.conf.patch #%endif install -m744 platforms/apccontrol \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/apccontrol install -m755 platforms/yellowdog/apcupsd $RPM_BUILD_ROOT%{initdir} rm $RPM_BUILD_ROOT%{initdir}/halt rm $RPM_BUILD_ROOT%{initdir}/halt.old %if %{usb} install -m744 examples/hid-ups \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/hid-ups install -m744 examples/make-hiddev \ $RPM_BUILD_ROOT%{_sysconfdir}/apcupsd/make-hiddev %endif %clean [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf $RPM_BUILD_ROOT %if %{usb} %files usb %defattr(-,root,root) %doc COPYING ChangeLog INSTALL doc/* examples %dir /etc/apcupsd %dir /etc/apcupsd/cgi %{initdir}/apcupsd %config(noreplace) /etc/apcupsd/apccontrol %config(noreplace) /etc/apcupsd/changeme %config(noreplace) /etc/apcupsd/commfailure %config(noreplace) /etc/apcupsd/commok %config(noreplace) /etc/apcupsd/onbattery %config(noreplace) /etc/apcupsd/offbattery %config(noreplace) /etc/apcupsd/apcupsd.conf %config(noreplace) /etc/apcupsd/hosts.conf %config(noreplace) /etc/apcupsd/multimon.conf /etc/apcupsd/make-hiddev /etc/apcupsd/hid-ups /etc/apcupsd/cgi/* /sbin/* %attr(-,root,man) %{_mandir}/*/* %pre usb %post usb # get rid of any 3.6.2 stuff rm -f /etc/rc.d/rc[0-6].d/[KS]20apcups rm -f /etc/rc.d/init.d/apcups # delete then add our links /sbin/chkconfig --del apcupsd /sbin/chkconfig --add apcupsd cp -f /etc/rc.d/init.d/halt /etc/rc.d/init.d/halt.old awk '# Stuff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert the new apcupsd code just before the following line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " @PWRFAILDIR@/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # Everything else is duplicated { print } ' /etc/rc.d/init.d/halt.old > /etc/rc.d/init.d/halt chmod 744 /etc/rc.d/init.d/halt # Undo things a bit %preun usb if [ $1 = 0 ] ; then # stop running version (if any) # I have removed the following because it sometimes produces # an error message which may confuse someone. #/sbin/service apcupsd stop # remove startup links /sbin/chkconfig --del apcupsd # restore old halt script (hopefully) # mv -f /etc/rc.d/init.d/halt.old /etc/rc.d/init.d/halt cp -f /etc/rc.d/init.d/halt /etc/rc.d/init.d/halt.old awk '# Stuff added by apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # Everything else is duplicated { print } ' /etc/rc.d/init.d/halt.old > /etc/rc.d/init.d/halt chmod 744 /etc/rc.d/init.d/halt fi %postun usb if [ "$1" -ge "1" ]; then : # /sbin/service apcupsd condrestart >/dev/null 2>&1 || : fi %else %files std %defattr(-,root,root) %doc COPYING ChangeLog INSTALL doc/* examples %dir /etc/apcupsd %dir /etc/apcupsd/cgi %{initdir}/apcupsd %config(noreplace) /etc/apcupsd/apccontrol %config(noreplace) /etc/apcupsd/changeme %config(noreplace) /etc/apcupsd/commfailure %config(noreplace) /etc/apcupsd/commok %config(noreplace) /etc/apcupsd/onbattery %config(noreplace) /etc/apcupsd/offbattery %config(noreplace) /etc/apcupsd/apcupsd.conf %config(noreplace) /etc/apcupsd/hosts.conf %config(noreplace) /etc/apcupsd/multimon.conf /etc/apcupsd/cgi/* /sbin/* %attr(-,root,man) %{_mandir}/*/* %pre std %post std # get rid of any 3.6.2 stuff rm -f /etc/rc.d/rc[0-6].d/[KS]20apcups rm -f /etc/rc.d/init.d/apcups # delete then add our links /sbin/chkconfig --del apcupsd /sbin/chkconfig --add apcupsd cp -f /etc/rc.d/init.d/halt /etc/rc.d/init.d/halt.old awk '# Stuff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert the new apcupsd code just before the following line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " @PWRFAILDIR@/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # Everything else is duplicated { print } ' /etc/rc.d/init.d/halt.old > /etc/rc.d/init.d/halt chmod 744 /etc/rc.d/init.d/halt # Undo things a bit %preun std if [ $1 = 0 ] ; then # stop running version (if any) # I have removed the following because it sometimes produces # an error message which may confuse someone. #/sbin/service apcupsd stop # remove startup links /sbin/chkconfig --del apcupsd # restore old halt script (hopefully) # mv -f /etc/rc.d/init.d/halt.old /etc/rc.d/init.d/halt cp -f /etc/rc.d/init.d/halt /etc/rc.d/init.d/halt.old awk '# Stuff added by apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # Everything else is duplicated { print } ' /etc/rc.d/init.d/halt.old > /etc/rc.d/init.d/halt chmod 744 /etc/rc.d/init.d/halt fi %postun std if [ "$1" -ge "1" ]; then : # /sbin/service apcupsd condrestart >/dev/null 2>&1 || : fi %endif %changelog * Sat Dec 09 2006 Adam Kropelin - Remove obsolete masterconnect and mastertimeout scripts * Sat Jan 17 2004 D. Scott Barninger - added build of net driver to configure - moved usb driver build into both packages - set --with-serial-dev= to blank so will find any device and removed rh7 patch * Sat Jan 10 2004 D. Scott Barninger - added build tags for rh8 rh9 fc1 and wb3 - cleaned up dependancies and Requires by platform * Thu Jan 1 2004 D. Scott Barninger - removed rh_version from package names - added platform build configuration section to beginning of file * Sat Nov 08 2003 Scott at fairfieldcomputersdot com - expanded usb devices from 0-9 to 0-15 * Fri Nov 07 2003 Scott at fairfieldcomputers dot com - corrected device path for usb devices to /dev/usb and added patch for - rh7 builds to make it /dev/usb/hid in /etc/apcupsd/apcupsd.conf * Sat Oct 18 2003 Scott at fairfieldcomputers dot com - added master-slave, apcsmart and dumb to configure options * Sun Sep 14 2003 Scott at fairfieldcomputers dot com - added rm commands during install to remove halt scripts created - in the build root * Mon May 11 2003 Scott at fairfieldcomputers dot com - combined layout for usb/serial builds * Thu Jan 16 2003 Scott at fairfieldcomputers dot com - Update spec to new source layout - Added masterconnect and mastertimout to files section - Changed make install-apcupsd and make install-cgi to make install * Wed Sep 05 2001 kern at sibbald dot com - Applied very nice patch to this spec by Giulio Orsero * Thu Sep 14 2000 kern at sibbald dot com - Many thanks to Fredrik Persson and Neil Darlow for helping me write this spec file. - Basic spec by Kern Sibbald apcupsd-3.14.14/platforms/yellowdog/awkhaltprog.in000066400000000000000000000020451274230402600222130ustar00rootroot00000000000000# # Awk program to insert the necessary apcupsd script in # to a halt script. # # Suff left over from a previous apcupsd, remove it /^# See if this is a powerfail situation\./ { do { getline } while (length($0) != 0) getline } # We insert our code just before this line /^# Now halt or reboot\./ { print "# See if this is a powerfail situation. # ***apcupsd***" print "if [ -f @PWRFAILDIR@/powerfail ]; then # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"APCUPSD will now power off the UPS\" # ***apcupsd***" print " echo # ***apcupsd***" print " @sysconfdir@/apccontrol killpower # ***apcupsd***" print " echo # ***apcupsd***" print " echo \"Please ensure that the UPS has powered off before rebooting\" # ***apcupsd***" print " echo \"Otherwise, the UPS may cut the power during the reboot!!!\" # ***apcupsd***" print " echo # ***apcupsd***" print "fi # ***apcupsd***" print "" } # everything else is duplicated { print } apcupsd-3.14.14/src/000077500000000000000000000000001274230402600141125ustar00rootroot00000000000000apcupsd-3.14.14/src/Makefile000066400000000000000000000035411274230402600155550ustar00rootroot00000000000000topdir:=.. SUBDIRS = lib drivers $(CGIDIR) $(USBHIDDIR) $(GAPCMON) $(APCAGENT) $(WIN32) include $(topdir)/autoconf/targets.mak # Force dirs that needs libapc.a to build after lib_DIR # Necessary for parallel make since they link against libapc.a cgi_DIR: lib_DIR apcagent_DIR: lib_DIR win32_DIR: lib_DIR # CGI requires win32, but only if building for win32 cgi_DIR: $(if $(WIN32),win32_DIR) common_srcs := options.c device.c reports.c action.c apcupsd_srcs := apcupsd.c apcnis.c apcaccess_srcs := apcaccess.c apctest_srcs := apctest.c smtp_srcs := smtp.c common_obj := $(call SRC2OBJ,$(common_srcs)) apcupsd_obj := $(call SRC2OBJ,$(apcupsd_srcs)) $(if $(WIN32),$(call SRC2OBJ,win32/winservice.cpp win32/winmain.cpp)) apcaccess_obj := $(call SRC2OBJ,$(apcaccess_srcs)) apctest_obj := $(call SRC2OBJ,$(apctest_srcs)) smtp_obj := $(call SRC2OBJ,$(smtp_srcs)) SRCS = $(common_srcs) $(apcupsd_srcs) $(apcaccess_srcs) \ $(apctest_srcs) $(smtp_srcs) all-targets: apcupsd$(EXE) apcaccess$(EXE) apctest$(EXE) smtp$(EXE) apcupsd$(EXE): $(common_obj) $(apcupsd_obj) $(APCDRVLIBS) $(APCLIBS) $(LINK) $(DRVLIBS) $(BG) apctest$(EXE): $(common_obj) $(apctest_obj) $(APCDRVLIBS) $(APCLIBS) $(LINK) $(DRVLIBS) apcaccess$(EXE): $(apcaccess_obj) $(APCLIBS) $(LINK) smtp$(EXE): $(smtp_obj) $(APCLIBS) $(LINK) all-install: install-base all-uninstall: uninstall-base install-base: $(call MKDIR,$(sbindir)) $(call INSTPROG,700,apcupsd,$(sbindir)/apcupsd$(EXE)) $(call INSTPROG,700,apctest,$(sbindir)/apctest$(EXE)) $(call INSTPROG,755,apcaccess,$(sbindir)/apcaccess$(EXE)) $(call INSTPROG,755,smtp,$(sbindir)/smtp$(EXE)) uninstall-base: $(call UNINST,$(sbindir)/apcupsd$(EXE)) $(call UNINST,$(sbindir)/apctest$(EXE)) $(call UNINST,$(sbindir)/apcaccess$(EXE)) $(call UNINST,$(sbindir)/smtp$(EXE)) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/action.c000066400000000000000000000536111274230402600155410ustar00rootroot00000000000000/* * apcaction.c * * Actions taken when something happens to the UPS. */ /* * Copyright (C) 2000-2004 Kern Sibbald * Copyright (C) 1996-1999 Andre M. Hedrick * Copyright (C) 1999-2000 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" extern int kill_on_powerfail; static void do_shutdown(UPSINFO *ups, int cmdtype); /* * These are the commands understood by the apccontrol shell script. * You _must_ keep the the commands[] array in sync with the defines in * include/apc_defines.h */ UPSCOMMANDS ups_event[] = { {"powerout", 0}, /* CMDPOWEROUT */ {"onbattery", 0}, /* CMDONBATTERY */ {"failing", 0}, /* CMDFAILING */ {"timeout", 0}, /* CMDTIMEOUT */ {"loadlimit", 0}, /* CMDLOADLIMIT */ {"runlimit", 0}, /* CMDRUNLIMIT */ {"doshutdown", 0}, /* CMDDOSHUTDOWN */ {"mainsback", 0}, /* CMDMAINSBACK */ {"annoyme", 0}, /* CMDANNOYME */ {"emergency", 0}, /* CMDEMERGENCY */ {"changeme", 0}, /* CMDCHANGEME */ {"remotedown", 0}, /* CMDREMOTEDOWN */ {"commfailure", 0}, /* CMDCOMMFAILURE */ {"commok", 0}, /* CMDCOMMOK */ {"startselftest", 0}, /* CMDSTARTSELFTEST */ {"endselftest", 0}, /* CMDENDSELFTEST */ {"offbattery", 0}, /* CMDOFFBATTERY */ {"battdetach", 0}, /* CMDBATTDETACH */ {"battattach", 0} /* CMDBATTATTACH */ }; /* * These messages must be kept in sync with the above array * and the defines in include/apc_defines.h */ UPSCMDMSG event_msg[] = { {LOG_CRIT, "Power failure."}, {LOG_CRIT, "Running on UPS batteries."}, {LOG_ALERT, "Battery power exhausted."}, {LOG_ALERT, "Reached run time limit on batteries."}, {LOG_ALERT, "Battery charge below low limit."}, {LOG_ALERT, "Reached remaining time percentage limit on batteries."}, {LOG_ALERT, "Initiating system shutdown!"}, {LOG_ALERT, "Power is back. UPS running on mains."}, {LOG_ALERT, "Users requested to logoff."}, {LOG_ALERT, "Battery failure. Emergency."}, {LOG_CRIT, "UPS battery must be replaced."}, {LOG_CRIT, "Remote shutdown requested."}, {LOG_WARNING, "Communications with UPS lost."}, {LOG_WARNING, "Communications with UPS restored."}, {LOG_WARNING, "UPS Self Test switch to battery."}, {LOG_WARNING, "UPS Self Test completed."}, {LOG_CRIT, "Mains returned. No longer on UPS batteries."}, {LOG_CRIT, "Battery disconnected."}, {LOG_CRIT, "Battery reattached."} }; void generate_event(UPSINFO *ups, int event) { /* Log message and execute script for this event */ log_event(ups, event_msg[event].level, event_msg[event].msg); Dmsg(80, "calling execute_ups_event %s event=%d\n", ups_event[event], event); execute_command(ups, ups_event[event]); /* * Additional possible actions. For certain, we now do a * shutdown */ switch (event) { /* * For the following, in addition to the basic, * message logged and executed above, we do a * system shutdown. */ case CMDFAILING: case CMDTIMEOUT: case CMDRUNLIMIT: case CMDLOADLIMIT: case CMDEMERGENCY: case CMDREMOTEDOWN: log_event(ups, event_msg[CMDDOSHUTDOWN].level, event_msg[CMDDOSHUTDOWN].msg); do_shutdown(ups, CMDDOSHUTDOWN); break; /* For the following, everything is already done. */ case CMDSTARTSELFTEST: case CMDENDSELFTEST: case CMDCOMMFAILURE: case CMDCOMMOK: case CMDCHANGEME: case CMDANNOYME: case CMDMAINSBACK: case CMDDOSHUTDOWN: /* Already shutdown, don't recall */ case CMDPOWEROUT: case CMDONBATTERY: case CMDOFFBATTERY: case CMDBATTDETACH: case CMDBATTATTACH: default: break; } } /* * Closes procfile and logfile to preserve information. * * ok = 1 => power is back * ok = 2 => power failure * ok = 3 => remote shutdown */ static void powerfail(int ok) { /* * If apcupsd terminates here, it will never get a chance to * report the event of returning mains-power. I think apcupsd * has no need to force terminate() by itself. It will receive * a SIGTERM from init, when system goes down. This signal is * trapped and will trigger apcupsd's terminate() function. */ if (ok == 2) { clear_files(); if (terminate_on_powerfail) { /* * This sends a SIGTERM signal to itself. * The SIGTERM is bound to apcupsd_ or apctest_terminate(), * depending on which program is running this code, so it will * do in anyway the right thing. */ sendsig_terminate(); } } /* * For network slaves, apcupsd needs to terminate here for now. * This is sloppy, but it works. If you are networked, then the * master must fall also. This is required so that the UPS * can reboot the slaves. */ if (ok == 3) sendsig_terminate(); } /* * If called with zero, prevent users from logging in. * If called with one, allow users to login. */ static void logonfail(UPSINFO *ups, int ok) { int lgnfd; unlink(ups->nologinpath); if (ok == 0 && ((lgnfd = open(ups->nologinpath, O_CREAT | O_WRONLY | O_CLOEXEC, 0644)) >= 0)) { write(lgnfd, POWERFAIL, strlen(POWERFAIL)); close(lgnfd); } } static void prohibit_logins(UPSINFO *ups) { if (ups->nologin_file) return; /* already done */ logonfail(ups, 0); ups->nologin_file = true; log_event(ups, LOG_ALERT, "User logins prohibited"); } static void do_shutdown(UPSINFO *ups, int cmdtype) { if (ups->is_shutdown()) return; /* already done */ ups->ShutDown = time(NULL); ups->set_shutdown(); delete_lockfile(ups); ups->set_fastpoll(); make_file(ups, ups->pwrfailpath); prohibit_logins(ups); if (!ups->is_slave()) { /* * Note, try avoid using this option if at all possible * as it will shutoff the UPS power, and you cannot * be guaranteed that the shutdown command will have * succeeded. This PROBABLY should be executed AFTER * the shutdown command is given (the execute_command below). */ if (kill_on_powerfail) initiate_hibernate(ups); } /* Now execute the shutdown command */ execute_command(ups, ups_event[cmdtype]); /* * On some systems we may stop on the previous * line if a SIGTERM signal is sent to us. */ if (cmdtype == CMDREMOTEDOWN) powerfail(3); else powerfail(2); } /* These are the different "states" that the UPS can be in. */ enum a_state { st_PowerFailure, st_SelfTest, st_OnBattery, st_MainsBack, st_OnMains, st_Calibration }; /* * Figure out what "state" the UPS is in and * return it for use in do_action() */ static enum a_state get_state(UPSINFO *ups, time_t now) { enum a_state state; /* If we're on battery for calibration, treat as not on battery */ if (ups->is_onbatt()) { if (ups->is_calibration()) { state = st_Calibration; } else if (ups->chg_onbatt()) { state = st_PowerFailure; /* Power failure just detected */ } else { if (ups->SelfTest) /* see if UPS is doing self test */ state = st_SelfTest; /* yes */ else state = st_OnBattery; /* No, this must be real power failure */ } } else { if (ups->chg_onbatt()) /* if we were on batteries */ state = st_MainsBack; /* then we just got power back */ else state = st_OnMains; /* Solid on mains, normal condition */ } return state; } static const char *testresult_to_string(SelfTestResult res) { switch (res) { case TEST_NA: return "Not supported"; case TEST_NONE: return "No test results available"; case TEST_FAILED: return "Test failed"; case TEST_WARNING: return "Warning"; case TEST_INPROGRESS: return "In progress"; case TEST_PASSED: return "Battery OK"; case TEST_FAILCAP: return "Test failed -- insufficient battery capacity"; case TEST_FAILLOAD: return "Test failed -- battery overloaded"; case TEST_UNKNOWN: default: return "Unknown"; } } /* * Carl Lindberg patch applied 24Dec04 * * The APC network management cards have options to shut down, reboot, or * "sleep" (really just a delayed reboot) the UPS. For all of these, it * has a "graceful" option, meaning it gives the PowerChute software a * chance to cleanly shutdown the machine before the UPS is shut down. To * do this, the card sets the ONBATT and LOWBATT statuses at the same * time, waits several minutes, then cuts power. PowerChute (presumably) * notices this and shuts the machine down, but unfortunately apcupsd did * not. * * The problem happens because in this situation, apcupsd sets the * UPS_prev_battlow status before testing for it. In the do_action() * function, apcupsd notices the ONBATT status, and uses the * "st_PowerFailure" state to send off an initial power failure event. * After a short delay, do_action() is invoked again. If ONBATT is * still set, the "st_OnBattery" state is used, and the onbattery event * (among other things) is sent. * * The test for LOWBATT to see if shutdown is needed is only done in the * st_OnBattery state, and it's done if LOWBATT is set but * UPS_prev_battlow is not set yet. In normal operation, LOWBATT will * only come on after a period of ONBATT, and this situation works fine. * However, since ONBATT and LOWBATT were set simultaneously, the * UPS_prev_battlow was set the first time through, when the * st_PowerFailure was used, meaning the test for LOWBATT was not * performed. The second time through in st_OnBattery, UPS_prev_battlow * is already set, meaning apcupsd is assuming that the needed shutdown * has already been invoked. * * The code fix just moves setting of the UPS_prev_battlow status to * inside the block that tests for it, ensuring that LOWBATT will never be * ignored. Clearing the UPS_prev_battlow status remains where it is in * the code, and it will always be turned off if LOWBATT is no longer set. * * After the fix, UPS_prev_battlow is not prematurely set, and apcupsd * catches the signal from the management card to shut down. I've had the * code in for over a month, and it's worked fine, both from using the * management card and regular pull-the-plug tests as well. This was * only tested with a serial UPS, but I assume it would be a problem with * USB and SNMP connections as well. */ /*********************************************************************/ void do_action(UPSINFO *ups) { time_t now; static int requested_logoff = 0; /* asked user to logoff */ static int first = 1; enum a_state state; write_lock(ups); time(&now); /* get current time */ if (first) { first = 0; ups->last_time_nologon = ups->last_time_annoy = now; ups->last_time_on_line = now; /* * This is cheating slightly. We want to initialize the previous * status to zero so all set bits in current status will appear * as changes, thus allowing us to handle starting up when power * has already failed, for instance. However, we don't want to * get a BATTATTACHED event every time the daemon starts, so we * set the UPS_battpresent bit in the previous status. */ ups->PrevStatus = UPS_battpresent; } if (ups->is_replacebatt()) { /* Replace battery */ /* * Complain every 9 hours, this causes the complaint to * cycle around the clock and hopefully be more noticable * without being too annoying. Also, ignore all change battery * indications for the first 10 minutes of running time to * prevent false alerts. Finally, issue the event 5 times, then * clear the flag to silence false alarms. If the battery is * really dead, the flag will be reset in apcsmart.c * * UPS_replacebatt is a flag. To count use a static local counter. * The counter is initialized only one time at startup. */ if (now - ups->start_time < 60 * 10 || ups->ChangeBattCounter > 5) { ups->clear_replacebatt(); ups->ChangeBattCounter = 0; } else if (now - ups->last_time_changeme > 60 * 60 * 9) { generate_event(ups, CMDCHANGEME); ups->last_time_changeme = now; ups->ChangeBattCounter++; } } /* Remote is shutting down, so must we. */ if (ups->is_shut_remote()) { if (ups->chg_shut_remote()) { generate_event(ups, CMDREMOTEDOWN); } ups->PrevStatus = ups->Status; write_unlock(ups); return; } /* Generate event if battery is disconnected or reattached */ if (ups->chg_battpresent()) { if (ups->is_battpresent()) generate_event(ups, CMDBATTATTACH); else generate_event(ups, CMDBATTDETACH); } /* * Did BattLow bit go high? If so, start the battlow shutdown * timer. We will only act on this timer if we switch to battery * (or are already on battery). It is possible that this event occurs * at the same time as or even slightly before we switch to battery. * Therefore we must check it every time we get new status. */ if (ups->chg_battlow()) { if (ups->is_battlow()) { Dmsg(100, "BATTLOW asserted\n"); ups->start_shut_lbatt = now; } else { Dmsg(100, "BATTLOW glitch\n"); } } state = get_state(ups, now); switch (state) { case st_OnMains: /* If power is good, update the timers. */ ups->last_time_nologon = ups->last_time_annoy = now; ups->last_time_on_line = now; ups->clear_fastpoll(); break; case st_PowerFailure: /* This is our first indication of a power problem */ ups->set_fastpoll(); /* speed up polling */ /* Check if selftest */ Dmsg(80, "Power failure detected. 0x%x\n", ups->Status); device_entry_point(ups, DEVICE_CMD_CHECK_SELFTEST, NULL); if (ups->SelfTest) generate_event(ups, CMDSTARTSELFTEST); else generate_event(ups, CMDPOWEROUT); ups->last_time_nologon = ups->last_time_annoy = now; ups->last_time_on_line = now; ups->last_onbatt_time = now; ups->num_xfers++; /* Enable DTR on dumb UPSes with CUSTOM_SIMPLE cable. */ device_entry_point(ups, DEVICE_CMD_DTR_ENABLE, NULL); break; case st_SelfTest: /* allow 40 seconds max for selftest */ if (now - ups->SelfTest < 40 && !ups->is_battlow()) break; /* Cancel self test, announce power failure */ ups->SelfTest = 0; Dmsg(80, "UPS Self Test cancelled, fall-thru to On Battery. 0x%x\n", ups->Status); /* ...FALL-THRU to st_OnBattery... */ case st_OnBattery: /* Did the second test verify the power is failing? */ if (!ups->is_onbatt_msg() && time(NULL) - ups->last_time_on_line >= ups->onbattdelay) { ups->set_onbatt_msg(); /* it is confirmed, we are on batteries */ generate_event(ups, CMDONBATTERY); ups->last_time_nologon = ups->last_time_annoy = now; ups->last_time_on_line = now; break; } /* shutdown requested but still running */ if (ups->is_shutdown()) { if (ups->killdelay && now - ups->ShutDown >= ups->killdelay) { if (!ups->is_slave()) initiate_hibernate(ups); ups->ShutDown = now; /* wait a bit before doing again */ ups->set_shutdown(); } } else { /* not shutdown yet */ /* * Did MaxTimeOnBattery Expire? (TIMEOUT in apcupsd.conf) * Normal Power down during Power Failure: Shutdown immediately. */ if ((ups->maxtime > 0) && ((now - ups->last_time_on_line) > ups->maxtime)) { ups->set_shut_btime(); generate_event(ups, CMDTIMEOUT); break; } /* * Did Battery Charge or Runtime go below percent cutoff? * Normal Power down during Power Failure: Start shutdown timer. */ if (ups->UPS_Cap[CI_BATTLEV] && ups->BattChg <= ups->percent) { if (!ups->is_shut_load()) { Dmsg(100, "CI_BATTLEV shutdown\n"); ups->set_shut_load(); ups->start_shut_load = now; } } else { if (ups->UPS_Cap[CI_BATTLEV] && ups->is_shut_load()) Dmsg(100, "CI_BATTLEV glitch\n"); ups->clear_shut_load(); } if (ups->UPS_Cap[CI_RUNTIM] && ups->TimeLeft <= ups->runtime) { if (!ups->is_shut_ltime()) { Dmsg(100, "CI_RUNTIM shutdown\n"); ups->set_shut_ltime(); ups->start_shut_ltime = now; } } else { if (ups->UPS_Cap[CI_RUNTIM] && ups->is_shut_ltime()) Dmsg(100, "CI_RUNTIM glitch\n"); ups->clear_shut_ltime(); } /* * Check for expired shutdown timers and act on them. */ if (ups->is_battlow() && ((now - ups->start_shut_lbatt) >= 5)) { generate_event(ups, CMDFAILING); break; } if (ups->is_shut_load() && ((now - ups->start_shut_load) >= 5)) { generate_event(ups, CMDLOADLIMIT); break; } if (ups->is_shut_ltime() && ((now - ups->start_shut_ltime) >= 5)) { generate_event(ups, CMDRUNLIMIT); break; } /* * We are on batteries, the battery is low, and the power is not * down ==> the battery is dead. KES Sept 2000 * * Then the battery has failed!!! * Must do Emergency Shutdown NOW */ if (ups->is_battlow() && ups->is_online()) { ups->set_shut_emerg(); generate_event(ups, CMDEMERGENCY); } /* Announce to LogOff, with initial delay. */ if (((now - ups->last_time_on_line) > ups->annoydelay) && ((now - ups->last_time_annoy) > ups->annoy) && ups->nologin_file) { if (!requested_logoff) { /* generate log message once */ generate_event(ups, CMDANNOYME); } else { /* but execute script every time */ execute_command(ups, ups_event[CMDANNOYME]); } time(&ups->last_time_annoy); requested_logoff = true; } /* Delay NoLogons. */ if (!ups->nologin_file) { switch (ups->nologin.type) { case NEVER: break; case TIMEOUT: if ((now - ups->last_time_nologon) > ups->nologin_time) prohibit_logins(ups); break; case PERCENT: if (ups->UPS_Cap[CI_BATTLEV] && ups->nologin_time >= ups->BattChg) prohibit_logins(ups); break; case MINUTES: if (ups->UPS_Cap[CI_RUNTIM] && ups->nologin_time >= ups->TimeLeft) prohibit_logins(ups); break; case ALWAYS: default: prohibit_logins(ups); break; } } } break; case st_MainsBack: /* The power is back after a power failure or a self test */ if (ups->is_onbatt_msg()) { ups->clear_onbatt_msg(); generate_event(ups, CMDOFFBATTERY); } if (ups->SelfTest) { ups->LastSelfTest = ups->SelfTest; ups->SelfTest = 0; /* Get last selftest results, only for smart UPSes. */ device_entry_point(ups, DEVICE_CMD_GET_SELFTEST_MSG, NULL); log_event(ups, LOG_ALERT, "UPS Self Test completed: %s", testresult_to_string(ups->testresult)); execute_command(ups, ups_event[CMDENDSELFTEST]); } else { generate_event(ups, CMDMAINSBACK); } if (ups->nologin_file) log_event(ups, LOG_ALERT, "Allowing logins"); logonfail(ups, 1); ups->nologin_file = false; requested_logoff = false; device_entry_point(ups, DEVICE_CMD_DTR_ST_DISABLE, NULL); ups->last_offbatt_time = now; /* * Sanity check. Sometimes only first power problem trips * thus last_onbatt_time is not set when we get here. */ if (ups->last_onbatt_time <= 0) ups->last_onbatt_time = ups->last_offbatt_time; ups->cum_time_on_batt += (ups->last_offbatt_time - ups->last_onbatt_time); break; case st_Calibration: /* * During calibration we ignore battery level, runtime remaining, etc. * since the UPS will switch us back online when it is done. We also have * no timeout here since we can't predict how long the calibration will * take. */ break; default: break; } /* Do a non-blocking wait on any exec()ed children */ if (ups->num_execed_children > 0) { while (waitpid(-1, NULL, WNOHANG) > 0) ups->num_execed_children--; } /* Remember status */ ups->PrevStatus = ups->Status; write_unlock(ups); } apcupsd-3.14.14/src/apcaccess.c000066400000000000000000000140741274230402600162110ustar00rootroot00000000000000/* * apcaccess.c * * Text based IPC management tool for apcupsd package. */ /* * Copyright (C) 2000-2006 Kern Sibbald * Copyright (C) 1996-99 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" /* These are all the possible unit labels generated in src/lib/apcstatus.c * -u removes them. (To make life easier for scripts.) */ const char *const units[] = { " Minutes\n", " Seconds\n", " Percent\n", " Volts\n", " Watts\n", " Hz\n", " C\n", }; /* Behavior modifying flags */ #define NO_UNITS 0x1 /* Get and print status from apcupsd NIS server */ static int do_pthreads_status(const char *host, int port, const char *par, int flags) { sock_t sockfd; int n; char recvline[MAXSTRING + 1]; char *line; if ((sockfd = net_open(host, NULL, port)) < 0) { fprintf(stderr, "Error contacting apcupsd @ %s:%d: %s\n", host, port, strerror(-sockfd)); return 1; } net_send(sockfd, "status", 6); while ((n = net_recv(sockfd, recvline, sizeof(recvline))) > 0) { recvline[n] = 0; line = recvline; if (par) { /* Check for match against parameter name */ char *r = NULL; char *var; var = strtok_r(recvline, ":", &r); if (!var) // No : separator? Skip it. continue; line = recvline + strlen(var) + 1; if ((r = strchr(var, ' '))) *r = '\0'; if (strcmp(par, var)) // Doesn't match parameter? Skip it. continue; while (*line == ' ') line++; } if (flags & NO_UNITS) { /* Remove units labels */ size_t i; for (i = 0; i < sizeof units / sizeof units[0]; i++) { const char * const u = units[i]; size_t ulen = strlen(u); size_t llen = strlen(line); if (llen >= ulen && !strcmp (line + llen - ulen, u)) { line[llen - ulen] = '\n'; line[llen+1 - ulen] = '\0'; break; } } } fputs(line, stdout); // If we had a param to match and we got this far we must have // matched it. Clear par to indicate success and bail out. if (par) { par = NULL; break; } } if (n < 0) { fprintf(stderr, "Error reading status from apcupsd @ %s:%d: %s\n", host, port, strerror(-n)); net_close(sockfd); return 1; } net_close(sockfd); return par ? 2 : 0; } /*********************************************************************/ #if defined(HAVE_MINGW) #undef main #endif void usage() { fprintf(stderr, "Usage: apcaccess [-f ] [-h [:]] " "[-p ] [-u] [] [[:]]\n" "\n" " -f Load default host,port from given conf file (default: %s)\n" " -h Connect to host and port (supercedes conf file)\n" " -p Return only the value of the named parameter rather than all parameters and values\n" " -u Strip unit labels\n" "\n" "Supported commands: 'status' (default)\n" "Trailing host/port spec overrides -h and conf file.\n" , APCCONF); } int main(int argc, char **argv) { const char *par = NULL; char *cfgfile = NULL; char DEFAULT_HOST[] = "localhost"; char *host = NULL; const char *cmd = "status"; int port = NISPORT; int flags = 0; FILE *cfg; UPSINFO ups; // Process standard options int ch; while ((ch = getopt(argc, argv, "f:h:p:u")) != -1) { switch (ch) { case 'f': cfgfile = optarg; break; case 'h': host = optarg; break; case 'p': par = optarg; break; case 'u': flags |= NO_UNITS; break; case '?': default: usage(); return 1; } } // Default cfgfile if not provided on command line // Remember if we defaulted so we know later if conf failure is fatal bool fatal = cfgfile != NULL; if (!cfgfile) cfgfile = APCCONF; // Parse conf file for defaults if ((cfg = fopen(cfgfile, "r"))) { fclose(cfg); memset(&ups, 0, sizeof(UPSINFO)); init_ups_struct(&ups); check_for_config(&ups, cfgfile); port = ups.statusport; if (!host) // Don't override command line -h host = ups.nisip; } else if (fatal) { // Failure to find explicitly specified conf file is fatal fprintf(stderr, "Unable to open config file '%s'\n", cfgfile); return 2; } // Remaining non-option arguments are optional command and host:port // These are from legacy apcaccess syntax. They take priority over // the default from the conf file and/or switch values. int optleft = argc - optind; if (optleft >= 1) cmd = argv[optind]; if (optleft >= 2) host = argv[optind + 1]; // If still no host, use default if (!host || !*host) host = DEFAULT_HOST; // Separate host and port char *p = strchr(host, ':'); if (p) { *p++ = 0; port = atoi(p); } // Translate host of 0.0.0.0 to localhost // This is due to NISIP in apcupsd.conf being 0.0.0.0 for listening on all // interfaces. In that case just use loopback. if (!strcmp(host, "0.0.0.0")) host = DEFAULT_HOST; if (!strcmp(cmd, "status")) { return do_pthreads_status(host, port, par, flags); } else { fprintf(stderr, "Unknown command %s\n", cmd); usage(); return 1; } } apcupsd-3.14.14/src/apcagent/000077500000000000000000000000001274230402600156745ustar00rootroot00000000000000apcupsd-3.14.14/src/apcagent/ActiveNumberFormatter.m000066400000000000000000000036211274230402600223240ustar00rootroot00000000000000/* * ActiveNumberFormatter.m * * Subclass of NSNumberFormatter to provide on-the-fly range checking */ /* * Copyright (C) 2014 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #import // // NSNumberFormatter allows user to enter invalid characters into the cell and // only validates the content when they attempt to tab off or select another // control. ActiveNumberFormatter provides on-the-fly validation so the content // is always known to be correct. // @interface ActiveNumberFormatter: NSNumberFormatter - (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error; @end @implementation ActiveNumberFormatter - (BOOL)isPartialStringValid:(NSString *)partialString newEditingString:(NSString **)newString errorDescription:(NSString **)error { NSCharacterSet *nonDigits = [[NSCharacterSet decimalDigitCharacterSet] invertedSet]; return [partialString length] == 0 || ([partialString rangeOfCharacterFromSet:nonDigits].location == NSNotFound && ([self minimum] == nil || [partialString intValue] >= [[self minimum] intValue]) && ([self maximum] == nil || [partialString intValue] <= [[self maximum] intValue])); } @end apcupsd-3.14.14/src/apcagent/AppController.h000066400000000000000000000112161274230402600206320ustar00rootroot00000000000000/* * AppController.h * * Apcupsd monitoring applet for Mac OS X */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #import #import "alist.h" #import "astring.h" #import "InstanceManager.h" #import "InstanceConfig.h" class StatMgr; // Prior to 10.6, NSTableViewDataSource was an informal protocol #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 @protocol NSTableViewDataSource @end #endif // NSUserNotificationCenterDelegate was added in 10.8 #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1080 @protocol NSUserNotificationCenterDelegate @end #endif // NSMenuDelegate was added in 10.6 #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1060 @protocol NSMenuDelegate @end #endif @interface StatusTableDataSource: NSObject { NSLock *_mutex; NSMutableArray *_keys; NSMutableArray *_values; } - (id) init; - (void)populate:(alist &)keys values:(alist &)values; - (int)numberOfRowsInTableView:(NSTableView *)aTableView; - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; @end @interface EventsTableDataSource: NSObject { NSLock *mutex; NSMutableArray *strings; } - (id) init; - (void)populate:(alist &)stats; - (int)numberOfRowsInTableView:(NSTableView *)aTableView; - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex; @end @interface AppController: NSObject { // Status item shown in the status bar NSStatusItem *statusItem; // The menu attached to the status item IBOutlet NSMenu *statusMenu; IBOutlet NSMenuItem *upsName; IBOutlet NSMenuItem *upsHost; IBOutlet NSMenuItem *startAtLogin; // The config window and its controls IBOutlet NSWindow *configWindow; IBOutlet NSTextField *configHost; IBOutlet NSTextField *configPort; IBOutlet NSTextField *configRefresh; IBOutlet NSTextField *growlLabel; IBOutlet NSButton *configPopups; // The status window and its controls IBOutlet NSWindow *statusWindow; IBOutlet NSTextField *statusText; IBOutlet NSTextField *statusRuntime; IBOutlet NSLevelIndicator *statusBatteryBar; IBOutlet NSTextField *statusBatteryText; IBOutlet NSTableView *statusGrid; IBOutlet NSLevelIndicator *statusLoadBar; IBOutlet NSTextField *statusLoadText; // The events window and its controls IBOutlet NSWindow *eventsWindow; IBOutlet NSTableView *eventsGrid; // Icon images NSImage *commlostImage; NSImage *chargingImage; NSImage *onbattImage; NSImage *onlineImage; // User-configurable settings and a lock to protect them NSLock *configMutex; InstanceConfig *config; InstanceManager *manager; // Copy of settings used to detect changes NSString *prevHost; int prevPort; int prevRefresh; // Full set of status strings from the UPS, used to provide // data for status window grid control StatusTableDataSource *statusDataSource; // Full set of events strings from the UPS, used to provide // data for events window grid control plus a flag indicating if // the polling loop should update it. EventsTableDataSource *eventsDataSource; bool updateEvents; // Previous status, used to detect changes NSString *lastStatus; // Timer for UPS polling NSTimer *timer; // C++ object which handles polling the UPS StatMgr *statmgr; // If system support Notification Center (10.8 and above) BOOL haveNotifCtr; // Runloop variables BOOL running; CFRunLoopRef runLoop; NSConditionLock *condLock; } -(IBAction)config:(id)sender; -(IBAction)configComplete:(id)sender; -(IBAction)status:(id)sender; -(IBAction)events:(id)sender; -(IBAction)about:(id)sender; -(NSString *)id; -(void)close; - (void)timerHandler:(NSTimer*)theTimer; - (void)activateWithConfig:(InstanceConfig*)cfg manager:(InstanceManager*)mgr; - (void)menuNeedsUpdate:(NSMenu *)menu; @end apcupsd-3.14.14/src/apcagent/AppController.m000066400000000000000000000372141274230402600206450ustar00rootroot00000000000000/* * AppController.m * * Apcupsd monitoring applet for Mac OS X */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #import "AppController.h" #import "statmgr.h" //****************************************************************************** // CLASS AppController //****************************************************************************** @implementation AppController - (void)awakeFromNib { // Load images NSBundle *bundle = [NSBundle mainBundle]; chargingImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource:@"charging" ofType:@"png"]]; commlostImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource:@"commlost" ofType:@"png"]]; onbattImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource:@"onbatt" ofType:@"png"]]; onlineImage = [[NSImage alloc] initWithContentsOfFile: [bundle pathForResource:@"online" ofType:@"png"]]; // Create our status item statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength: NSVariableStatusItemLength] retain]; [statusItem setHighlightMode:YES]; [statusItem setImage:commlostImage]; [statusItem setMenu:statusMenu]; // Setup status table control statusDataSource = [[StatusTableDataSource alloc] init]; [statusGrid setDataSource:statusDataSource]; // Setup events table control eventsDataSource = [[EventsTableDataSource alloc] init]; [eventsGrid setDataSource:eventsDataSource]; // Configure to post notifications #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 haveNotifCtr = NSClassFromString(@"NSUserNotificationCenter") != nil; if (haveNotifCtr) { // Allow user to enable/disable notifications [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:self]; [configPopups setEnabled:YES]; [configPopups setHidden:NO]; } #else haveNotifCtr = NO; #endif } - (void)activateWithConfig:(InstanceConfig*)cfg manager:(InstanceManager*)mgr { manager = [mgr retain]; // Save copies of preferences so worker can tell what changed configMutex = [[NSLock alloc] init]; config = [cfg retain]; prevHost = [[config host] retain]; prevPort = [config port]; prevRefresh = [config refresh]; statmgr = NULL; lastStatus = [@"" retain]; // Create timer object used by the thread timer = [[NSTimer timerWithTimeInterval:[config refresh] target:self selector:@selector(timerHandler:) userInfo:nil repeats:YES] retain]; // Start worker thread to handle polling UPS for status running = YES; condLock = [[NSConditionLock alloc] initWithCondition:1]; [NSThread detachNewThreadSelector:@selector(thread:) toTarget:self withObject:nil]; } - (void) thread:(id)arg { NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init]; // Hold this lock while we're running to prevent release of the object [condLock lockWhenCondition:1]; // Publicise our CFRunLoop reference so main thread can stop us runLoop = [[NSRunLoop currentRunLoop] getCFRunLoop]; // Add periodic timer to the runloop [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; // Fire timer once immediately to get the first data sample ASAP [timer fire]; // Invoke the runloop until we're asked to exit while (running) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; } // All done...clean up [timer invalidate]; [timer release]; delete statmgr; [p release]; // Signal that we've completed [condLock unlockWithCondition:0]; } - (void)timerHandler:(NSTimer*)theTimer { // Reinitialize the StatMgr if host or port setting changes [configMutex lock]; if (!statmgr || ![prevHost isEqualToString:[config host]] || prevPort != [config port]) { [statusItem setImage:commlostImage]; delete statmgr; statmgr = new StatMgr([[config host] UTF8String], [config port]); [prevHost release]; prevHost = [[config host] retain]; prevPort = [config port]; } BOOL doPopup = [config popups]; [configMutex unlock]; // Grab updated status info from apcupsd int battstat; astring statstr, upsname; statmgr->GetSummary(battstat, statstr, upsname); // Update icon based on UPS state if (battstat == -1) [statusItem setImage:commlostImage]; else if (battstat == 0) [statusItem setImage:onbattImage]; else if (battstat >= 100) [statusItem setImage:onlineImage]; else [statusItem setImage:chargingImage]; // Update tooltip with status and UPS name NSString *tooltip; if (upsname == "UPS_IDEN" || upsname.empty()) tooltip = [NSString stringWithUTF8String:statstr]; else tooltip = [NSString stringWithFormat: @"%s: %s", upsname.str(), statstr.str()]; [statusItem setToolTip:tooltip]; // Update menu with UPS name and host if (upsname.empty()) upsname = ""; [upsName setTitle:[NSString stringWithFormat:@"UPS: %s",upsname.str()]]; [upsHost setTitle:[NSString stringWithFormat:@"HOST: %@:%d",[config host],[config port]]]; // Update status window, but only if it's visible (optimization) if ([statusWindow isVisible]) { // Set window title to include UPS name [statusWindow setTitle: [NSString stringWithFormat:@"Status for UPS: %s",upsname.str()]]; // Update raw status table alist keys, values; statmgr->GetAll(keys, values); [statusDataSource populate:keys values:values]; [statusGrid reloadData]; // Update status text [statusText setStringValue:[NSString stringWithUTF8String:statstr]]; // Update runtime NSString *tmp = [NSString stringWithUTF8String:statmgr->Get("TIMELEFT")]; tmp = [[tmp componentsSeparatedByString:@" "] objectAtIndex:0]; [statusRuntime setStringValue:tmp]; // Update battery tmp = [NSString stringWithUTF8String:statmgr->Get("BCHARGE")]; tmp = [[tmp componentsSeparatedByString:@" "] objectAtIndex:0]; [statusBatteryText setStringValue:[tmp stringByAppendingString:@"%"]]; [statusBatteryBar setIntValue:[tmp intValue]]; // Update load tmp = [NSString stringWithUTF8String:statmgr->Get("LOADPCT")]; tmp = [[tmp componentsSeparatedByString:@" "] objectAtIndex:0]; [statusLoadText setStringValue:[tmp stringByAppendingString:@"%"]]; [statusLoadBar setIntValue:[tmp intValue]]; } // Update events window, but only if it's visible (optimization) if ([eventsWindow isVisible]) { // Set window title to include UPS name [eventsWindow setTitle: [NSString stringWithFormat:@"Events for UPS: %s",upsname.str()]]; // Fetch current events from the UPS alist eventStrings; statmgr->GetEvents(eventStrings); [eventsDataSource populate:eventStrings]; [eventsGrid reloadData]; } // If status has changed, display a popup window NSString *newStatus = [NSString stringWithUTF8String:statstr]; if (haveNotifCtr && doPopup && [lastStatus length] && ![lastStatus isEqualToString:newStatus]) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 // Post notification here... NSUserNotification *notification = [[NSUserNotification alloc] init]; notification.title = @"Apcupsd Event"; notification.subtitle = [NSString stringWithFormat:@"%s %@",upsname.str(),newStatus]; NSDate *now = [NSDate dateWithTimeIntervalSinceNow:0]; notification.informativeText = [NSString stringWithFormat:@"UPS '%s' status %@ at %@", upsname.str(),newStatus,now]; notification.contentImage = [statusItem image]; [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; [notification release]; #endif } // Save status for comparison next time [lastStatus release]; lastStatus = [newStatus retain]; // If refresh interval changed, invalidate old timer and start a new one [configMutex lock]; if (prevRefresh != [config refresh]) { prevRefresh = [config refresh]; [theTimer invalidate]; [theTimer release]; timer = [[NSTimer timerWithTimeInterval:[config refresh] target:self selector:@selector(timerHandler:) userInfo:nil repeats:YES] retain]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode]; } [configMutex unlock]; } - (void) dealloc { NSLog(@"%s:%d", __FUNCTION__, __LINE__); [chargingImage release]; [commlostImage release]; [onlineImage release]; [onbattImage release]; [prevHost release]; [lastStatus release]; [statusDataSource release]; [eventsDataSource release]; [configMutex release]; [condLock release]; [manager release]; [statusItem release]; [super dealloc]; } -(IBAction)config:(id)sender; { // Copy current settings into config window [configHost setStringValue:[config host]]; [configPort setIntValue:[config port]]; [configRefresh setIntValue:[config refresh]]; [configPopups setIntValue:[config popups]]; // Force app to foreground and move key focus to config window [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; [configWindow makeKeyAndOrderFront:self]; } -(IBAction)configComplete:(id)sender; { // Validate fields are not empty NSString *tmpstr = [configHost stringValue]; tmpstr = [tmpstr stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceCharacterSet]]; if ([tmpstr length] == 0) { [configWindow makeFirstResponder:configHost]; } else if ([[configPort stringValue] length] == 0) { [configWindow makeFirstResponder:configPort]; } else if ([[configRefresh stringValue] length] == 0) { [configWindow makeFirstResponder:configRefresh]; } else { // Grab new settings from window controls [configMutex lock]; [config setHost:[configHost stringValue]]; [config setPort:[configPort intValue]]; [config setRefresh:[configRefresh intValue]]; [config setPopups:[configPopups intValue]]; [config save]; [configMutex unlock]; // Hide window [configWindow orderOut:self]; // Kick runloop timer so new config will be acted on immediately [timer fire]; } } -(IBAction)status:(id)sender { // Force app to foreground and move key focus to status window [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; [statusWindow makeKeyAndOrderFront:self]; // Kick timer so window is updated immediately [timer fire]; } -(IBAction)events:(id)sender { // Force app to foreground and move key focus to events window [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; [eventsWindow makeKeyAndOrderFront:self]; // Kick timer so window is updated immediately [timer fire]; } -(IBAction)about:(id)sender; { // Normally we'd just wire the about button directly to NSApp // orderFrontStandardAboutPanel. However, since we're a status item without // a main window we need to bring ourself to the foreground or else the // about box will be buried behind whatever window the user has active at // the time. So we'll force ourself active, then call out to NSApp. [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; [[NSApplication sharedApplication] orderFrontStandardAboutPanel:self]; } -(NSString *)id { return [config id]; } -(void)close { NSLog(@"%s:%d", __FUNCTION__, __LINE__); // Stop the runloop and wait for it to complete // Using a lock to wait for thread termination is silly, but Apple's // lousy threading API gives us no 'join'. running = NO; CFRunLoopStop(runLoop); [condLock lockWhenCondition:0]; [condLock unlockWithCondition:0]; // Remove the icon from the status bar [[NSStatusBar systemStatusBar] removeStatusItem:statusItem]; } - (void)menuNeedsUpdate:(NSMenu *)menu { [startAtLogin setState:([manager isStartAtLogin] ? NSOnState : NSOffState)]; } #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 - (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification { return YES; } #endif @end //****************************************************************************** // CLASS StatusTableDataSource //****************************************************************************** @implementation StatusTableDataSource - (id) init { if ((self = [super init])) { _mutex = [[NSLock alloc] init]; _keys = [[NSMutableArray alloc] init]; _values = [[NSMutableArray alloc] init]; } return self; } - (void) dealloc { [_keys release]; [_values release]; [_mutex release]; [super dealloc]; } - (void)populate:(alist &)keys values:(alist &)values { [_mutex lock]; [_keys removeAllObjects]; [_values removeAllObjects]; alist::const_iterator iter; for (iter = keys.begin(); iter != keys.end(); ++iter) [_keys addObject:[NSString stringWithUTF8String:*iter]]; for (iter = values.begin(); iter != values.end(); ++iter) [_values addObject:[NSString stringWithUTF8String:*iter]]; [_mutex unlock]; } - (int)numberOfRowsInTableView:(NSTableView *)aTableView { [_mutex lock]; int count = [_keys count]; [_mutex unlock]; return count; } - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { NSString *ret; // Lookup and retain value under lock [_mutex lock]; if ([[aTableColumn identifier] intValue] == 0) ret = [[[_keys objectAtIndex:rowIndex] retain] autorelease]; else ret = [[[_values objectAtIndex:rowIndex] retain] autorelease]; [_mutex unlock]; return ret; } @end //****************************************************************************** // CLASS EventsTableDataSource //****************************************************************************** @implementation EventsTableDataSource - (id) init { if ((self = [super init])) { mutex = [[NSLock alloc] init]; strings = [[NSMutableArray alloc] init]; } return self; } - (void) dealloc { [strings release]; [mutex release]; [super dealloc]; } - (void)populate:(alist &)stats { [mutex lock]; [strings removeAllObjects]; alist::const_iterator iter; for (iter = stats.begin(); iter != stats.end(); ++iter) { NSString *data = [NSString stringWithUTF8String:*iter]; [strings addObject:data]; } [mutex unlock]; } - (int)numberOfRowsInTableView:(NSTableView *)aTableView { [mutex lock]; int count = [strings count]; [mutex unlock]; return count; } - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex { NSString *ret; // Lookup and retain value under lock [mutex lock]; ret = [[[strings objectAtIndex:rowIndex] retain] autorelease]; [mutex unlock]; return ret; } @end apcupsd-3.14.14/src/apcagent/Info.plist000066400000000000000000000020661274230402600176500ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable apcagent CFBundleIdentifier com.apcupsd.apcagent CFBundleInfoDictionaryVersion 6.0 CFBundleName apcagent CFBundlePackageType APPL CFBundleSignature ???? CFBundleVersion __VERSION__ LSUIElement NSMainNibFile MainMenu NSPrincipalClass NSApplication NSHumanReadableCopyright Copyright © 2009-2014 Adam Kropelin (GPLv2) CFBundleGetInfoString __VERSION__, © 2009-2014 Adam Kropelin (GPLv2) CFBundleShortVersionString __VERSION__ apcupsd-3.14.14/src/apcagent/InstanceConfig.h000066400000000000000000000027301274230402600207410ustar00rootroot00000000000000/* * InstanceConfig.h * * Apcupsd monitoring applet for Mac OS X */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #import #define INSTANCES_PREF_KEY @"Instances" #define ID_PREF_KEY @"id" #define HOSTNAME_PREF_KEY @"host" #define PORT_PREF_KEY @"port" #define REFRESH_PREF_KEY @"refresh" #define POPUPS_PREF_KEY @"popups" @interface InstanceConfig: NSObject { NSMutableDictionary *config; } + (InstanceConfig*)configWithDictionary:(NSDictionary*)dict; + (InstanceConfig*) configWithDefaults; + (void) removeConfigWithId:(NSString*)id; - (void)dealloc; - (NSString *)host; - (int)port; - (int)refresh; - (BOOL)popups; - (NSString *)id; - (void)setHost:(NSString *)host; - (void)setPort:(int)port; - (void)setRefresh:(int)refresh; - (void)setPopups:(BOOL)popupsEnabled; - (void)save; @end apcupsd-3.14.14/src/apcagent/InstanceConfig.m000066400000000000000000000110131274230402600207400ustar00rootroot00000000000000/* * InstanceConfig.m * * Apcupsd monitoring applet for Mac OS X */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #import "InstanceConfig.h" #import "NSString+uuid.h" #define DEFAULT_HOSTNAME @"127.0.0.1" #define DEFAULT_PORT 3551 #define DEFAULT_REFRESH 5 #define DEFAULT_POPUPS YES @implementation InstanceConfig + (InstanceConfig*) configWithDictionary:(NSDictionary*)dict { InstanceConfig *cfg = [[[InstanceConfig alloc] init] autorelease]; cfg->config = [[NSMutableDictionary dictionaryWithDictionary:dict] retain]; return cfg; } + (InstanceConfig*) configWithDefaults { InstanceConfig *cfg = [[[InstanceConfig alloc] init] autorelease]; cfg->config = [[NSMutableDictionary dictionary] retain]; // Establish defaults [cfg->config setObject:[NSString stringWithUUID] forKey:ID_PREF_KEY]; [cfg->config setObject:DEFAULT_HOSTNAME forKey:HOSTNAME_PREF_KEY]; [cfg->config setObject:[NSNumber numberWithInt:DEFAULT_PORT] forKey:PORT_PREF_KEY]; [cfg->config setObject:[NSNumber numberWithInt:DEFAULT_REFRESH] forKey:REFRESH_PREF_KEY]; [cfg->config setObject:[NSNumber numberWithBool:DEFAULT_POPUPS] forKey:POPUPS_PREF_KEY]; return cfg; } + (void) removeConfigWithId:(NSString*)id { // Fetch instances array from preferences and make a mutable copy NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; NSArray *tmp = [prefs arrayForKey:INSTANCES_PREF_KEY]; if (!tmp) tmp = [NSArray array]; NSMutableArray *instances = [NSMutableArray arrayWithArray:tmp]; // Remove existing config from array for (unsigned int i = 0; i < [instances count]; i++) { InstanceConfig *tmpconfig = [InstanceConfig configWithDictionary:[instances objectAtIndex:i]]; // If id was found, remove that config if ([id isEqualToString:[tmpconfig id]]) [instances removeObjectAtIndex:i]; } // Write array back to prefs [prefs setObject:instances forKey:INSTANCES_PREF_KEY]; [prefs synchronize]; } - (void)dealloc { [config release]; [super dealloc]; } - (NSString *)host { return [[[config objectForKey:HOSTNAME_PREF_KEY] retain] autorelease]; } - (int)port { return [(NSNumber*)[config objectForKey:PORT_PREF_KEY] intValue]; } - (int)refresh { return [(NSNumber*)[config objectForKey:REFRESH_PREF_KEY] intValue]; } - (BOOL)popups { return [(NSNumber*)[config objectForKey:POPUPS_PREF_KEY] boolValue]; } - (NSString *)id { return [[[config objectForKey:ID_PREF_KEY] retain] autorelease]; } - (void)setHost:(NSString *)host { [config setObject:host forKey:HOSTNAME_PREF_KEY]; } - (void)setPort:(int)port; { [config setObject:[NSNumber numberWithInt:port] forKey:PORT_PREF_KEY]; } - (void)setRefresh:(int)refresh; { [config setObject:[NSNumber numberWithInt:refresh] forKey:REFRESH_PREF_KEY]; } - (void)setPopups:(BOOL)popupsEnabled; { [config setObject:[NSNumber numberWithBool:popupsEnabled] forKey:POPUPS_PREF_KEY]; } - (void) save { // Fetch instances array from preferences and make a mutable copy NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; NSArray *tmp = [prefs arrayForKey:INSTANCES_PREF_KEY]; if (!tmp) tmp = [NSArray array]; NSMutableArray *instances = [NSMutableArray arrayWithArray:tmp]; // Search for matching config unsigned int i; for (i = 0; i < [instances count]; i++) { InstanceConfig *tmpconfig = [InstanceConfig configWithDictionary:[instances objectAtIndex:i]]; // If id was found replace with new config if ([[self id] isEqualToString:[tmpconfig id]]) { [instances replaceObjectAtIndex:i withObject:config]; break; } } // If config did not yet exist in array, add it at the end if (i == [instances count]) [instances addObject:config]; // Write array back to prefs [prefs setObject:instances forKey:INSTANCES_PREF_KEY]; [prefs synchronize]; } @end apcupsd-3.14.14/src/apcagent/InstanceManager.h000066400000000000000000000021431274230402600211040ustar00rootroot00000000000000/* * InstanceManager.h * * Apcupsd monitoring applet for Mac OS X */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #import "InstanceConfig.h" @interface InstanceManager: NSObject { NSMutableDictionary *instmap; NSNib *nib; } - (InstanceManager *)init; - (void)dealloc; -(IBAction)remove:(id)sender; -(IBAction)add:(id)sender; -(IBAction)removeAll:(id)sender; -(IBAction)startAtLogin:(id)sender; - (void) createMonitors; -(BOOL)isStartAtLogin; @end apcupsd-3.14.14/src/apcagent/InstanceManager.m000066400000000000000000000167231274230402600211220ustar00rootroot00000000000000/* * InstanceManager.m * * Apcupsd monitoring applet for Mac OS X */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #import "InstanceConfig.h" #import "AppController.h" #include @implementation InstanceManager //****************************************************************************** // PRIVATE helper methods //****************************************************************************** -(NSURL*)appURL { // Get application URL (10.4 lacks NSBundle::bundleURL so get the path // and then convert to a file URL) return [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; } // Fetches a reference to the apcagent login item or returns NULL if no login // item for apcagent is found -(LSSharedFileListItemRef)getLoginItem { LSSharedFileListItemRef ret = NULL; // Fetch current user login items LSSharedFileListRef fileList = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); if (!fileList) return NULL; UInt32 seed; NSArray *loginItems = (NSArray *)LSSharedFileListCopySnapshot(fileList, &seed); // Search list for our URL if (loginItems) { NSURL *appUrl = [self appURL]; for (unsigned i = 0; !ret && i < [loginItems count]; i++) { LSSharedFileListItemRef item = (LSSharedFileListItemRef)[loginItems objectAtIndex:i]; NSURL *url = nil; // LSSharedFileListItemResolve is deprecated in Mac OS X 10.10 // Switch to LSSharedFileListItemCopyResolvedURL if possible #if MAC_OS_X_VERSION_MIN_REQUIRED < 10100 LSSharedFileListItemResolve(item, 0, (CFURLRef*)&url, NULL); #else url = (NSURL*)LSSharedFileListItemCopyResolvedURL(item, 0, NULL); #endif if (url) { if ([url isEqual:appUrl]) ret = (LSSharedFileListItemRef)CFRetain(item); [url release]; } } [loginItems release]; } CFRelease(fileList); return ret; } // Checks to see if apcagent login item is installed -(BOOL)isStartAtLogin { LSSharedFileListItemRef item = [self getLoginItem]; BOOL ret = item != NULL; if (item) CFRelease(item); return ret; } // Add login item for apcagent (if not already present) - (void)addLoginItem { if (![self isStartAtLogin]) { LSSharedFileListRef fileList = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); if (fileList) { LSSharedFileListItemRef item = LSSharedFileListInsertItemURL( fileList, kLSSharedFileListItemLast, NULL, NULL, (CFURLRef)[self appURL], NULL, NULL); if (item) CFRelease(item); CFRelease(fileList); } } } // Remove login item for apcagent (if present) - (void)removeLoginItem { LSSharedFileListRef fileList = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); if (fileList) { LSSharedFileListItemRef item = [self getLoginItem]; if (item) { LSSharedFileListItemRemove(fileList, item); CFRelease(item); } CFRelease(fileList); } } // Toggle start at login in response to menu click -(IBAction)startAtLogin:(id)sender { if ([self isStartAtLogin]) { [self removeLoginItem]; [sender setState:NSOffState]; } else { [self addLoginItem]; [sender setState:NSOnState]; } } - (void) instantiateMonitor:(InstanceConfig*)config { // Instantiate the NIB for this monitor NSArray *objs; // instantiateNibWithOwner is deprecated in 10.8 where instantiateWithOwner // is preferred due to better memory management characteristics #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 [nib instantiateNibWithOwner:self topLevelObjects:&objs]; #else [nib instantiateWithOwner:self topLevelObjects:&objs]; #endif [instmap setObject:objs forKey:[config id]]; // Locate the AppController object and activate it for (unsigned int j = 0; j < [objs count]; j++) { if ([[objs objectAtIndex:j] isMemberOfClass:[AppController class]]) { AppController *ctrl = [objs objectAtIndex:j]; [ctrl activateWithConfig:config manager:self]; break; } } } //****************************************************************************** // PUBLIC methods //****************************************************************************** - (InstanceManager *)init { self = [super init]; if (!self) return nil; instmap = [[NSMutableDictionary alloc] init]; nib = [[NSNib alloc] initWithNibNamed:@"MainMenu" bundle:nil]; return self; } - (void)dealloc { [nib release]; [instmap release]; [super dealloc]; } - (void) createMonitors { NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; InstanceConfig *config; // Fetch instances array from preferences NSArray *instances = [prefs arrayForKey:INSTANCES_PREF_KEY]; // If instance array does not exist or is empty, add a default entry if (!instances || [instances count] == 0) { config = [InstanceConfig configWithDefaults]; [config save]; instances = [prefs arrayForKey:INSTANCES_PREF_KEY]; // Add login item if not already there [self addLoginItem]; } // Instantiate monitors for (unsigned int i = 0; i < [instances count]; i++) { config = [InstanceConfig configWithDictionary:[instances objectAtIndex:i]]; [self instantiateMonitor:config]; } } -(IBAction)add:(id)sender { // Create a new default monitor and save it to prefs InstanceConfig *config = [InstanceConfig configWithDefaults]; [config save]; // Instantiate the new monitor [self instantiateMonitor:config]; } -(IBAction)remove:(id)sender { NSLog(@"%s:%d %@", __FUNCTION__, __LINE__, [[sender menu] delegate]); // Find AppController instance which this menu refers to AppController *ac = (AppController *)[[sender menu] delegate]; // Remove the config from prefs for this monitor [InstanceConfig removeConfigWithId:[ac id]]; // Instruct the instance to close [ac close]; // Remove our reference to the instance and all of its NIB objects [instmap removeObjectForKey:[ac id]]; #if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 // When using instantiateNibWithOwner above in instantiateMonitor() we need // to manually remove a ref on ac because the NIB top-level object array is // retained "automatically". [ac release]; #endif // If all instances have been removed, terminate the app if ([instmap count] == 0) [self removeAll:sender]; } -(IBAction)removeAll:(id)sender { // Remove all instances from preferences NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults]; [prefs removeObjectForKey:INSTANCES_PREF_KEY]; // Remove user login item [self removeLoginItem]; // Terminate the app [[NSApplication sharedApplication] terminate:self]; } @end apcupsd-3.14.14/src/apcagent/MainMenu.nib000066400000000000000000000543121274230402600201040ustar00rootroot00000000000000bplist00 * +X$versionX$objectsY$archiverT$top#$*.2W_efx %9BCL^_ghkuvw|123456789:;1>?@DEIMRSWYbfghklqz{ +/;DENOTUX]^_fgpqxyz$%*+.347;<ARSTUZ^tz~$128;BHIMWX^efkst{| ()019:ABJKRS[\cdlmtu~DGHKLPUW,                           ! $ 'U$null VNSRoot]NSConnections\NSOidsValues_NSObjectsValues]NSObjectsKeys_NSAccessibilityOidsValues_NSVisibleWindows_NSAccessibilityOidsKeys_NSAccessibilityConnectorsV$classZNSOidsKeys~v !"[NSClassName_InstanceManager%&'(Z$classnameX$classes^NSCustomObject')XNSObject+,-ZNS.objects%&/0\NSMutableSet/1)UNSSet+3V"456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU3HT{؀ "',WY[]_`adfhjlnprt-XYZ[\]^XNSSource]NSDestinationWNSLabel /12`abcdWNSTitle[NSMenuItems .P+gVhijklmnopqrstuv !"$&()+-yz{|}`~[b]NSMnemonicLocVNSMenuYNSOnImageZNSKeyEquiv\NSIsDisabled\NSMixedImage  Wupsname[NSClassName^NSResourceNameWNSImage_NSMenuCheckmark%&_NSCustomResource)_NSMenuMixedState%&ZNSMenuItem)zy{|`~[b  Wupshostyz{|}`~[bb]NSIsSeparator  zy{|`~[b  [Show Statuszy{|`~[b  [Show Eventsyz{|}`~[bb  zy{|`~[b  ^Preferences...zy{|`~[b  ^Start at loginyz{|}`~[bb  zy{|`~[b  #[Add Monitorzy{|`~[b  %^Remove Monitorzy{|`~[b  '_Remove All Monitorsyz{|}`~[bb  zy{|`~[b  *^About apcagentzy{|`~[b   ,TQuit%&^NSMutableArray)WNSArray%&VNSMenu) "0]AppControllerXdelegate%&_NSNibOutletConnector)^NSNibConnectorXYZ\"#^/4G2&'()*+,-./01233567VNSCellWNSFrame_NSAllowsLogicalLayoutDirection_NSNextResponder[NSSuperview]NSNextKeyViewXNSvFlags_%NSTextFieldAlignmentRectInsetsVersionYNSEnabled86F557  ':)*+,;<=>>@AZNSSubviews_{{169, 113}, {168, 22}}&'()*+,-.DE1233J67F55U MNOPQRSTU"WXZ[\][NSCellFlags]NSControlViewYNSSupport_NSDrawsBackground_NSBackgroundColorZNSContents[NSTextColor\NSCellFlags2pA4E: =9B@Xhostname`abcdefVNSSizeXNSfFlagsVNSName#@*;<_#.HelveticaNeueDeskInterface-Regular%&ijVNSFonti)lmnopqrst[NSColorName\NSColorSpace]NSCatalogNameWNSColorA?>@VSystem_textBackgroundColorxmyzpWNSWhiteB1A%&}~WNSColor})lmnoprsAC>DYtextColorxmzpB0A%&_NSTextFieldCell)\NSActionCellVNSCell%&[NSTextField)YNSControlVNSView[NSResponderZconfigHostXYZ\^/IS2&'()*,.133KJR55 _{{121, 17}, {155, 18}}MTNRObbX_NSPeriodicInterval]NSButtonFlags_NSAlternateContents_NSKeyEquivalent_NSAlternateImage]NSNormalImage_NSPeriodicDelay^NSButtonFlags2H[NSFrameSize+V>-&'()*,.16R _{{281, 13}, {96, 32}}MTNRO  b XX@ :Q:ROKQ +'*,):13"3$&7()*YNSBoxType]NSTransparent]NSContentView_NSTitlePosition\NSBorderType[NSTitleCellYNSOffsets55 +,V35-+0VJn"@5xU|47~WI-&'()*+,-.<=1233"67F554 _{{-3, 115}, {167, 17}}MNOQSRTF@WXJKLM@E:@_Hostname or IP Address:lmnopQrsSA>\controlColorxmVzpM0.6666666667AlmnopZrsA>D_controlTextColor_{{37, 84}, {127, 17}}MNOQSRTF5WXJKeM7E:UPort:&'()*+,-.hi1233n67F55| _{{16, 51}, {149, 17}}MNOQSRTFWXJKwME:XRefresh:_{{270, 51}, {61, 17}}MNOQSRTFxWXJK]~E:Wseconds_{{270, 83}, {70, 17}}MNOQSRTFWXJK]WE:Y(1-65535)_{{1, 1}, {355, 159}}%&)_{{17, 50}, {357, 161}}V{0, 0}MOQSRT WZE=SBox`abef#@& ;<lmnoprsA>DZlabelColor%&UNSBox)Z{391, 229}_{{0, 0}, {1280, 937}}_ {10000000000000, 10000000000000}%&_NSWindowTemplate)\configWindowXYZ\^/׀2,()Q.*1t71_ NSControlAllowsExpansionToolTips_NSColumnAutoresizingStyle_NSDraggingSourceMaskForNonLocal_#NSTableViewDraggingDestinationStyleZNSDelegate_NSIntercellSpacingHeight[NSRowHeightYNSTvFlags_NSDraggingSourceMaskForLocal\NSCornerView\NSDataSource[NSGridColor_NSIntercellSpacingWidth^NSTableColumns_NSTableViewGroupRowStyle_NSAllowsTypeSelect @ր#@#@1ÀՀ #@':)*+,YNScvFlagsYNSDocViewYNSBGColor_#NSAutomaticallyAdjustsContentInsets߀߀ Z{413, 229})', Àŀ_{{399, 0}, {16, 17}}%&]_NSCornerView)]_NSCornerView+Vǀ-zZNSDataCell\NSHeaderCellZNSMaxWidth^NSResizingMask^NSIsResizeableWNSWidthZNSMinWidth[NSTableViewр̀#@@ #@y#@DMOQSRT  b @̀ɀʀ xmzpK0.33333299AlmnoprsAˀ>D_headerTextColor%&_NSTableHeaderCell)_NSTableHeaderCell\NSActionCellMNOQSRTWXK#  @E:πYText Celllmnop'rsSAЀ>_controlBackgroundColor%&,-]NSTableColumn,)lmnop0rs2AӀ>YgridColorxm5zpD0.5A%&89[NSTableView:)[NSTableViewZeventsGridXYZ\>?^/ـ2BCD FGHIKMN QYNSMinSize_NSWindowContentMinSizeڀۀ݀ 퀽d _{{196, 239}, {455, 271}}^Apcupsd EventsZ{455, 271}):, WX;Àހ쀱+[V߀-+_'`a*),bc:deghjklHHAopqrsXNSsFlags_NSMinMagnification[NSVScroller\NSScrollAmts_NSMaxMagnification[NSHScroller_NSMagnification 2#?݀OA A AA#@#?+uVlr-+{V-_{{1, 1}, {413, 229}}%&ZNSClipView)'()*,1_NSControlAction_NSControlTargetXNSTargetXNSActionYNSPercent߀߀߀#?m_{{399, 0}, {15, 215}}\_doScroller:%&ZNSScroller)_'(*,)1߀߀߀#?wnÀ_{{1, 215}, {398, 15}}_{{20, 20}, {415, 231}}%&\NSScrollView)Z{455, 271}_{{0, 0}, {1280, 937}}Z{455, 293}_ {10000000000000, 10000000000000}\eventsWindowXYZ\o^/2\startAtLoginXYZ\^/2&'()*,.16 ):, ;ŀ1R_{{83, 400}, {133, 18}}MNT77^NSWarningValueWNSValueZNSMaxValue_NSIndicatorStyle_NSCriticalValue_NSTickMarkPosition#@4#@Y#@Y#@$%&_NSLevelIndicatorCell)_NSLevelIndicatorCell\NSActionCell%&_NSLevelIndicator)_NSLevelIndicator_statusBatteryBarXYZ\^/2&'()*,-.1267F _{{80, 400}, {139, 17}}MNOQSRTFWXJKE:@T100%_statusBatteryTextXYZ\^/2,()Q.*A17  71_NSGridStyleMask πր#@#@1bՀ #@':)*+,5422 Z{414, 322})', Ł_{{-26, 0}, {16, 17}}+ V!"-%&()*z-./0_NSSortDescriptorPrototype\NSIdentifier  #@@  #@Y@#@D Q0MOQSRT5 b ̀ ʀ xm9zpK0.33333299AMNOQSRTWXK# E:πCDEG[NSAscendingZNSSelector Xcompare:%&JK_NSSortDescriptorL)_NSSortDescriptor&OPQzTUV#@@ #@s0#@DQ1MOQSRT5 b ̀ ʀ MNOQSRTWXK# E:πZstatusGridXYZ\hi^/2&'()*,.lm16 _{{303, 399}, {133, 18}}MNTuhxy7z7#@R#@I#@Y#@V]statusLoadBarXYZ\~^/2&'()*,-.1267F _{{300, 400}, {139, 17}}MNOQSRTF~WXJKE:S50%^statusLoadTextXYZ\[^/ !2ZstatusMenuXYZ\^/#&2&'()*,-.1267%$F _{{303, 370}, {74, 22}}MNOPQRSTWXZb\pA#E: = B]statusRuntimeXYZ\^/(+2&'()*,-.1267*)F _{{83, 369}, {133, 22}}MNOPQRSTWXZb\(E: = BZstatusTextXYZ\^/-V2BC  Q./UT S0d_{{378, 358}, {456, 438}}^Apcupsd StatusZ{456, 438}+Vh~2(#;?CGKO-+_'`a*),bc:degjA:#?6OA A AA#@38#?+V68-+V-_{{1, 1}, {414, 322}}'()*, 172222#?7 _{{400, 1}, {15, 307}}_'(*,)192222#?Bٶ_{{1, 308}, {399, 15}}_{{20, 20}, {416, 324}}&'()*,-.!"1267=<F _{{17, 372}, {61, 17}}MNOQSRTFWXJK/M;E:>WStatus:&'()*,-.231267A@F _{{237, 372}, {61, 17}}MNOQSRTFWXJK@M?E:BXRuntime:&'()*,-.CD1267EDF _{{17, 400}, {61, 17}}MNOQSRTFWXJKQMCE:FXBattery:&'()*,-.TU1267IHF _{{252, 400}, {46, 17}}MNOQSRTFWXJKbMGE:JULoad:&'()*,-.ef1267MLF _{{382, 372}, {60, 17}}MNOQSRTFWXJKs]KE:NWMinutes')*,$wx*1}zPQ _{{12, 354}, {432, 5}}MOQSRT WXZE:=Z{456, 438}_{{0, 0}, {1280, 937}}Z{456, 460}_ {10000000000000, 10000000000000}\statusWindowXYZ\i^/X2WupsHostXYZ\h^/ Z2WupsNameXYZ"^4\2_initialFirstResponderXYZ"J^4U^2[nextKeyViewXYZJn^U|^2XYZn"^|4^2XZv+bcZterminate:%&_NSNibControlConnector)^NSNibConnectorXYZ\/ec_configComplete:XYZk\/gcWstatus:XYZl\/icWevents:XYZu\)/kcVabout:XYZq"mcTadd:XYZr$ocWremove:XYZs&qcZremoveAll:XYZn\/scWconfig:XYZouc]startAtLogin:+CV[vkltmuqrjhisnpo\>nrx|J"/h@<5DhlT~!2Ce!("O>HlrBwy +()"$ &!/|W~UXZ487IK-OGI(*#%;=?ACEKM268 ـ݀߀ǀ́{} E"x]NSApplication I"z]NSFontManagerMO_NSSharedInstance |%&QR_NSUserDefaultsControllerST)_NSUserDefaultsController\NSController%&V)+XCV[[[[[[[[[[[[[[[>nr>>x>J>">>@>5>h~!">H |W~UX47I-G(#;?CK222ـ݀߀߀߀ǀ}+Cy[vkltmuqrjhisnpo\>nrx|J"/h@<5DhlT~!2Ce!("O>HlrB456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUwy +()"$ &!/|W~UXZ487IK-OGI(*#%;=?ACEKM268 ـ݀߀ǀ́{3HT{؀ "',WY[]_`adfhjlnprt}+-Cy./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÁāŁƁǁȁɁʁˁ́́΁ρЁсҁӁԁՁցׁ؁فځہ܁݁ށ߁}     + "V-+ %C}%& ( )^NSIBObjectData ()_NSKeyedArchiver , -7 ._IB.systemFontUpdateVersion]IB.objectdata"+5:?=Cpw)+-0369;>ADGP\^`r{68:<>@BDFHJLORUX[^adgjmpsvy|!#%')+-/13579;=^ls}  %2468KT_d ( * , . 0 2 4 @ e g i k l n o q s        3 5 7 9 ; = ? K h j l n p r t        - J L N P R T V [ d s z     3 : B c u      . W Y [ \ ^ ` b d e    /6?FORTV| !).CEGIKUbegp!#%&(*,56O %')+-/13579;R_acenwCEGHJLNPQi ]j|'5GHIKMOQSUWY[]_acegij%/7Kdmr{|}"$&(,9:;=FK`x$579;=fhjkmoqstLMNPRTVXZ\^`bdfhjlno ".=GRTghjktR_!#(*,G^g| %.0279;=?ACFH  "$&(*,.024]_abdfhjk 13579Ld   4UWY[]_ai   " $ & * ; D G I K ` b d f h s | !!!!!!{!!!"" "("4">"]"j"w""""""""""""""""#### # # #####H#R#\#f#####################$ $$$$$>$I$V$a$p$$$$$$$$$$$$$$$$$$$$$% % %!%#%%%'%)%;%D%X%c%w%%%%%%%%%%%%%%%%%& &&'&)&+&-&/&9&F&K&M&V&b&m&y&&&&&&&&&''''' ' ' ''''''''8'G'R'g'i'k'm'o'x'{'}''''''( ((((*(/(1(3(5(>(@(B(D(W(`(b(d(m(v(}((((((((((((()))#),)6)8):)<)=)?)A)C)L)N)P)Y)q)~))))))))))))))***"*/*8*C*[*f*******************+++++++!+$+=+f+u+}+++++++++++, ,,*,7,@,S,^,q,,,,,,,,,,,,,,,- - - -------3-D-F-I-L-N-----------------....1.3.6.9.<.?.B.E.G.H.S.d.f.h.k............/////////://A/C/E/R/^/`//////////////////00"0%0(0103040=0F0I0K0h0j0l0o0q0s0000000000000000000001191B1E1G1P1Y1b1p1111111111111111122222 22+2-2/22242?2P2R2U2X2Z22222222222222222223333 3 30333637393;3=3>3W3|3333333333333333333344444 444,4;4F4O4j4m4o4r4u4x4{4~4444444444444444455 5 555&5)5,5/515:5=5@5B5Y5555555555555555555566 6 6%6>6c6f6i6j6l6n6p6q666666666666666667 7-70727476787;7D7i7l7o7p7r7t7v7w7777777777777777788487898;8=8?8B8H8m8p8s8t8v8x8z8{888888888888999999 9!9>9@9B9D9F9H9S9k9v99999999999999999::::-:/:1:4:6:B:S:U:W:Z:\:m:o:q:t:v:::::::::::::::; ; ;;;;;.;0;2;5;8;@;Q;S;U;X;[;b;s;u;w;z;};;;;;;;;;;;;;;;;;;;;<<<< << <<<<<<<<<<<<<<<<<<<<<<<<===== = = ==========!=#=%='=)=,=.=1=4=7=:===@=C=E=G=J=M=P=S=V=Y=\=_=b=e=g=i=l=o=r=u=x={=~==========================>> >;>H>Q>V>_?????????? ?"?$?&?(?*?,?.?0?2?4?6?8?:??@?B?D?F?H?J?L?N?P?R?T?V?X?Z?\?^?`?b?d?f?h?k?m?o?r?t?w?y?|?~??????????????????????????????????@@@@@@@@@@@@@@@@@@@@@@@@@AAAAAA A AAAAAAAAAA A"A$A&A(A+A-A0A3A6A9AEAEDEGEJEMEPESEVEYE\E_EbEeEhEkEnEqEtEwEzE}EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEFFFF 1050 14A389 6250 1343.14 755.00 com.apple.InterfaceBuilder.CocoaPlugin 6250 NSBox NSButton NSButtonCell NSCustomObject NSLevelIndicator NSLevelIndicatorCell NSMenu NSMenuItem NSNumberFormatter NSScrollView NSScroller NSTableColumn NSTableView NSTextField NSTextFieldCell NSUserDefaultsController NSView NSWindowTemplate com.apple.InterfaceBuilder.CocoaPlugin InstanceManager FirstResponder NSApplication NSFontManager YES upsname 2147483647 NSImage NSMenuCheckmark NSImage NSMenuMixedState upshost 2147483647 YES YES 2147483647 Show Status 2147483647 Show Events 2147483647 YES YES 2147483647 Preferences... 2147483647 Start at login 2147483647 YES YES 2147483647 Add Monitor 2147483647 Remove Monitor 2147483647 Remove All Monitors 2147483647 YES YES 2147483647 About apcagent 2147483647 Quit 2147483647 AppController 1 2 {{889, 673}, {391, 229}} 603980800 Apcagent Preferences NSWindow 268 {{281, 13}, {96, 32}} YES 67108864 134217728 OK YES 13 1044 -2034876416 129 DQ 200 25 NO 4108 274 268 {{168, 81}, {96, 22}} YES -1804599231 -1874852864 port -∞ +∞ # # NaN 3 YES YES YES . , NO NO YES YES 6 System textBackgroundColor 3 MQA 6 System textColor 3 MAA NO 1 268 {{168, 49}, {96, 22}} YES -1804599231 -1874852864 refresh -∞ +∞ # # NaN 0 0 YES NO 1 AAAAAAAAAAAAAAAAAAAAAA 3 YES YES YES . , NO NO YES YES NO 1 268 {{169, 113}, {168, 22}} YES -1804599231 272630784 hostname YES NO 1 268 {{-3, 115}, {167, 17}} YES 68157504 71304192 Hostname or IP Address: 6 System controlColor 3 MC42NjY2NjY2NjY3AA 6 System controlTextColor NO 1 268 {{37, 84}, {127, 17}} YES 68157504 71304192 Port: NO 1 268 {{16, 51}, {149, 17}} YES 68157504 71304192 Refresh: NO 1 268 {{270, 51}, {61, 17}} YES 68157504 272630784 seconds NO 1 268 {{270, 83}, {70, 17}} YES 68157504 272630784 (1-65535) NO 1 -2147483380 {{121, 17}, {155, 18}} YES -1543503872 0 Enable Notifications 1211912448 130 NSImage NSSwitch NSSwitch 200 25 NO {{1, 1}, {355, 159}} {{17, 50}, {357, 161}} {0, 0} 67108864 0 Box YES 11 3100 6 System labelColor 1 0 0 NO {391, 229} {{0, 0}, {1280, 937}} {10000000000000, 10000000000000} YES 11 2 {{378, 358}, {456, 438}} 1677722624 Apcupsd Status NSWindow {456, 438} 258 274 2304 274 {414, 322} YES NO YES -2147483392 {{-26, 0}, {16, 17}} 0 101 40 1000 75497536 2048 3 MC4zMzMzMzI5OQA 6 System headerTextColor 337641536 2048 Text Cell 6 System controlBackgroundColor 3 YES YES compare: 1 307 40 1000 75497536 2048 337641536 2048 Text Cell 3 YES 3 2 6 System gridColor 3 MC41AA 17 1656750080 1 4 15 0 NO 0 1 {{1, 1}, {414, 322}} 4 YES -2147483392 {{400, 1}, {15, 307}} NO _doScroller: _doScroller: 0.99690400000000001 -2147483392 {{1, 308}, {399, 15}} NO _doScroller: 1 _doScroller: 0.99759039999999999 {{20, 20}, {416, 324}} 133682 QSAAAEEgAABBmAAAQZgAAA 0.25 4 1 268 {{83, 400}, {133, 18}} YES 0 0 100 100 20 10 1 1 NO 268 {{83, 369}, {133, 22}} YES -2073034687 138413056 YES NO 1 268 {{303, 370}, {74, 22}} YES -2073034687 138413056 YES NO 1 268 {{17, 372}, {61, 17}} YES 68157504 71304192 Status: NO 1 268 {{237, 372}, {61, 17}} YES 68157504 71304192 Runtime: NO 1 268 {{17, 400}, {61, 17}} YES 68157504 71304192 Battery: NO 1 268 {{80, 400}, {139, 17}} YES 68157504 138413056 100% NO 1 268 {{303, 399}, {133, 18}} YES 0 0 50 100 75 90 1 1 NO 268 {{252, 400}, {46, 17}} YES 68157504 71304192 Load: NO 1 268 {{300, 400}, {139, 17}} YES 68157504 138413056 50% NO 1 268 {{382, 372}, {60, 17}} YES 68157504 272630784 Minutes NO 1 10 {{12, 354}, {432, 5}} {0, 0} 67108864 0 Box 3 2 0 NO {456, 438} {{0, 0}, {1280, 937}} {456, 460} {10000000000000, 10000000000000} YES 11 2 {{196, 239}, {455, 271}} 1677721600 Apcupsd Events NSWindow {455, 271} 256 274 2304 256 {413, 229} YES NO YES 256 {{399, 0}, {16, 17}} 410 40 1000 75497536 2048 3 MC4zMzMzMzI5OQA 337641536 2048 Text Cell 3 YES 3 2 17 46137344 4 15 0 NO 0 1 {{1, 1}, {413, 229}} 4 YES -2147483392 {{399, 0}, {15, 215}} NO _doScroller: _doScroller: 0.99537039999999999 -2147483392 {{1, 215}, {398, 15}} NO _doScroller: 1 _doScroller: 0.99749370000000004 {{20, 20}, {415, 231}} 133682 QSAAAEEgAABBmAAAQZgAAA 0.25 4 1 {455, 271} {{0, 0}, {1280, 937}} {455, 293} {10000000000000, 10000000000000} YES YES remove: 623 add: 624 removeAll: 632 startAtLogin: 637 terminate: 458 delegate 621 statusMenu 456 configWindow 470 configHost 487 configPort 488 configRefresh 489 configComplete: 490 statusBatteryBar 538 statusBatteryText 539 statusRuntime 540 statusText 541 statusWindow 542 statusGrid 543 status: 546 statusLoadText 556 statusLoadBar 557 eventsWindow 564 events: 567 eventsGrid 582 about: 587 upsName 628 upsHost 630 config: 635 startAtLogin 638 configPopups 661 initialFirstResponder 493 nextKeyView 491 nextKeyView 492 nextKeyView 496 0 -2 File's Owner -1 First Responder -3 Application 420 450 StatusItem 452 455 467 ConfigWindow 468 485 486 503 StatusWindow 504 505 506 507 508 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 531 545 550 551 552 553 554 555 558 EventsWindow 559 566 573 574 575 576 578 581 583 584 585 616 618 625 627 629 631 633 634 636 650 476 477 480 481 472 473 664 673 665 672 666 671 667 670 668 669 674 676 678 639 640 com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {544.5, 438.5} com.apple.InterfaceBuilder.CocoaPlugin {{84, 405}, {391, 329}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{160, 214}, {456, 438}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{54, 78}, {455, 271}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin ActiveNumberFormatter com.apple.InterfaceBuilder.CocoaPlugin ActiveNumberFormatter com.apple.InterfaceBuilder.CocoaPlugin 678 0 IBCocoaFramework NO com.apple.InterfaceBuilder.CocoaPlugin.macosx com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 YES 3 {12, 12} {10, 2} {15, 15} apcupsd-3.14.14/src/apcagent/Makefile000066400000000000000000000035721274230402600173430ustar00rootroot00000000000000topdir:=../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.m) $(wildcard *.c) LIBS := -Wl,-framework -Wl,Cocoa -Wl,-framework -Wl,ApplicationServices $(LIBS) all-targets: apcagent MainMenu.nib apcagent.app apcagent: $(OBJS) $(APCLIBS) $(LINK) apcagent.app: apcagent MainMenu.nib Info.plist PkgInfo \ $(topdir)/doc/images/commlost.png \ $(topdir)/doc/images/charging.png \ $(topdir)/doc/images/onbatt.png \ $(topdir)/doc/images/online.png @$(ECHO) " BUNDL" $@ $(V)$(RMF) apcagent.app $(V)$(MKINSTALLDIRS) apcagent.app/Contents/MacOS $(V)$(MKINSTALLDIRS) apcagent.app/Contents/Resources $(V)$(MKINSTALLDIRS) apcagent.app/Contents/Frameworks $(V)$(MKINSTALLDIRS) apcagent.app/Contents/Resources/English.lproj $(V)$(INSTALL_PROGRAM) $(STRIP) -m 755 apcagent apcagent.app/Contents/MacOS $(V)$(SED) -e "s/__VERSION__/${VERSION}/" Info.plist > /tmp/Info.plist.out $(V)$(INSTALL_DATA) -m 644 /tmp/Info.plist.out apcagent.app/Contents/Info.plist $(V)$(INSTALL_DATA) -m 644 PkgInfo apcagent.app/Contents $(V)$(INSTALL_DATA) -m 644 MainMenu.nib apcagent.app/Contents/Resources/English.lproj $(V)$(INSTALL_DATA) -m 644 $(topdir)/doc/images/commlost.png apcagent.app/Contents/Resources $(V)$(INSTALL_DATA) -m 644 $(topdir)/doc/images/charging.png apcagent.app/Contents/Resources $(V)$(INSTALL_DATA) -m 644 $(topdir)/doc/images/onbatt.png apcagent.app/Contents/Resources $(V)$(INSTALL_DATA) -m 644 $(topdir)/doc/images/online.png apcagent.app/Contents/Resources $(V)$(RMF) /tmp/Info.plist.out apcagent.dmg: apcagent.app hdiutil create -ov -srcfolder apcagent.app apcagent.dmg all-install: install-apcagent all-uninstall: uninstall-apcagent install-apcagent: $(call MKDIR,/Applications) $(call COPY,apcagent.app,Applications) uninstall-apcagent: $(call UNINST,/Applications/apcagent.app) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/apcagent/NSString+uuid.h000066400000000000000000000005211274230402600205140ustar00rootroot00000000000000/* * NSString+uuid.h * * UUID category for NSString * * Everyone seems to create their own version of this (hint, hint, Apple!) * This one is courtesy of Vincent Gable * */ #import @interface NSString(uuid) + (NSString *)stringWithUUID; @end apcupsd-3.14.14/src/apcagent/NSString+uuid.m000066400000000000000000000010621274230402600205220ustar00rootroot00000000000000/* * NSString+uuid.m * * UUID category for NSString * * Everyone seems to create their own version of this (hint, hint, Apple!) * This one is courtesy of Vincent Gable * */ #include #import "NSString+uuid.h" @implementation NSString(uuid) + (NSString*) stringWithUUID { CFUUIDRef uuidObj = CFUUIDCreate(nil); NSString *uuidString = (NSString*)CFUUIDCreateString(nil, uuidObj); CFRelease(uuidObj); return [uuidString autorelease]; } @end apcupsd-3.14.14/src/apcagent/PkgInfo000066400000000000000000000000101274230402600171430ustar00rootroot00000000000000APPL????apcupsd-3.14.14/src/apcagent/main.m000066400000000000000000000020701274230402600167750ustar00rootroot00000000000000/* * main.m * * Apcupsd monitoring applet for Mac OS X */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #import #import "InstanceManager.h" int main(int argc, char *argv[]) { NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init]; [[[InstanceManager alloc] init] createMonitors]; [p release]; // run is never coming back, so free the pool now [[NSApplication sharedApplication] run]; } apcupsd-3.14.14/src/apcnis.c000066400000000000000000000203301274230402600155310ustar00rootroot00000000000000/* * apcnis.c * * Network server for apcupsd. */ /* * Copyright (C) 1999-2006 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #ifdef HAVE_NISSERVER static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static char largebuf[4096]; static int stat_recs; struct s_arg { UPSINFO *ups; int newsockfd; }; /* forward referenced subroutines */ void *handle_client_request(void *arg); static void status_open(UPSINFO *ups) { P(mutex); largebuf[0] = 0; stat_recs = 0; } #define STAT_REV 1 /* * Send the status lines across the network one line * at a time (to prevent sending too large a buffer). * * Returns -1 on error or EOF * 0 OK */ static int status_close(UPSINFO *ups, int nsockfd) { int i; char buf[MAXSTRING]; char *sptr, *eptr; i = strlen(largebuf); asnprintf(buf, sizeof(buf), "APC : %03d,%03d,%04d\n", STAT_REV, stat_recs, i); if (net_send(nsockfd, buf, strlen(buf)) <= 0) { V(mutex); return -1; } sptr = eptr = largebuf; for (; i > 0; i--) { if (*eptr == '\n') { eptr++; if (net_send(nsockfd, sptr, eptr - sptr) <= 0) break; sptr = eptr; } else { eptr++; } } if (net_send(nsockfd, NULL, 0) < 0) { V(mutex); return -1; } V(mutex); return 0; } /* * Buffer up the status messages so that they can be sent * by the status_close() routine over the network. */ static void status_write(UPSINFO *ups, const char *fmt, ...) { va_list ap; int i; char buf[MAXSTRING]; va_start(ap, fmt); avsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if ((i = (strlen(largebuf) + strlen(buf))) < (int)(sizeof(largebuf) - 1)) { strlcat(largebuf, buf, sizeof(largebuf)); stat_recs++; } else { log_event(ups, LOG_ERR, "apcserver.c: Status buffer overflow %d bytes\n", i - sizeof(largebuf)); } } void do_server(UPSINFO *ups) { int newsockfd, sockfd; struct sockaddr_in cli_addr; /* client's address */ struct sockaddr_in serv_addr; /* our address */ int tlog; struct s_arg *arg; struct in_addr local_ip; #ifndef HAVE_MINGW int turnon = 1; #endif for (tlog = 0; (ups = attach_ups(ups)) == NULL; tlog -= 5 * 60) { if (tlog <= 0) { tlog = 60 * 60; log_event(ups, LOG_ERR, "apcserver: Cannot attach SYSV IPC.\n"); } sleep(5 * 60); } local_ip.s_addr = INADDR_ANY; if (ups->nisip[0]) { if (inet_pton(AF_INET, ups->nisip, &local_ip) != 1) { log_event(ups, LOG_WARNING, "Invalid NISIP specified: '%s'", ups->nisip); local_ip.s_addr = INADDR_ANY; } } /* Open a TCP socket */ for (tlog = 0; (sockfd = socket_cloexec(AF_INET, SOCK_STREAM, 0)) < 0; tlog -= 5 * 60) { if (tlog <= 0) { tlog = 60 * 60; log_event(ups, LOG_ERR, "apcserver: cannot open stream socket"); } sleep(5 * 60); } /* Reuse old sockets */ #ifndef HAVE_MINGW if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&turnon, sizeof(turnon)) < 0) { log_event(ups, LOG_WARNING, "Cannot set SO_REUSEADDR on socket: %s\n", strerror(errno)); } #endif /* Bind our local address so that the client can send to us. */ memset((char *)&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr = local_ip; serv_addr.sin_port = htons(ups->statusport); for (tlog = 0; bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0; tlog -= 5 * 60) { if (tlog <= 0) { tlog = 60 * 60; log_event(ups, LOG_ERR, "apcserver: cannot bind port %d. ERR=%s", ups->statusport, strerror(errno)); } sleep(5 * 60); } listen(sockfd, 5); /* tell system we are ready */ log_event(ups, LOG_INFO, "NIS server startup succeeded"); for (;;) { /* Wait for a connection from a client process. */ for (tlog = 0; (newsockfd = net_accept(sockfd, &cli_addr)) < 0; tlog -= 5 * 60) { if (tlog <= 0) { tlog = 60 * 60; log_event(ups, LOG_ERR, "apcserver: accept error. ERR=%s", strerror(errno)); } sleep(5 * 60); } #ifdef HAVE_LIBWRAP /* * This function checks the incoming client and if it's not * allowed closes the connection. */ if (check_wrappers(argvalue, newsockfd) == FAILURE) { net_close(newsockfd); continue; } #endif arg = (struct s_arg *)malloc(sizeof(struct s_arg)); arg->newsockfd = newsockfd; arg->ups = ups; pthread_t tid; pthread_create(&tid, NULL, handle_client_request, arg); } } /* * Accept requests from client. Send output one line * at a time followed by a zero length transmission. * * Return when the connection is terminated or there * is an error. */ void *handle_client_request(void *arg) { int len; FILE *events_file; char line[MAXSTRING]; const char errmsg[] = "Invalid command\n"; const char notavail[] = "Not available\n"; const char notrun[] = "Apcupsd internal error\n"; int nsockfd = ((struct s_arg *)arg)->newsockfd; UPSINFO *ups = ((struct s_arg *)arg)->ups; int fd; free(arg); pthread_detach(pthread_self()); if ((ups = attach_ups(ups)) == NULL) { net_send(nsockfd, notrun, sizeof(notrun)); net_send(nsockfd, NULL, 0); net_close(nsockfd); return NULL; } for (;;) { /* Read command */ if ((len = net_recv(nsockfd, line, sizeof(line))) <= 0) break; /* connection terminated */ if (len == 6 && strncmp("status", line, 6) == 0) { if (output_status(ups, nsockfd, status_open, status_write, status_close) < 0) { break; } } else if (len == 6 && strncmp("events", line, 6) == 0) { if (ups->eventfile[0] == 0 || (fd = open(ups->eventfile, O_RDONLY|O_CLOEXEC)) == -1 || (events_file = fdopen(fd, "r")) == NULL) { net_send(nsockfd, notavail, sizeof(notavail)); if (net_send(nsockfd, NULL, 0) < 0) break; } else { int stat = output_events(nsockfd, events_file); fclose(events_file); if (stat < 0) { net_send(nsockfd, notavail, sizeof(notavail)); net_send(nsockfd, NULL, 0); break; } } } else { net_send(nsockfd, errmsg, sizeof(errmsg)); if (net_send(nsockfd, NULL, 0) < 0) break; } } net_close(nsockfd); detach_ups(ups); return NULL; } #else /* HAVE_NISSERVER */ void do_server(UPSINFO *ups) { log_event(ups, LOG_ERR, "apcserver: code not enabled in config.\n"); exit(1); } #endif /* HAVE_NISSERVER */ #ifdef HAVE_LIBWRAP /* * Unfortunately this function is also used by the old network code * so for now compile it in anyway. */ int allow_severity = LOG_INFO; int deny_severity = LOG_WARNING; int check_wrappers(char *av, int newsock) { struct request_info req; char *av0; av0 = strrchr(av, '/'); if (av0) av0++; /* strip everything before and including / */ else av0 = av; request_init(&req, RQ_DAEMON, av0, RQ_FILE, newsock, NULL); fromhost(&req); if (!hosts_access(&req)) { log_event(core_ups, LOG_WARNING, "Connection from %.500s refused by tcp_wrappers.", eval_client(&req)); return FAILURE; } #ifdef I_WANT_LOTS_OF_LOGGING log_event(core_ups, LOG_NOTICE, "connect from %.500s", eval_client(&req)); #endif return SUCCESS; } #endif /* HAVE_LIBWRAP */ apcupsd-3.14.14/src/apctest.c000066400000000000000000002271521274230402600157320ustar00rootroot00000000000000/* * apctest.c * * A cable tester program for apcupsd. * * Hacked from apcupsd.c by Kern Sibbald, Sept 2000 */ /* * Copyright (C) 2000-2004 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include UPSINFO *core_ups; UPSINFO *ups; int le_bit = TIOCM_LE; int st_bit = TIOCM_ST; int sr_bit = TIOCM_SR; int dtr_bit = TIOCM_DTR; int rts_bit = TIOCM_RTS; int cts_bit = TIOCM_CTS; int cd_bit = TIOCM_CD; int rng_bit = TIOCM_RNG; int dsr_bit = TIOCM_DSR; struct termios oldtio; struct termios newtio; /* Forward referenced functions */ static void do_dumb_testing(void); static void test1(void); static void test2(void); static void test3(void); static void test4(void); static void test5(void); static void test6(void); static void guess(void); static void do_smart_testing(void); #ifdef HAVE_APCSMART_DRIVER #include "drivers/apcsmart/apcsmart.h" static void smart_test1(void); static void smart_calibration(void); static void monitor_calibration_progress(int monitor); static void terminate_calibration(int ask); static void program_smart_eeprom(void); static void print_eeprom_values(UPSINFO *ups); static void smart_ttymode(void); static void parse_eeprom_cmds(char *eprom, char locale); static void print_valid_eeprom_values(UPSINFO *ups); #endif static void do_usb_testing(void); #ifdef HAVE_USB_DRIVER /* USB driver functions */ #include "drivers/usb/usb.h" /* Our own test functions */ static void usb_kill_power_test(void); static void usb_get_self_test_result(void); static void usb_run_self_test(void); static int usb_get_battery_date(void); static void usb_set_battery_date(void); static void usb_get_manf_date(void); static void usb_set_alarm(void); static void usb_set_sens(void); static void usb_set_xferv(int lowhigh); static void usb_calibration(); static void usb_test_alarm(void); static int usb_get_self_test_interval(void); static void usb_set_self_test_interval(void); #endif static void do_modbus_testing(void); #ifdef HAVE_MODBUS_DRIVER /* MODBUS driver functions */ #include "drivers/modbus/modbus.h" /* MODBUS register mapping */ #include "drivers/modbus/mapping.h" using namespace APCModbusMapping; /* Our own test functions */ static void modbus_kill_power_test(void); static void modbus_get_self_test_result(void); static void modbus_run_self_test(void); static uint64_t modbus_get_battery_date(void); static void modbus_set_battery_date(void); static void modbus_get_manf_date(void); //static void modbus_set_alarm(void); //static void modbus_set_sens(void); //static void modbus_set_xferv(int lowhigh); static void modbus_calibration(); static void modbus_test_alarm(void); //static int modbus_get_self_test_interval(void); //static void modbus_set_self_test_interval(void); #endif static void strip_trailing_junk(char *cmd); static char *get_cmd(const char *prompt); static int write_file(char *buf); /* Static variables */ static int normal, no_cable, no_power, low_batt; static int test1_done = 0; static int test2_done = 0; static int test3_done = 0; static int test4_done = 0; static int test5_done = 0; #define smart_poll(a, ups) \ ((ApcSmartUpsDriver*)((ups)->driver))->smart_poll(a) #define getline(a,b,ups) \ ((ApcSmartUpsDriver*)((ups)->driver))->getline(a,b) #define writechar(a,ups) \ ((ApcSmartUpsDriver*)((ups)->driver))->writechar(a) #define apcsmart_ups_program_eeprom(ups,ci,cmd) \ (ups)->driver->program_eeprom(ci, cmd) #define usb_read_int_from_ups(ups, ci, result) \ ((UsbUpsDriver*)((ups)->driver))->read_int_from_ups(ci, result) #define usb_write_int_to_ups(ups, ci, val, text) \ ((UsbUpsDriver*)((ups)->driver))->write_int_to_ups(ci, val, text) #define modbus_read_int_from_ups(ups, ci, result) \ ((ModbusUpsDriver*)((ups)->driver))->read_int_from_ups(ci, result) #define modbus_write_int_to_ups(ups, ci, val) \ ((ModbusUpsDriver*)((ups)->driver))->write_int_to_ups(ci, val) #define modbus_write_string_to_ups(ups, ci, val) \ ((ModbusUpsDriver*)((ups)->driver))->write_string_to_ups(ci, val) /* Print a message, and also write it to an output file */ static void pmsg(const char *fmt, ...) { char buf[3000]; va_list arg_ptr; va_start(arg_ptr, fmt); avsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr); va_end(arg_ptr); printf("%s", buf); fflush(stdout); write_file(buf); } /* Write output into "log" file */ static int write_file(char *buf) { static int out_fd = -1; if (out_fd == -1) { out_fd = open("apctest.output", O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0644); if (out_fd < 0) { printf("Could not create apctest.output: %s\n", strerror(errno)); return -1; } } return write(out_fd, buf, strlen(buf)); } /* Print out current time */ static void ptime(void) { char dt[MAXSTRING]; time_t now = time(NULL); strftime(dt, MAXSTRING, "%Y-%m-%d %T ", localtime(&now)); pmsg(dt); } /* * The terminate function; trapping signals allows apctest * to exit and cleanly close logfiles, and reset the tty back * to its original settings. You may want to add this * to all configurations. Of course, the file descriptors * must be global for this to work, I also set them to * NULL initially to allow terminate to determine whether * it should close them. */ void apctest_terminate(int sig) { if (sig != 0) { ptime(); pmsg("apctest exiting, signal %u\n", sig); } clear_files(); device_close(ups); delete_lockfile(ups); clean_threads(); closelog(); destroy_ups(ups); _exit(0); } void apctest_error_cleanup(UPSINFO *ups) { device_close(ups); delete_lockfile(ups); clean_threads(); pmsg("apctest error termination completed\n"); closelog(); destroy_ups(ups); exit(1); } /* * Subroutine error_out prints FATAL ERROR with file, * line number, and the error message then cleans up * and exits. It is normally called from the Error_abort * define, which inserts the file and line number. */ void apctest_error_out(const char *file, int line, const char *fmt, va_list arg_ptr) { char buf[256]; int i; asnprintf(buf, sizeof(buf), "apctest FATAL ERROR in %s at line %d\n", file, line); i = strlen(buf); avsnprintf((char *)&buf[i], sizeof(buf) - i, (char *)fmt, arg_ptr); pmsg(buf); apctest_error_cleanup(core_ups); /* finish the work */ } /* Main program */ /* This application must be linked as console app. */ int main(int argc, char *argv[]) { /* Set specific error_* handlers. */ error_out = apctest_error_out; /* * Default config file. If we set a config file in startup switches, it * will be re-filled by parse_options() */ cfgfile = APCCONF; ups = new_ups(); /* get new ups */ if (!ups) Error_abort("%s: init_ipc failed.\n", argv[0]); init_ups_struct(ups); core_ups = ups; /* this is our core ups structure */ /* parse_options is self messaging on errors, so we need only to exit() */ if (parse_options(argc, argv)) exit(1); pmsg("\n\n"); ptime(); pmsg("apctest " APCUPSD_RELEASE " (" ADATE ") " APCUPSD_HOST "\n"); pmsg("Checking configuration ...\n"); check_for_config(ups, cfgfile); attach_driver(ups); if (ups->driver == NULL) Error_abort("apctest cannot continue without a valid driver.\n"); // pmsg("Attached to driver: %s\n", ups->driver->driver_name); ups->start_time = time(NULL); /* Print configuration */ pmsg("sharenet.type = %s\n", ups->sharenet.long_name); pmsg("cable.type = %s\n", ups->cable.long_name); pmsg("mode.type = %s\n", ups->mode.long_name); if (create_lockfile(ups) == LCKERROR) { Error_abort("Unable to create UPS lock file.\n" " If apcupsd or apctest is already running,\n" " please stop it and run this program again.\n"); } pmsg("Setting up the port ...\n"); if (!setup_device(ups)) { Error_abort("Unable to open UPS device.\n" " If apcupsd or apctest is already running,\n" " please stop it and run this program again.\n"); } if (hibernate_ups) { pmsg("apctest: bad option, I cannot do a killpower\n"); apctest_terminate(0); } init_signals(apctest_terminate); pmsg("Doing prep_device() ...\n"); prep_device(ups); /* * This isn't a documented option but can be used * for testing dumb mode on a SmartUPS if you have * the proper cable. */ if (dumb_mode_test) { #ifdef HAVE_APCSMART_DRIVER char ans[20]; write(ups->fd, "R", 1); /* enter dumb mode */ *ans = 0; getline(ans, sizeof(ans), ups); pmsg("Going dumb: %s\n", ans); #else pmsg("apcsmart not compiled: dumb mode test unavailable\n"); #endif } switch (ups->mode.type) { case MODBUS_UPS: pmsg("\nYou are using a MODBUS cable type, so I'm entering MODBUS test mode\n"); do_modbus_testing(); break; case USB_UPS: pmsg("\nYou are using a USB cable type, so I'm entering USB test mode\n"); do_usb_testing(); break; case APCSMART_UPS: pmsg("\nYou are using a SMART cable type, so I'm entering SMART test mode\n"); do_smart_testing(); break; case DUMB_UPS: pmsg("\nYou are using a DUMB cable type, so I'm entering DUMB test mode\n"); do_dumb_testing(); break; default: pmsg("Testing not yet implemented for this UPSTYPE.\n"); } apctest_terminate(0); return -1; /* to keep compiler happy */ } static void print_bits(int bits) { char buf[200]; asnprintf(buf, sizeof(buf), "IOCTL GET: %x ", bits); if (bits & le_bit) strlcat(buf, "LE ", sizeof(buf)); if (bits & st_bit) strlcat(buf, "ST ", sizeof(buf)); if (bits & sr_bit) strlcat(buf, "SR ", sizeof(buf)); if (bits & dtr_bit) strlcat(buf, "DTR ", sizeof(buf)); if (bits & rts_bit) strlcat(buf, "RTS ", sizeof(buf)); if (bits & cts_bit) strlcat(buf, "CTS ", sizeof(buf)); if (bits & cd_bit) strlcat(buf, "CD ", sizeof(buf)); if (bits & rng_bit) strlcat(buf, "RNG ", sizeof(buf)); if (bits & dsr_bit) strlcat(buf, "DSR ", sizeof(buf)); strlcat(buf, "\n", sizeof(buf)); pmsg(buf); } static void do_dumb_testing(void) { int quit = FALSE; char *cmd; pmsg("Hello, this is the apcupsd Cable Test program.\n\n" "We are beginning testing for dumb UPSes, which\n" "use signaling rather than commands.\n" "Most tests enter a loop polling every second for 10 seconds.\n"); while (!quit) { pmsg("\n" "1) Test 1 - normal mode\n" "2) Test 2 - no cable\n" "3) Test 3 - no power\n" "4) Test 4 - low battery (requires test 3 first)\n" "5) Test 5 - battery exhausted\n" "6) Test 6 - kill UPS power\n" "7) Test 7 - run tests 1 through 5\n" "8) Guess which is the appropriate cable\n" "Q) Quit\n\n"); cmd = get_cmd("Select test number: "); if (cmd) { int item = atoi(cmd); switch (item) { case 1: test1(); break; case 2: test2(); break; case 3: test3(); break; case 4: test4(); break; case 5: test5(); break; case 6: test6(); break; case 7: test1(); test2(); test3(); test4(); test5(); break; case 8: guess(); break; default: if (tolower(*cmd) == 'q') quit = TRUE; else pmsg("Illegal response. Please enter 1-8,Q\n"); break; } } else { pmsg("Illegal response. Please enter 1-8,Q\n"); } } ptime(); pmsg("End apctest.\n"); } /* * Poll 10 times once per second and report any * change in serial port bits. */ static int test_bits(int inbits) { int i, nbits; int bits = inbits; for (i = 0; i < 10; i++) { if (ioctl(ups->fd, TIOCMGET, &nbits) < 0) { pmsg("ioctl error, big problem: %s\n", strerror(errno)); return 0; } if (i == 0 || nbits != bits) { ptime(); print_bits(nbits); bits = nbits; } sleep(1); } return bits; } static void test1(void) { pmsg("\nFor the first test, everything should be normal.\n" "The UPS should be plugged in to the power, and the serial cable\n" "should be connected to the computer.\n\n" "Please enter any character when ready to continue: "); (void)fgetc(stdin); pmsg("\n"); normal = test_bits(0); ptime(); pmsg("Test 1: normal condition, completed.\n"); test1_done = TRUE; } static void test2(void) { pmsg("\nFor the second test, the UPS should be plugged in to the power, \n" "but the serial port should be DISCONNECTED from the computer.\n\n" "Please enter any character when ready to continue: "); (void)fgetc(stdin); pmsg("\n"); no_cable = test_bits(0); ptime(); pmsg("Test 2: no cable, completed. \n"); test2_done = TRUE; } static void test3(void) { pmsg("\nFor the third test, the serial cable should be plugged\n" "back into the UPS, but the AC power plug to the UPS should be DISCONNECTED.\n\n" "Please enter any character when ready to continue: "); (void)fgetc(stdin); pmsg("\n"); no_power = test_bits(0); ptime(); pmsg("Test 3: no power, completed.\n"); test3_done = TRUE; } static void test4(void) { int i, bits; if (!test3_done) { pmsg("We need the output of test 3 to run this test.\n" "Please run test 3 first then this test.\n"); return; } pmsg("\nThe fourth test is the same as the third test:\n" "the serial cable should be plugged in to the UPS, but the AC power\n" "plug to the UPS should be DISCONNECTED. In addition, you should\n" "continue this test until the batteries are exhausted.\n" "If apctest detects a state change, it will stop\n" "the test. If not, hit control-C to stop the program\n\n" "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n" "Please enter any character when ready to continue: "); (void)fgetc(stdin); pmsg("\n"); low_batt = no_power; ptime(); pmsg("Start test 4: "); pmsg("\n"); /* Spin until we get a state change */ for (i = 0;; i++) { if (ioctl(ups->fd, TIOCMGET, &bits) < 0) { pmsg("ioctl error, big problem: %s\n", strerror(errno)); return; } if (bits != low_batt) { ptime(); print_bits(bits); low_batt = bits; break; } else if (i == 0) { ptime(); print_bits(bits); } sleep(1); } ptime(); pmsg("Test 4: low battery, completed.\n"); test4_done = TRUE; } static void test5(void) { int i, bits, last_bits = 0; pmsg("\nThe fifth test is the same as the third test:\n" "the serial cable should be plugged in to the UPS, but the AC power\n" "plug to the UPS should be DISCONNECTED. In addition, you should\n" "continue this test until the batteries are exhausted.\n" "If apctest detects a state change, contrary to test 4, it\n" "will not stop. The idea is to see ANY changed bits just up to\n" "the very moment that the UPS powers down.\n\n" "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n" "Please enter any character when ready to continue: "); (void)fgetc(stdin); pmsg("\n"); pmsg("Start test 5:\n"); /* Spin until we get a state change */ for (i = 0;; i++) { if (ioctl(ups->fd, TIOCMGET, &bits) < 0) { pmsg("ioctl error, big problem: %s\n", strerror(errno)); return; } if (i == 60) i = 0; /* force print once a minute */ if (i == 0 || bits != last_bits) { ptime(); print_bits(bits); last_bits = bits; } sleep(1); } /* Should never get here */ /* NOTREACHED */ ptime(); pmsg("Test 5: battery exhausted, completed.\n"); test5_done = TRUE; } static void test6(void) { int bits; pmsg("\nThis test will attempt to power down the UPS.\n" "The serial cable should be plugged in to the UPS, but the\n" "AC power plug to the UPS should be DISCONNECTED.\n\n" "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n" "Please enter any character when ready to continue: "); (void)fgetc(stdin); pmsg("\n"); if (ioctl(ups->fd, TIOCMGET, &bits) < 0) { pmsg("ioctl error, big problem: %s\n", strerror(errno)); return; } ptime(); print_bits(bits); make_file(ups, ups->pwrfailpath); initiate_hibernate(ups); unlink(ups->pwrfailpath); ptime(); pmsg("returned from kill_power function.\n"); if (ioctl(ups->fd, TIOCMGET, &bits) < 0) { pmsg("ioctl error, big problem: %s\n", strerror(errno)); return; } ptime(); print_bits(bits); } /* * Make a wild guess at the cable type * * If I had more data on each of the cable types, this could * be much improved. */ static void guess(void) { int found = 0; if (!(test1_done && test3_done)) { pmsg("Test 1 and test 3 must be performed before I can make a guess.\n"); return; } if (!(normal & (cd_bit | cts_bit)) && (no_power & cd_bit) && (low_batt & cts_bit)) { pmsg("This looks like a CUSTOM_SIMPLE cable\n"); found = 1; } if (!(normal & (cd_bit | cts_bit)) && (no_power & cts_bit) && (low_batt & cd_bit)) { pmsg("This looks like a 940-0020A\n"); found = 1; } if (!(normal & (cd_bit | sr_bit)) && (no_power & cd_bit) && (low_batt & sr_bit)) { pmsg("This looks like a 940-0023A cable\n"); found = 1; } if (!(normal & (rng_bit | cd_bit)) && (no_power & rng_bit) && (low_batt & cd_bit)) { pmsg("This looks like a 940-0095A cable\n"); found = 1; } if (!found) { pmsg("Hmmm. I don't quite know what you have. Sorry.\n"); } } static void do_smart_testing(void) { #ifdef HAVE_APCSMART_DRIVER char *cmd; int quit = FALSE; pmsg("Hello, this is the apcupsd Cable Test program.\n" "This part of apctest is for testing Smart UPSes.\n" "Please select the function you want to perform.\n"); while (!quit) { pmsg("\n" "1) Query the UPS for all known values\n" "2) Perform a Battery Runtime Calibration\n" "3) Abort Battery Calibration\n" "4) Monitor Battery Calibration progress\n" "5) Program EEPROM\n" "6) Enter TTY mode communicating with UPS\n" "Q) Quit\n\n"); cmd = get_cmd("Select function number: "); if (cmd) { int item = atoi(cmd); switch (item) { case 1: smart_test1(); break; case 2: smart_calibration(); break; case 3: terminate_calibration(1); break; case 4: monitor_calibration_progress(0); break; case 5: program_smart_eeprom(); break; case 6: smart_ttymode(); break; default: if (tolower(*cmd) == 'q') quit = TRUE; else pmsg("Illegal response. Please enter 1-6,Q\n"); break; break; } } else { pmsg("Illegal response. Please enter 1-6,Q\n"); } } ptime(); pmsg("End apctest.\n"); #else pmsg("APC Smart Driver not configured.\n"); #endif } #ifdef HAVE_APCSMART_DRIVER static void smart_ttymode(void) { #ifdef HAVE_MINGW // This is crap. Windows has no sane way (that I can find) to watch two // fds for activity from a single thread without involving the overly // complex "overlapped" io junk. So we will resort to polling. // Save any existing timeouts on the UPS fd HANDLE hnd = (HANDLE)_get_osfhandle(ups->fd); COMMTIMEOUTS orig_ups_ct; GetCommTimeouts(hnd, &orig_ups_ct); // Reset UPS fd timeout to 50 msec COMMTIMEOUTS ct; ct.ReadIntervalTimeout = MAXDWORD; ct.ReadTotalTimeoutMultiplier = 0; ct.ReadTotalTimeoutConstant = 50; ct.WriteTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; SetCommTimeouts(hnd, &ct); pmsg("Enter an ESC character (or ctl-[) to exit.\n\n"); char ch; while (1) { // Waits up to 50 msec for a char from the UPS if (read(ups->fd, &ch, 1) == 1) putch(ch); // Check if keyboard key was hit and read it (only Windows would // have a function dedicated to checking if a key has been pressed!) if (kbhit()) { ch = getch(); if (ch == 0x1b) break; else write(ups->fd, &ch, 1); } } // Restore original timeouts on UPS fd SetCommTimeouts(hnd, &orig_ups_ct); #else char ch; struct termios t, old_term_params; fd_set rfds; int stat; if (tcgetattr(0, &old_term_params) != 0) { pmsg("Cannot tcgetattr()\n"); return; } t = old_term_params; t.c_cc[VMIN] = 1; /* satisfy read after 1 char */ t.c_cc[VTIME] = 0; t.c_iflag &= ~(BRKINT | IGNPAR | PARMRK | INPCK | ISTRIP | ICRNL | IXON | IXOFF | INLCR | IGNCR); t.c_iflag |= IGNBRK; t.c_lflag &= ~(ICANON | ISIG | NOFLSH | TOSTOP); tcflush(0, TCIFLUSH); if (tcsetattr(0, TCSANOW, &t) == -1) { pmsg("Cannot tcsetattr()\n"); return; } pmsg("Enter an ESC character (or ctl-[) to exit.\n\n"); tcflush(ups->fd, TCIOFLUSH); for (;;) { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(ups->fd, &rfds); stat = select((ups->fd) + 1, &rfds, NULL, NULL, NULL); if (stat == -1) { pmsg("select() failed.\n"); break; } if (FD_ISSET(0, &rfds)) { if (read(0, &ch, 1) != 1) break; if (ch == 0x1B) break; write(ups->fd, &ch, 1); } if (FD_ISSET(ups->fd, &rfds)) { if (read(ups->fd, &ch, 1) != 1) break; write(1, &ch, 1); } } tcsetattr(0, TCSANOW, &old_term_params); #endif } /* Do runtime battery calibration */ static void smart_calibration(void) { char *ans, cmd; char answer[2000]; int stat, monitor, elapse; time_t start_time; pmsg("First ensure that we have a good link and \n" "that the UPS is functionning normally.\n"); pmsg("Simulating UPSlinkCheck ...\n"); tcflush(ups->fd, TCIOFLUSH); /* Start really simply */ cmd = 'Y'; stat = write(ups->fd, &cmd, 1); if (stat < 0) pmsg("Bad status from write: %s\n", strerror(errno)); stat = getline(answer, sizeof(answer), ups); pmsg("Wrote: Y Got: %s\n", answer); if (stat == FAILURE) { pmsg("getline failed. Apparently the link is not up.\n" "Giving up.\n"); return; } pmsg("Attempting to use smart_poll() ...\n"); ans = smart_poll('Y', ups); pmsg("Sent: Y Got: %s ", ans); if (strcmp(ans, "SM") == 0) { pmsg("Good -- smart_poll() works!.\n\n"); } else { pmsg("Not good.\nGiving up.\n"); return; } pmsg("Checking estimated runtime ...\n"); ans = smart_poll('j', ups); if (*ans >= '0' && *ans <= '9') { int rt = atoi(ans); pmsg("Current runtime is %d minutes\n", rt); } else { pmsg("Unexpected response from UPS: %s\n", ans); return; } pmsg("Checking for battery level ...\n"); ans = smart_poll('f', ups); if (strncmp(ans, "100.0", 5) == 0) { pmsg("Battery level is 100.0 -- OK\n"); } else { pmsg("Battery level %s insufficient to run test.\n", ans); return; } pmsg("\nThe battery calibration should automatically end\n" "when the battery level drops below about 25, depending\n" "on your UPS.\n\n" "I can also optionally monitor the progress\n" "and stop the calibration if it goes below 10. However,\n" "in the case of a new battery this may prematurely end the\n" "calibration loosing the effect.\n\n"); ans = get_cmd("Do you want me to stop the calibration\n" "if the battery level goes too low? (y/n): "); if (*ans == 'Y' || *ans == 'y') monitor = 1; else monitor = 0; pmsg("\nSending Battery Calibration command. ...\n"); ans = smart_poll('D', ups); if (*ans == '!' || strcmp(ans, "OK") == 0) { pmsg("UPS has initiated battery calibration.\n"); } else { pmsg("Unexpected response from UPS: %s\n", ans); return; } start_time = time(NULL); monitor_calibration_progress(monitor); elapse = time(NULL) - start_time; pmsg("On battery %d sec or %dm%ds.\n", elapse, elapse / 60, elapse % 60); } static void terminate_calibration(int ask) { char *ans, *cmd; if (ask) { pmsg("\nCAUTION! Don't use this command unless the UPS\n" "is already doing a calibration.\n"); cmd = get_cmd("Are you sure? (yes/no): "); if (strcmp(cmd, "yes") != 0) return; } pmsg("\nAttempting to abort calibration ...\n"); ans = smart_poll('D', ups); /* abort calibration */ if (*ans == '$' || strcmp(ans, "NO") == 0) { pmsg("Battery Runtime Calibration terminated.\n"); pmsg("Checking estimated runtime ...\n"); ans = smart_poll('j', ups); if (*ans >= '0' && *ans <= '9') { int rt = atoi(ans); pmsg("Updated runtime is %d\n", rt); } else { pmsg("Unexpected response from UPS: %s\n", ans); } } else { pmsg("Response to abort request: %s\n", ans); } } static void monitor_calibration_progress(int monitor) { char *ans; int count = 6; int max_count = 6; pmsg("Monitoring the calibration progress ...\n" "To stop the calibration, enter a return.\n"); for (;;) { int percent; char cmd; bool aborted = false; int retval = 0; #ifdef HAVE_MINGW // select only works on sockets on win32, so we must poll for (unsigned int i = 0; !aborted && retval == 0 && i < 10; ++i) { while (kbhit()) { aborted = true; (void)getch(); } if (!aborted) { COMMTIMEOUTS ct; HANDLE h = (HANDLE)_get_osfhandle(ups->fd); ct.ReadIntervalTimeout = MAXDWORD; ct.ReadTotalTimeoutMultiplier = MAXDWORD; ct.ReadTotalTimeoutConstant = 1000; ct.WriteTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; SetCommTimeouts(h, &ct); retval = read(ups->fd, &cmd, 1); } } #else fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(ups->fd, &rfds); FD_SET(STDIN_FILENO, &rfds); tv.tv_sec = 10; tv.tv_usec = 0; errno = 0; retval = select((ups->fd) + 1, &rfds, NULL, NULL, &tv); if (retval == -1 && (errno == EINTR || errno == EAGAIN)) { continue; } else if (retval != 0) { if (FD_ISSET(STDIN_FILENO, &rfds)) { /* *ANY* user input aborts the calibration */ read(STDIN_FILENO, &cmd, 1); aborted = true; } else if(FD_ISSET(ups->fd, &rfds)) { // UPS char retval = read(ups->fd, &cmd, 1); } } #endif if (retval == -1) { pmsg("\nselect/read failure.\n"); terminate_calibration(0); return; } if (aborted) { pmsg("\nUser input. Terminating calibration ...\n"); terminate_calibration(0); return; } if (retval != 0) { if (cmd == '$') { pmsg("\nBattery Runtime Calibration terminated by UPS.\n"); pmsg("Checking estimated runtime ...\n"); ans = smart_poll('j', ups); if (*ans >= '0' && *ans <= '9') { int rt = atoi(ans); pmsg("Remaining runtime is %d minutes\n", rt); } else { pmsg("Unexpected response from UPS: %s\n", ans); } return; /* ignore normal characters */ } else if (cmd == '!' || cmd == '+' || cmd == ' ' || cmd == '\n' || cmd == '\r') { continue; } else { pmsg("\nUPS sent: %c\n", cmd); } } else { if (++count >= max_count) { ans = smart_poll('f', ups); /* Get battery charge */ percent = (int)strtod(ans, NULL); pmsg("\nBattery charge %d\n", percent); if (percent > 0) { if (monitor && percent <= 10) { pmsg("Battery charge less than 10% terminating calibration ...\n"); terminate_calibration(0); return; } if (percent < 30) max_count = 2; /* report faster */ } ans = smart_poll('j', ups); /* Get runtime */ if (*ans >= '0' && *ans <= '9') { int rt = atoi(ans); pmsg("Remaining runtime is %d minutes\n", rt); if (monitor && rt < 2) { pmsg("Runtime less than 2 minutes terminating calibration ...\n"); terminate_calibration(0); return; } } count = 0; } else { printf("."); fflush(stdout); } } } } static void program_smart_eeprom(void) { char *cmd; int quit = FALSE; pmsg("This is the EEPROM programming section of apctest.\n" "Please select the function you want to perform.\n"); while (!quit) { pmsg("\n" " 1) Print EEPROM values\n" " 2) Change Battery date\n" " 3) Change UPS name\n" " 4) Change sensitivity\n" " 5) Change alarm delay\n" " 6) Change low battery warning delay\n" " 7) Change wakeup delay\n" " 8) Change shutdown delay\n" " 9) Change low transfer voltage\n" "10) Change high transfer voltage\n" "11) Change battery return threshold percent\n" "12) Change output voltage when on batteries\n" "13) Change the self test interval\n" "14) Set EEPROM with conf file values\n" " Q) Quit\n\n"); cmd = get_cmd("Select function number: "); if (cmd) { int item = atoi(cmd); switch (item) { case 1: print_eeprom_values(ups); break; case 2: cmd = get_cmd("Enter new battery date -- DD/MM/YY: "); if (strlen(cmd) != 8 || cmd[2] != '/' || cmd[5] != '/') { pmsg("Date must be exactly DD/MM/YY\n"); break; } apcsmart_ups_program_eeprom(ups, CI_BATTDAT, cmd); break; case 3: cmd = get_cmd("Enter new UPS name -- max 8 chars: "); if (strlen(cmd) == 0 || strlen(cmd) > 8) { pmsg("Name must be between 1 and 8 characters long.\n"); break; } apcsmart_ups_program_eeprom(ups, CI_IDEN, cmd); break; case 4: cmd = get_cmd("Enter new sensitivity: "); apcsmart_ups_program_eeprom(ups, CI_SENS, cmd); break; case 5: cmd = get_cmd("Enter new alarm delay: "); apcsmart_ups_program_eeprom(ups, CI_DALARM, cmd); break; case 6: cmd = get_cmd("Enter new low battery delay: "); apcsmart_ups_program_eeprom(ups, CI_DLBATT, cmd); break; case 7: cmd = get_cmd("Enter new wakeup delay: "); apcsmart_ups_program_eeprom(ups, CI_DWAKE, cmd); break; case 8: cmd = get_cmd("Enter new shutdown delay: "); apcsmart_ups_program_eeprom(ups, CI_DSHUTD, cmd); break; case 9: cmd = get_cmd("Enter new low transfer voltage: "); apcsmart_ups_program_eeprom(ups, CI_LTRANS, cmd); break; case 10: cmd = get_cmd("Enter new high transfer voltage: "); apcsmart_ups_program_eeprom(ups, CI_HTRANS, cmd); break; case 11: cmd = get_cmd("Enter new battery return level: "); apcsmart_ups_program_eeprom(ups, CI_RETPCT, cmd); break; case 12: cmd = get_cmd("Enter new output voltage on batteries: "); apcsmart_ups_program_eeprom(ups, CI_NOMOUTV, cmd); break; case 13: cmd = get_cmd("Enter new self test interval: "); apcsmart_ups_program_eeprom(ups, CI_STESTI, cmd); break; case 14: pmsg("The EEPROM values to be changed will be taken from\n" "the configuration directives in your apcupsd.conf file.\n"); cmd = get_cmd("Do you want to continue? (Y/N): "); if (*cmd != 'y' && *cmd != 'Y') { pmsg("EEPROM changes NOT made.\n"); break; } apcsmart_ups_program_eeprom(ups, -1, NULL); break; default: if (tolower(*cmd) == 'q') quit = TRUE; else pmsg("Illegal response. Please enter 1-14,Q\n"); break; } } else { pmsg("Illegal response. Please enter 1-14,Q\n"); } } ptime(); pmsg("End EEPROM programming.\n"); } static void smart_test1(void) { char *ans, *p, *o, cmd; char answer[2000]; char parts[2000]; int stat; #ifdef working char locale, locale1, locale2; #endif pmsg("I am going to run through the series of queries of the UPS\n" "that are used in initializing apcupsd.\n\n"); pmsg("Simulating UPSlinkCheck ...\n"); tcflush(ups->fd, TCIOFLUSH); /* Start really simply */ cmd = 'Y'; stat = write(ups->fd, &cmd, 1); if (stat < 0) pmsg("Bad status from write: %s\n", strerror(errno)); stat = getline(answer, sizeof(answer), ups); pmsg("Wrote: Y Got: %s\n", answer); if (stat == FAILURE) { pmsg("getline failed. Apparently the link is not up.\n" "Giving up.\n"); return; } pmsg("Attempting to use smart_poll() ...\n"); ans = smart_poll('Y', ups); pmsg("Sent: Y Got: %s ", ans); if (strcmp(ans, "SM") == 0) { pmsg("Good -- smart_poll() works!.\n\n"); } else { pmsg("Not good.\nGiving up.\n"); return; } pmsg("Going to ask for valid commands...\n"); cmd = 'a'; stat = write(ups->fd, &cmd, 1); if (stat != 1) pmsg("Bad response from write: %d %s\n", stat, strerror(errno)); *answer = 0; stat = getline(answer, sizeof(answer), ups); pmsg("Wrote: a Got: %s\n", answer); if (stat == FAILURE) { pmsg("Cannot get the list of valid commands (a very old ups perhaps ?).\n"); } /* Get protocol version */ for (p = answer, o = parts; *p && *p != '.'; p++) *o++ = *p; *o = 0; pmsg("Protocol version is: %s\n", parts); if (*p == '.') p++; /* Get alert characters */ for (o = parts; *p && *p != '.'; p++) { if (*p < 0x20) { *o++ = '^'; *o++ = *p + 'A' - 1; } else { *o++ = *p; } } *o = 0; pmsg("Alert characters are: %s\n", parts); if (*p == '.') p++; /* Get command characters */ for (o = parts; *p; p++) { if (*p < 0x20) { *o++ = '^'; *o++ = *p + 'A' - 1; } else { *o++ = *p; } } *o = 0; pmsg("Command characters are: %s\n", parts); pmsg("\nNow running through apcupsd get_UPS capabilities().\n" "NA indicates that the feature is Not Available\n\n"); pmsg("UPS Status: %s\n", smart_poll(ups->UPS_Cmd[CI_STATUS], ups)); pmsg("Line quality: %s\n", smart_poll(ups->UPS_Cmd[CI_LQUAL], ups)); pmsg("Reason for last transfer to batteries: %s\n", smart_poll(ups->UPS_Cmd[CI_WHY_BATT], ups)); pmsg("Self-Test Status: %s\n", smart_poll(ups->UPS_Cmd[CI_ST_STAT], ups)); pmsg("Line Voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_VLINE], ups)); pmsg("Line Voltage Max: %s\n", smart_poll(ups->UPS_Cmd[CI_VMAX], ups)); pmsg("Line Voltage Min: %s\n", smart_poll(ups->UPS_Cmd[CI_VMIN], ups)); pmsg("Output Voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_VOUT], ups)); pmsg("Batt level percent: %s\n", smart_poll(ups->UPS_Cmd[CI_BATTLEV], ups)); pmsg("Batt voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_VBATT], ups)); pmsg("UPS Load: %s\n", smart_poll(ups->UPS_Cmd[CI_LOAD], ups)); pmsg("Line freq: %s\n", smart_poll(ups->UPS_Cmd[CI_FREQ], ups)); pmsg("Runtime left: %s\n", smart_poll(ups->UPS_Cmd[CI_RUNTIM], ups)); pmsg("UPS Internal temp: %s\n", smart_poll(ups->UPS_Cmd[CI_ITEMP], ups)); pmsg("Dip switch settings: %s\n", smart_poll(ups->UPS_Cmd[CI_DIPSW], ups)); pmsg("Register 1: %s\n", smart_poll(ups->UPS_Cmd[CI_REG1], ups)); pmsg("Register 2: %s\n", smart_poll(ups->UPS_Cmd[CI_REG2], ups)); pmsg("Register 3: %s\n", smart_poll('8', ups)); pmsg("Sensitivity: %s\n", smart_poll(ups->UPS_Cmd[CI_SENS], ups)); pmsg("Wakeup delay: %s\n", smart_poll(ups->UPS_Cmd[CI_DWAKE], ups)); pmsg("Sleep delay: %s\n", smart_poll(ups->UPS_Cmd[CI_DSHUTD], ups)); pmsg("Low transfer voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_LTRANS], ups)); pmsg("High transfer voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_HTRANS], ups)); pmsg("Batt charge for return: %s\n", smart_poll(ups->UPS_Cmd[CI_RETPCT], ups)); pmsg("Alarm status: %s\n", smart_poll(ups->UPS_Cmd[CI_DALARM], ups)); pmsg("Low battery shutdown level: %s\n", smart_poll(ups->UPS_Cmd[CI_DLBATT], ups)); pmsg("UPS Name: %s\n", smart_poll(ups->UPS_Cmd[CI_IDEN], ups)); pmsg("UPS Self test interval: %s\n", smart_poll(ups->UPS_Cmd[CI_STESTI], ups)); pmsg("UPS manufacture date: %s\n", smart_poll(ups->UPS_Cmd[CI_MANDAT], ups)); pmsg("UPS serial number: %s\n", smart_poll(ups->UPS_Cmd[CI_SERNO], ups)); pmsg("Date battery replaced: %s\n", smart_poll(ups->UPS_Cmd[CI_BATTDAT], ups)); pmsg("Output voltage when on batteries: %s\n", smart_poll(ups->UPS_Cmd[CI_NOMOUTV], ups)); pmsg("Nominal battery voltage: %s\n", smart_poll(ups->UPS_Cmd[CI_NOMBATTV], ups)); pmsg("Percent humidity: %s\n", smart_poll(ups->UPS_Cmd[CI_HUMID], ups)); pmsg("Ambient temperature: %s\n", smart_poll(ups->UPS_Cmd[CI_ATEMP], ups)); pmsg("Firmware revision: %s\n", smart_poll(ups->UPS_Cmd[CI_REVNO], ups)); pmsg("Number of external batteries installed: %s\n", smart_poll(ups->UPS_Cmd[CI_EXTBATTS], ups)); pmsg("Number of bad batteries installed: %s\n", smart_poll(ups->UPS_Cmd[CI_BADBATTS], ups)); pmsg("UPS model as defined by UPS: %s\n", smart_poll(ups->UPS_Cmd[CI_UPSMODEL], ups)); pmsg("UPS EPROM capabilities string: %s\n", (ans = smart_poll(ups->UPS_Cmd[CI_EPROM], ups))); pmsg("The EPROM string is %d characters long!\n", strlen(ans)); pmsg("Hours since last self test: %s\n", smart_poll(ups->UPS_Cmd[CI_ST_TIME], ups)); pmsg("\nThat is all for now.\n"); return; } #endif static void do_usb_testing(void) { #ifdef HAVE_USB_DRIVER char *cmd; int quit = FALSE; pmsg("Hello, this is the apcupsd Cable Test program.\n" "This part of apctest is for testing USB UPSes.\n"); pmsg("\nGetting UPS capabilities..."); if (!ups->driver->get_capabilities()) pmsg("FAILED\nSome or all tests may not work!\n"); else pmsg("SUCCESS\n"); pmsg("\nPlease select the function you want to perform.\n"); while (!quit) { pmsg("\n" "1) Test kill UPS power\n" "2) Perform self-test\n" "3) Read last self-test result\n" "4) View/Change battery date\n" "5) View manufacturing date\n" "6) View/Change alarm behavior\n" "7) View/Change sensitivity\n" "8) View/Change low transfer voltage\n" "9) View/Change high transfer voltage\n" "10) Perform battery calibration\n" "11) Test alarm\n" "12) View/Change self-test interval\n" " Q) Quit\n\n"); cmd = get_cmd("Select function number: "); if (cmd) { int item = atoi(cmd); switch (item) { case 1: usb_kill_power_test(); break; case 2: usb_run_self_test(); break; case 3: usb_get_self_test_result(); break; case 4: usb_set_battery_date(); break; case 5: usb_get_manf_date(); break; case 6: usb_set_alarm(); break; case 7: usb_set_sens(); break; case 8: usb_set_xferv(0); break; case 9: usb_set_xferv(1); break; case 10: usb_calibration(); break; case 11: usb_test_alarm(); break; case 12: usb_set_self_test_interval(); break; default: if (tolower(*cmd) == 'q') quit = TRUE; else pmsg("Illegal response. Please enter 1-12,Q\n"); break; } } else { pmsg("Illegal response. Please enter 1-12,Q\n"); } } ptime(); pmsg("End apctest.\n"); #else pmsg("USB Driver not configured.\n"); #endif } #ifdef HAVE_USB_DRIVER static void usb_set_xferv(int lowhigh) { int result; char* cmd; const char *text; int ci; if (lowhigh) { text = "HIGH"; ci = CI_HTRANS; } else { text = "LOW"; ci = CI_LTRANS; } if (!usb_read_int_from_ups(ups, ci, &result)) { pmsg("\nI don't know how to control the %s transfer voltage " " settings on your UPS.\n", text); return; } int newval; do { pmsg("Current %s transfer voltage setting: %d Volts\n", text, result); pmsg("Enter new %s transfer voltage (0 to cancel): ", text); cmd = get_cmd(""); newval = atoi(cmd); // Check for exit if (newval == 0) return; // Write new value usb_write_int_to_ups(ups, ci, newval, text); // Give write a chance to work, then read new value sleep(1); result = 0; if (!usb_read_int_from_ups(ups, ci, &result)) pmsg("FAILED to set new %s transfer voltage.\n\n", text); else if (result != newval) { pmsg("FAILED to set new %s transfer voltage.\n\n" "This is probably because you entered a value that is out-of-range\n" "for your UPS. The acceptable range of values varies based on UPS\n" "model. The UPS has probably set the value as close as possible to\n" "what you requested.\n\n", text); } } while (result != newval); pmsg("New %s transfer voltage setting: %d Volts\n", text, result); } static void usb_set_sens(void) { int result; char* cmd; if (!usb_read_int_from_ups(ups, CI_SENS, &result)) { pmsg("\nI don't know how to control the alarm settings on your UPS.\n"); return; } pmsg("Current sensitivity setting: "); switch(result) { case 0: pmsg("LOW\n"); break; case 1: pmsg("MEDIUM\n"); break; case 2: pmsg("HIGH\n"); break; default: pmsg("UNKNOWN\n"); break; } while(1) { pmsg("Press...\n" " L for Low sensitivity\n" " M for Medium sensitivity\n" " H for High sensitivity\n" " Q to Quit with no changes\n" "Your choice: "); cmd = get_cmd("Select function: "); if (cmd) { switch(tolower(*cmd)) { case 'l': usb_write_int_to_ups(ups, CI_SENS, 0, "CI_SENS"); break; case 'm': usb_write_int_to_ups(ups, CI_SENS, 1, "CI_SENS"); break; case 'h': usb_write_int_to_ups(ups, CI_SENS, 2, "CI_SENS"); break; case 'q': return; default: pmsg("Illegal response.\n"); continue; } } else { pmsg("Illegal response.\n"); continue; } break; } /* Delay needed for readback to work */ sleep(1); if (!usb_read_int_from_ups(ups, CI_SENS, &result)) { pmsg("FAILED to set sensitivity\n"); } else { pmsg("New sensitivity setting: "); switch(result) { case 0: pmsg("LOW\n"); break; case 1: pmsg("MEDIUM\n"); break; case 2: pmsg("HIGH\n"); break; default: pmsg("UNKNOWN\n"); break; } } } static void usb_set_alarm(void) { int result; char* cmd; if (!usb_read_int_from_ups(ups, CI_DALARM, &result)) { pmsg("\nI don't know how to control the alarm settings on your UPS.\n"); return; } pmsg("Current alarm setting: "); switch(result) { case 1: pmsg("DISABLED\n"); break; case 2: pmsg("ENABLED\n"); break; default: pmsg("UNKNOWN\n"); break; } while(1) { pmsg("Press...\n" " E to Enable alarms\n" " D to Disable alarms\n" " Q to Quit with no changes\n" "Your choice: "); cmd = get_cmd("Select function: "); if (cmd) { switch(tolower(*cmd)) { case 'e': usb_write_int_to_ups(ups, CI_DALARM, 2, "CI_DALARM"); break; case 'd': usb_write_int_to_ups(ups, CI_DALARM, 1, "CI_DALARM"); break; case 'q': return; default: pmsg("Illegal response.\n"); continue; } } else { pmsg("Illegal response.\n"); continue; } break; } /* Delay needed for readback to work */ sleep(1); if (!usb_read_int_from_ups(ups, CI_DALARM, &result)) { pmsg("FAILED to set alarm\n"); } else { pmsg("New alarm setting: "); switch(result) { case 1: pmsg("DISABLED\n"); break; case 2: pmsg("ENABLED\n"); break; default: pmsg("UNKNOWN\n"); break; } } } static void usb_kill_power_test(void) { pmsg("\nThis test will attempt to power down the UPS.\n" "The USB cable should be plugged in to the UPS, but the\n" "AC power plug to the UPS should be DISCONNECTED.\n\n" "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n" "Please enter any character when ready to continue: "); (void)fgetc(stdin); pmsg("\n"); ptime(); pmsg("calling kill_power function.\n"); make_file(ups, ups->pwrfailpath); initiate_hibernate(ups); unlink(ups->pwrfailpath); ptime(); pmsg("returned from kill_power function.\n"); } static void usb_get_self_test_result(void) { int result; if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) { pmsg("\nI don't know how to run a self test on your UPS\n" "or your UPS does not support self test.\n"); return; } pmsg("Result of last self test: "); switch (result) { case 1: pmsg("PASSED\n"); break; case 2: pmsg("WARNING\n"); break; case 3: pmsg("ERROR\n"); break; case 4: pmsg("ABORTED\n"); break; case 5: pmsg("IN PROGRESS\n"); break; case 6: pmsg("NO TEST PERFORMED\n"); break; default: pmsg("UNKNOWN (%02x)\n", result); break; } } static bool usb_clear_test_result() { int timeout, result; pmsg("Clearing previous self test result..."); // abort battery calibration in case it's in progress usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus"); if (!usb_write_int_to_ups(ups, CI_ST_STAT, 0, "SelftestStatus")) { pmsg("FAILED\n"); return false; } for (timeout = 0; timeout < 10; timeout++) { if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) { pmsg("FAILED\n"); return false; } if (result == 6) { pmsg("CLEARED\n"); break; } sleep(1); } if (timeout == 10) { pmsg("FAILED\n"); return false; } return true; } static void usb_run_self_test(void) { int result; int timeout; pmsg("\nThis test instructs the UPS to perform a self-test\n" "operation and reports the result when the test completes.\n\n"); if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) { pmsg("I don't know how to run a self test on your UPS\n" "or your UPS does not support self test.\n"); return; } if (!usb_clear_test_result()) return; pmsg("Initiating self test..."); if (!usb_write_int_to_ups(ups, CI_ST_STAT, 1, "SelftestStatus")) { pmsg("FAILED\n"); return; } pmsg("INITIATED\n"); pmsg("Waiting for test to complete..."); for (timeout = 0; timeout < 40; timeout++) { if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) { pmsg("ERROR READING STATUS\n"); usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus"); return; } if (result != 6) { pmsg("COMPLETED\n"); break; } sleep(1); } if (timeout == 40) { pmsg("TEST DID NOT COMPLETE\n"); usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus"); return; } usb_get_self_test_result(); } static int usb_get_battery_date(void) { int result; if (!usb_read_int_from_ups(ups, CI_BATTDAT, &result)) { pmsg("\nI don't know how to access the battery date on your UPS\n" "or your UPS does not support the battery date feature.\n"); return 0; } /* * Date format is: * YYYY|YYYM|MMMD|DDDD * bit 0-4: Day * 5-8: Month * 9-15: Year-1980 */ pmsg("Current battery date: %02u/%02u/%04u\n", (result & 0x1e0) >> 5, result & 0x1f, 1980 + ((result & 0xfe00) >> 9)); return result; } static void usb_set_battery_date(void) { char *cmd; int result, day, month, year, temp, max; if (!(result = usb_get_battery_date())) return; cmd = get_cmd("Enter new battery date (MM/DD/YYYY), blank to quit: "); if (!isdigit(cmd[0]) || !isdigit(cmd[1]) || cmd[2] != '/' || !isdigit(cmd[3]) || !isdigit(cmd[4]) || cmd[5] != '/' || !isdigit(cmd[6]) || !isdigit(cmd[7]) || !isdigit(cmd[8]) || !isdigit(cmd[9]) || cmd[10] != '\0' || ((month = strtoul(cmd, NULL, 10)) > 12) || (month < 1) || ((day = strtoul(cmd + 3, NULL, 10)) > 31) || (day < 1) || ((year = strtoul(cmd + 6, NULL, 10)) < 1980)) { pmsg("Invalid format.\n"); return; } result = ((year - 1980) << 9) | (month << 5) | day; pmsg("Writing new date..."); if (!usb_write_int_to_ups(ups, CI_BATTDAT, result, "ManufactureDate")) { pmsg("FAILED\n"); return; } pmsg("SUCCESS\n"); pmsg("Waiting for change to take effect..."); for (max = 0; max < 10; max++) { if (!usb_read_int_from_ups(ups, CI_BATTDAT, &temp)) { pmsg("ERROR\n"); return; } if (temp == result) break; sleep(1); } if (max == 10) pmsg("TIMEOUT\n"); else pmsg("SUCCESS\n"); usb_get_battery_date(); } static void usb_get_manf_date(void) { int result; if (!usb_read_int_from_ups(ups, CI_MANDAT, &result)) { pmsg("\nI don't know how to access the manufacturing date on your UPS\n" "or your UPS does not support the manufacturing date feature.\n"); return; } /* * Date format is: * YYYY|YYYM|MMMD|DDDD * bit 0-4: Day * 5-8: Month * 9-15: Year-1980 */ pmsg("Manufacturing date: %02u/%02u/%04u\n", (result & 0x1e0) >> 5, result & 0x1f, 1980 + ((result & 0xfe00) >> 9)); } static void usb_calibration() { int result; int aborted; int ilastbl; if (!ups->UPS_Cap[CI_ST_STAT] || !ups->UPS_Cap[CI_BATTLEV] || !ups->UPS_Cap[CI_LOAD]) { pmsg("\nI don't know how to run a battery calibration on your UPS\n" "or your UPS does not support battery calibration\n"); return; } pmsg("This test instructs the UPS to perform a battery calibration\n" "operation and reports the result when the process completes.\n" "The battery level must be at 100%% and the load must be at least\n" "10%% to begin this test.\n\n"); if (!usb_read_int_from_ups(ups, CI_BATTLEV, &result)) { pmsg("Failed to read current battery level\n"); return; } if (result == 100) { pmsg("Battery level is %d%% -- OK\n", result); } else { pmsg("Battery level %d%% is insufficient to run test.\n", result); return; } if (!usb_read_int_from_ups(ups, CI_LOAD, &result)) { pmsg("Failed to read current load level\n"); return; } if (result >= 10) { pmsg("Load level is %d%% -- OK\n", result); } else { pmsg("Load level %d%% is insufficient to run test.\n", result); return; } if (!usb_clear_test_result()) return; pmsg("\nThe battery calibration should automatically end\n" "when the battery level drops below about 25%%.\n" "This process can take minutes or hours, depending on\n" "the size of your UPS and the load attached.\n\n"); pmsg("Initiating battery calibration..."); if (!usb_write_int_to_ups(ups, CI_ST_STAT, 2, "SelftestStatus")) { pmsg("FAILED\n"); return; } pmsg("INITIATED\n\n"); pmsg("Waiting for calibration to complete...\n" "To abort the calibration, press ENTER.\n"); ilastbl = 0; while (1) { #ifndef HAVE_MINGW fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(STDIN_FILENO, &rfds); tv.tv_sec = 10; tv.tv_usec = 0; aborted = select(STDIN_FILENO+1, &rfds, NULL, NULL, &tv) == 1; if (aborted) { while (fgetc(stdin) != '\n') ; } #else aborted = false; for (int i = 0; i < 100 && !aborted; i++) { while (kbhit() && !aborted) aborted = getch() == '\r'; if (!aborted) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000000; nanosleep(&ts, NULL); } } #endif if (aborted) { pmsg("\n\nUser input detected; aborting calibration..."); if (!usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus")) { pmsg("FAILED\n"); } else { pmsg("ABORTED\n"); } return; } if (!usb_read_int_from_ups(ups, CI_ST_STAT, &result)) { pmsg("\n\nError reading status; aborting calibration..."); if (!usb_write_int_to_ups(ups, CI_ST_STAT, 3, "SelftestStatus")) { pmsg("FAILED\n"); } else { pmsg("ABORTED\n"); } return; } if (result != 5) { pmsg("\nCALIBRATION COMPLETED\n"); break; } // Output the battery level if (usb_read_int_from_ups(ups, CI_BATTLEV, &result)) { if (ilastbl == result) pmsg("."); else pmsg("\nBattery level: %d%%", result); ilastbl = result; } else pmsg("."); } usb_get_self_test_result(); } static void usb_test_alarm(void) { int result; if (!usb_read_int_from_ups(ups, CI_TESTALARM, &result)) { pmsg("\nI don't know how to test the alarm on your UPS.\n"); return; } // Write to UPS pmsg("Testing alarm..."); usb_write_int_to_ups(ups, CI_TESTALARM, 1, "CI_TESTALARM"); sleep(1); pmsg("COMPLETE\n"); } static int usb_get_self_test_interval(void) { int result; if (!usb_read_int_from_ups(ups, CI_STESTI, &result)) { pmsg("\nI don't know how to access the self-test interval on your UPS\n" "or your UPS does not support the self-test interval feature.\n"); return -1; } pmsg("Current Self-test interval: "); switch (result) { case 0: pmsg("None\n"); break; case 1: pmsg("Power On\n"); break; case 2: pmsg("7 days\n"); break; case 3: pmsg("14 days\n"); break; default: pmsg("UNKNOWN (%02x)\n", result); break; } return result; } static void usb_set_self_test_interval(void) { if (usb_get_self_test_interval() == -1) return; while(1) { pmsg("Press...\n" " 0 for None\n" " 1 for On Power\n" " 2 for 7 Days\n" " 3 for 14 Days\n" " Q to Quit with no changes\n" "Your choice: "); char *cmd = get_cmd("Select function: "); if (cmd) { if (*cmd >= '0' && *cmd <= '3') { usb_write_int_to_ups(ups, CI_STESTI, *cmd-'0', "CI_STESTI"); break; } else if (tolower(*cmd) == 'q') return; else pmsg("Illegal response.\n"); } else { pmsg("Illegal response.\n"); } } /* Delay needed for readback to work */ sleep(1); usb_get_self_test_interval(); } #endif /* Get next input command from the terminal */ static char *get_cmd(const char *prompt) { static char cmd[1000]; pmsg(prompt); if (fgets(cmd, sizeof(cmd), stdin) == NULL) return NULL; write_file(cmd); pmsg("\n"); strip_trailing_junk(cmd); return cmd; } /* Strip any trailing junk from the command */ static void strip_trailing_junk(char *cmd) { char *p; p = cmd + strlen(cmd) - 1; /* strip trailing junk from command */ while ((p >= cmd) && (*p == '\n' || *p == '\r' || *p == ' ')) *p-- = 0; } #ifdef HAVE_APCSMART_DRIVER /* * EPROM commands and their values as parsed from the * ^Z eprom string returned by the UPS. */ static struct { char cmd; char size; char num; char cmdvals[50]; } cmd[15]; /* Total number of EPROM commands */ static int ncmd = 0; static UPSINFO eeprom_ups; /* * Table of the UPS command, the apcupsd configuration directive, * and an explanation of what the command sets in the EPROM. */ static struct { char cmd; const char *config_directive; const char *descript; char type; int *data; } cmd_table[] = { {'u', "HITRANSFER", "Upper transfer voltage", 'i', &eeprom_ups.hitrans}, {'l', "LOTRANSFER", "Lower transfer voltage", 'i', &eeprom_ups.lotrans}, {'e', "RETURNCHARGE", "Return threshold", 'i', &eeprom_ups.rtnpct}, {'o', "OUTPUTVOLTS", "Output voltage on batts", 'i', &eeprom_ups.NomOutputVoltage}, {'s', "SENSITIVITY", "Sensitivity", 'c', (int *)eeprom_ups.sensitivity}, {'q', "LOWBATT", "Low battery warning", 'i', &eeprom_ups.dlowbatt}, {'p', "SLEEP", "Shutdown grace delay", 'i', &eeprom_ups.dshutd}, {'k', "BEEPSTATE", "Alarm delay", 'c', (int *)eeprom_ups.beepstate}, {'r', "WAKEUP", "Wakeup delay", 'i', &eeprom_ups.dwake}, {'E', "SELFTEST", "Self test interval", 'c', (int *)eeprom_ups.selftest}, {0, NULL, NULL} /* Last entry */ }; static void print_valid_eeprom_values(UPSINFO *ups) { int i, j, k, l; char *p; char val[100];; pmsg("\nValid EEPROM values for the %s\n\n", ups->mode.long_name); memcpy(&eeprom_ups, ups, sizeof(UPSINFO)); pmsg("%-24s %-12s %-6s %s\n", " ", "Config", "Current", "Permitted"); pmsg("%-24s %-12s %-6s %s\n", "Description", "Directive", "Value ", "Values"); pmsg("===================================================================\n"); for (i = 0; i < ncmd; i++) { for (j = 0; cmd_table[j].cmd; j++) { if (cmd[i].cmd == cmd_table[j].cmd) { if (cmd_table[j].type == 'c') asnprintf(val, sizeof(val), "%s", (char *)cmd_table[j].data); else asnprintf(val, sizeof(val), "%d", *cmd_table[j].data); pmsg("%-24s %-12s %-6s ", cmd_table[j].descript, cmd_table[j].config_directive, val); p = cmd[i].cmdvals; for (k = cmd[i].num; k; k--) { for (l = cmd[i].size; l; l--) pmsg("%c", *p++); pmsg(" "); } pmsg("\n"); break; } } } pmsg("===================================================================\n"); tcflush(ups->fd, TCIOFLUSH); smart_poll('Y', ups); smart_poll('Y', ups); pmsg("Battery date: %s\n", smart_poll(ups->UPS_Cmd[CI_BATTDAT], ups)); pmsg("UPS Name : %s\n", smart_poll(ups->UPS_Cmd[CI_IDEN], ups)); pmsg("\n"); } /* * Parse EPROM command string returned by a ^Z command. We * pull out only entries that correspond to our UPS (locale). */ static void parse_eeprom_cmds(char *eprom, char locale) { char *p = eprom; char c, l, n, s; #ifdef debuggggggg int i; #endif ncmd = 0; for (;;) { c = *p++; if (c == 0) break; if (c == '#') continue; l = *p++; /* get locale */ n = *p++ - '0'; /* get number of commands */ s = *p++ - '0'; /* get character size */ if (l != '4' && l != locale) { /* skip this locale */ p += n * s; continue; } cmd[ncmd].cmd = c; /* store command */ cmd[ncmd].size = s; /* chare length of each value */ cmd[ncmd].num = n; /* number of values */ strncpy(cmd[ncmd].cmdvals, p, n * s); /* save values */ p += n * s; ncmd++; } #ifdef debuggggggg printf("\n"); for (i = 0; i < ncmd; i++) { printf("cmd=%c len=%d nvals=%d vals=%s\n", cmd[i].cmd, cmd[i].size, cmd[i].num, cmd[i].cmdvals); } #endif } /*********************************************************************/ static void print_eeprom_values(UPSINFO *ups) { char locale, locale1, locale2; pmsg("Doing prep_device() ...\n"); prep_device(ups); if (!ups->UPS_Cap[CI_EPROM]) Error_abort("Your model does not support EPROM programming.\n"); if (ups->UPS_Cap[CI_REVNO]) locale1 = *(ups->firmrev + strlen(ups->firmrev) - 1); else locale1 = 0; if (ups->UPS_Cap[CI_UPSMODEL]) locale2 = *(ups->upsmodel + strlen(ups->upsmodel) - 1); else locale2 = 0; if (locale1 == locale2 && locale1 == 0) Error_abort("Your model does not support EPROM programming.\n"); if (locale1 == locale2) locale = locale1; if (locale1 == 0) locale = locale2; else locale = locale1; parse_eeprom_cmds(ups->eprom, locale); print_valid_eeprom_values(ups); } #endif static void do_modbus_testing(void) { #ifdef HAVE_MODBUS_DRIVER char *cmd; int quit = FALSE; pmsg("Hello, this is the apcupsd Cable Test program.\n" "This part of apctest is for testing MODBUS UPSes.\n"); pmsg("\nGetting UPS capabilities..."); if (!ups->driver->get_capabilities()) pmsg("FAILED\nSome or all tests may not work!\n"); else pmsg("SUCCESS\n"); pmsg("\nPlease select the function you want to perform.\n"); while (!quit) { pmsg("\n" "1) Test kill UPS power\n" "2) Perform self-test\n" "3) Read last self-test result\n" "4) View/Change battery date\n" "5) View manufacturing date\n" //"6) View/Change alarm behavior\n" //"7) View/Change sensitivity\n" //"8) View/Change low transfer voltage\n" //"9) View/Change high transfer voltage\n" "10) Perform battery calibration\n" "11) Test alarm\n" //"12) View/Change self-test interval\n" " Q) Quit\n\n"); cmd = get_cmd("Select function number: "); if (cmd) { int item = atoi(cmd); switch (item) { case 1: modbus_kill_power_test(); break; case 2: modbus_run_self_test(); break; case 3: modbus_get_self_test_result(); break; case 4: modbus_set_battery_date(); break; case 5: modbus_get_manf_date(); break; //case 6: // modbus_set_alarm(); // break; //case 7: // modbus_set_sens(); // break; //case 8: // modbus_set_xferv(0); // break; //case 9: // modbus_set_xferv(1); // break; case 10: modbus_calibration(); break; case 11: modbus_test_alarm(); break; //case 12: // modbus_set_self_test_interval(); // break; default: if (tolower(*cmd) == 'q') quit = TRUE; else pmsg("Illegal response. Please enter 1-12,Q\n"); break; } } else { pmsg("Illegal response. Please enter 1-12,Q\n"); } } ptime(); pmsg("End apctest.\n"); #else pmsg("MODBUS Driver not configured.\n"); #endif } #ifdef HAVE_MODBUS_DRIVER static void modbus_kill_power_test(void) { pmsg("\nThis test will attempt to power down the UPS.\n" "The MODBUS cable should be plugged in to the UPS, but the\n" "AC power plug to the UPS should be DISCONNECTED.\n\n" "PLEASE DO NOT RUN THIS TEST WITH A COMPUTER CONNECTED TO YOUR UPS!!!\n\n" "Please enter any character when ready to continue: "); (void)fgetc(stdin); pmsg("\n"); ptime(); pmsg("calling kill_power function.\n"); make_file(ups, ups->pwrfailpath); initiate_hibernate(ups); unlink(ups->pwrfailpath); ptime(); pmsg("returned from kill_power function.\n"); } static void modbus_get_self_test_result(void) { uint64_t uint; if (!modbus_read_int_from_ups(ups, REG_BATTERY_TEST_STATUS, &uint)) { pmsg("\nI don't know how to run a self test on your UPS\n" "or your UPS does not support self test.\n"); return; } pmsg("Result of last self test: "); if (uint == 0) { pmsg("NO TEST PERFORMED\n"); } else { if (uint & BTS_PENDING) pmsg("PENDING"); else if (uint & BTS_IN_PROGRESS) pmsg("IN PROGRESS"); else if (uint & BTS_PASSED) pmsg("PASSED"); else if (uint & BTS_FAILED) pmsg("FAILED"); else if (uint & BTS_REFUSED) pmsg("REFUSED"); else if (uint & BTS_ABORTED) pmsg("ABORTED"); else pmsg("0x%llx", uint); if (uint & BTS_INVALID_STATE) pmsg(" (INVALID STATE)"); else if (uint & BTS_INTERNAL_FAULT) pmsg(" (INTERNAL FAUILT)"); else if (uint & BTS_STATE_OF_CHARGE) pmsg(" (STATE_OF_CHARGE)"); if (uint & BTS_SRC_PROTOCOL) pmsg(" (PROTOCOL)"); else if (uint & BTS_SRC_LOCAL_UI) pmsg(" (LOCAL UI)"); else if (uint & BTS_SRC_INTERNAL) pmsg(" (INTERNAL)"); pmsg("\n"); } } static void modbus_run_self_test(void) { uint64_t uint; int timeout; pmsg("\nThis test instructs the UPS to perform a self-test\n" "operation and reports the result when the test completes.\n\n"); if (!modbus_read_int_from_ups(ups, REG_BATTERY_TEST_CMD, &uint)) { pmsg("I don't know how to run a self test on your UPS\n" "or your UPS does not support self test.\n"); return; } pmsg("Initiating self test..."); if (!modbus_write_int_to_ups(ups, REG_BATTERY_TEST_CMD, BTC_START_TEST)) { pmsg("FAILED\n"); return; } pmsg("INITIATED\n"); pmsg("Waiting for test to complete..."); for (timeout = 0; timeout < 40; timeout++) { if (!modbus_read_int_from_ups(ups, REG_BATTERY_TEST_STATUS, &uint)) { pmsg("ERROR READING STATUS\n"); return; } if ((uint & (BTS_PENDING|BTS_IN_PROGRESS)) == 0) { pmsg("COMPLETED\n"); break; } sleep(1); } if (timeout == 40) { pmsg("TEST DID NOT COMPLETE\n"); return; } modbus_get_self_test_result(); } static void modbus_calibration() { uint64_t result; bool aborted; uint64_t ilastbl; if (!ups->UPS_Cap[CI_ST_STAT] || !ups->UPS_Cap[CI_BATTLEV] || !ups->UPS_Cap[CI_LOAD]) { pmsg("\nI don't know how to run a battery calibration on your UPS\n" "or your UPS does not support battery calibration\n"); return; } pmsg("This test instructs the UPS to perform a battery calibration\n" "operation and reports the result when the process completes.\n" "The battery level must be at 100%% and the load must be above a\n" "certain minimum to begin this test. If the conditions are not\n" "met, the UPS will refuse the calibration attempt.\n"); pmsg("\nThe battery calibration should automatically end\n" "when the battery level drops below about 25%%.\n" "This process can take minutes or hours, depending on\n" "the size of your UPS and the load attached.\n\n"); pmsg("Initiating battery calibration..."); if (!modbus_write_int_to_ups(ups, REG_CALIBRATION_CMD, CC_START_CALIBRATION)) { pmsg("FAILED\n"); return; } pmsg("INITIATED\n\n"); pmsg("Waiting for calibration to complete...\n" "To abort the calibration, press ENTER.\n"); ilastbl = 0; while (1) { if (!modbus_read_int_from_ups(ups, REG_CALIBRATION_STATUS, &result)) { pmsg("\n\nError reading status; aborting calibration..."); if (!modbus_write_int_to_ups(ups, REG_CALIBRATION_CMD, CC_ABORT_CALIBRATION)) { pmsg("FAILED\n"); } else { pmsg("ABORTED\n"); } return; } if (!(result & (CS_PENDING|CS_IN_PROGRESS))) { pmsg("\nCALIBRATION COMPLETED\n"); break; } #ifndef HAVE_MINGW fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(STDIN_FILENO, &rfds); tv.tv_sec = 10; tv.tv_usec = 0; aborted = select(STDIN_FILENO+1, &rfds, NULL, NULL, &tv) == 1; if (aborted) { while (fgetc(stdin) != '\n') ; } #else aborted = false; for (int i = 0; i < 100 && !aborted; i++) { while (kbhit() && !aborted) aborted = getch() == '\r'; if (!aborted) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000000; nanosleep(&ts, NULL); } } #endif if (aborted) { pmsg("\n\nUser input detected; aborting calibration..."); if (!modbus_write_int_to_ups(ups, REG_CALIBRATION_CMD, CC_ABORT_CALIBRATION)) { pmsg("FAILED\n"); } else { pmsg("ABORTED\n"); } return; } // Output the battery level if (modbus_read_int_from_ups(ups, REG_STATE_OF_CHARGE_PCT, &result)) { if (ilastbl == result) pmsg("."); else pmsg("\nBattery level: %d%%", result); ilastbl = result; } else pmsg("."); } pmsg("Calibration result: "); if (result & CS_PASSED) pmsg("PASSED"); else if (result & CS_FAILED) pmsg("FAILED"); else if (result & CS_REFUSED) pmsg("REFUSED"); else if (result & CS_ABORTED) pmsg("ABORTED"); else pmsg("0x%llx", result); if (result & CS_SRC_PROTOCOL) pmsg(" (PROTOCOL)"); else if (result & CS_SRC_LOCAL_UI) pmsg(" (LOCAL UI)"); else if (result & CS_SRC_INTERNAL) pmsg(" (INTERNAL)"); if (result & CS_INVALID_STATE) pmsg(" (INVALID STATE)"); else if (result & CS_INTERNAL_FAULT) pmsg(" (INTERNAL FAULT)"); else if (result & CS_STATE_OF_CHARGE) pmsg(" (STATE OF CHARGE)"); else if (result & CS_LOAD_CHANGE) pmsg(" (LOAD CHANGE)"); else if (result & CS_AC_INPUT_BAD) pmsg(" (AC INPUT BAD)"); else if (result & CS_LOAD_TOO_LOW) pmsg(" (LOAD TOO LOW)"); else if (result & CS_OVER_CHARGE) pmsg(" (OVER CHARGE)"); pmsg("\n"); } static struct tm modbus_uint_to_date(uint64_t uint) { // uint is in days since 1/1/2000 time_t date = ModbusRegTotime_t(uint); struct tm ret; gmtime_r(&date, &ret); return ret; } static void modbus_get_manf_date(void) { uint64_t result; if (!modbus_read_int_from_ups(ups, REG_MANUFACTURE_DATE, &result)) { pmsg("\nI don't know how to access the manufacturing date on your UPS\n" "or your UPS does not support the manufacturing date feature.\n"); return; } struct tm date = modbus_uint_to_date(result); char str[11]; strftime(str, sizeof(str), "%m/%d/%Y", &date); pmsg("Manufacturing date: %s\n", str); } static void modbus_test_alarm(void) { uint64_t result; if (!modbus_read_int_from_ups(ups, REG_USER_INTERFACE_CMD, &result)) { pmsg("\nI don't know how to test the alarm on your UPS.\n"); return; } // Write to UPS pmsg("Testing alarm..."); modbus_write_int_to_ups(ups, REG_USER_INTERFACE_CMD, UIC_SHORT_TEST); // Wait for complete while (modbus_read_int_from_ups(ups, REG_USER_INTERFACE_CMD, &result) && (result & UIS_TEST_IN_PROGRESS)) { sleep(1); } pmsg("COMPLETE\n"); } static uint64_t modbus_get_battery_date(void) { uint64_t result; if (!modbus_read_int_from_ups(ups, REG_BATTERY_DATE_SETTING, &result)) { pmsg("\nI don't know how to access the battery date on your UPS\n" "or your UPS does not support the battery date feature.\n"); return 0; } struct tm date = modbus_uint_to_date(result); char str[11]; strftime(str, sizeof(str), "%m/%d/%Y", &date); pmsg("Current battery date: %s\n", str); return result; } static void modbus_set_battery_date(void) { char *cmd; int day, month, year, max; uint64_t result, temp; if (!(result = modbus_get_battery_date())) return; cmd = get_cmd("Enter new battery date (MM/DD/YYYY), blank to quit: "); if (!isdigit(cmd[0]) || !isdigit(cmd[1]) || cmd[2] != '/' || !isdigit(cmd[3]) || !isdigit(cmd[4]) || cmd[5] != '/' || !isdigit(cmd[6]) || !isdigit(cmd[7]) || !isdigit(cmd[8]) || !isdigit(cmd[9]) || cmd[10] != '\0' || ((month = strtoul(cmd, NULL, 10)) > 12) || (month < 1) || ((day = strtoul(cmd + 3, NULL, 10)) > 31) || (day < 1) || ((year = strtoul(cmd + 6, NULL, 10)) < 1980)) { pmsg("Invalid format.\n"); return; } struct tm new_date_tm = {0}; new_date_tm.tm_mon = month - 1; new_date_tm.tm_year = year - 1900; new_date_tm.tm_mday = day; new_date_tm.tm_isdst = -1; time_t new_date = mktime(&new_date_tm); if (new_date < MODBUS_BASE_TIMESTAMP) { pmsg("Invalid date; Must be 1/1/2000 or later\n"); return; } result = time_tToModbusReg(new_date); pmsg("Writing new date..."); if (!modbus_write_int_to_ups(ups, REG_BATTERY_DATE_SETTING, result)) { pmsg("FAILED\n"); return; } pmsg("SUCCESS\n"); pmsg("Waiting for change to take effect..."); for (max = 0; max < 10; max++) { if (!modbus_read_int_from_ups(ups, REG_BATTERY_DATE_SETTING, &temp)) { pmsg("ERROR\n"); return; } if (temp == result) break; sleep(1); } if (max == 10) pmsg("TIMEOUT\n"); else pmsg("SUCCESS\n"); modbus_get_battery_date(); } #endif apcupsd-3.14.14/src/apcupsd.c000066400000000000000000000227261274230402600157260ustar00rootroot00000000000000/* * apcupsd.c * * APC UPS monitoring daemon. */ /* * Copyright (C) 1999-2005 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" UPSINFO *core_ups = NULL; static void daemon_start(void); int pidcreated = 0; extern int kill_on_powerfail; extern FILE *trace_fd; extern char *pidfile; /* * The terminate function and trapping signals allows apcupsd * to exit and cleanly close logfiles, and reset the tty back * to its original settings. You may want to add this * to all configurations. Of course, the file descriptors * must be global for this to work, I also set them to * NULL initially to allow terminate to determine whether * it should close them. */ void apcupsd_terminate(int sig) { UPSINFO *ups = core_ups; if (sig != 0) log_event(ups, LOG_WARNING, "apcupsd exiting, signal %u", sig); clean_threads(); clear_files(); if (ups->driver) device_close(ups); delete_lockfile(ups); if (pidcreated) unlink(pidfile); log_event(ups, LOG_NOTICE, "apcupsd shutdown succeeded"); destroy_ups(ups); closelog(); _exit(0); } void apcupsd_error_cleanup(UPSINFO *ups) { if (ups->driver) device_close(ups); delete_lockfile(ups); if (pidcreated) unlink(pidfile); clean_threads(); log_event(ups, LOG_ERR, "apcupsd error shutdown completed"); destroy_ups(ups); closelog(); exit(1); } /* * Subroutine error_out prints FATAL ERROR with file, * line number, and the error message then cleans up * and exits. It is normally called from the Error_abort * define, which inserts the file and line number. */ void apcupsd_error_out(const char *file, int line, const char *fmt, va_list arg_ptr) { char buf[256]; int i; asnprintf(buf, sizeof(buf), "apcupsd FATAL ERROR in %s at line %d\n", file, line); i = strlen(buf); avsnprintf((char *)&buf[i], sizeof(buf) - i, (char *)fmt, arg_ptr); fprintf(stderr, "%s", buf); log_event(core_ups, LOG_ERR, "%s", buf); apcupsd_error_cleanup(core_ups); /* finish the work */ } /* * ApcupsdMain is called from win32/winmain.cpp * we need to eliminate "main" as an entry point, * otherwise, it interferes with the Windows * startup. */ #ifdef HAVE_MINGW # define main ApcupsdMain #endif /* Main program */ int main(int argc, char *argv[]) { UPSINFO *ups; int tmp_fd, i; /* Set specific error_* handlers. */ error_out = apcupsd_error_out; /* * Default config file. If we set a config file in startup switches, it * will be re-filled by parse_options() */ cfgfile = APCCONF; /* * Create fake stdout in order to circumvent problems * which occur if apcupsd doesn't have a valid stdout * Fix by Alexander Schremmer */ tmp_fd = open("/dev/null", O_RDONLY); if (tmp_fd > 2) { close(tmp_fd); } else if (tmp_fd >= 0) { for (i = 1; tmp_fd + i <= 2; i++) dup2(tmp_fd, tmp_fd + i); } /* * If there's not one in libc, then we have to use our own version * which requires initialization. */ strlcpy(argvalue, argv[0], sizeof(argvalue)); ups = new_ups(); /* get new ups */ if (!ups) Error_abort("%s: init_ipc failed.\n", argv[0]); init_ups_struct(ups); core_ups = ups; /* this is our core ups structure */ /* parse_options is self messaging on errors, so we need only to exit() */ if (parse_options(argc, argv)) exit(1); Dmsg(10, "Options parsed.\n"); if (show_version) { printf("apcupsd " APCUPSD_RELEASE " (" ADATE ") " APCUPSD_HOST "\n"); exit(0); } /* * We open the log file early to be able to write to it * it at any time. However, please note that if the user * specifies a different facility in the config file * the log will be closed and reopened (see match_facility()) * in apcconfig.c. Any changes here should also be made * to the code in match_facility(). */ openlog("apcupsd", LOG_CONS | LOG_PID, ups->sysfac); #ifndef DEBUG if ((getuid() != 0) && (geteuid() != 0)) Error_abort("Needs super user privileges to run.\n"); #endif check_for_config(ups, cfgfile); Dmsg(10, "Config file %s processed.\n", cfgfile); /* * Disallow --kill-on-powerfail in conjunction with simple signaling * UPSes. Such UPSes have no shutdown grace period so using --kill-on- * powerfail would guarantee an unclean shutdown. */ if (kill_on_powerfail && ups->mode.type == DUMB_UPS) { kill_on_powerfail = 0; log_event(ups, LOG_WARNING, "Ignoring --kill-on-powerfail since it is unsafe " "on Simple Signaling UPSes"); } /* Attach the correct driver. */ attach_driver(ups); if (ups->driver == NULL) Error_abort("Apcupsd cannot continue without a valid driver.\n"); ups->start_time = time(NULL); if (!hibernate_ups && !shutdown_ups && go_background) { daemon_start(); /* Reopen log file, closed during becoming daemon */ openlog("apcupsd", LOG_CONS | LOG_PID, ups->sysfac); } init_signals(apcupsd_terminate); /* Create temp events file if we are not doing a hibernate or shutdown */ if (!hibernate_ups && !shutdown_ups && ups->eventfile[0] != 0) { ups->event_fd = open(ups->eventfile, O_RDWR | O_CREAT | O_APPEND | O_CLOEXEC, 0644); if (ups->event_fd < 0) { log_event(ups, LOG_WARNING, "Could not open events file %s: %s\n", ups->eventfile, strerror(errno)); } } if (create_lockfile(ups) == LCKERROR) { Error_abort("Unable to create UPS lock file.\n" " If apcupsd or apctest is already running,\n" " please stop it and run this program again.\n"); } make_pid_file(); pidcreated = 1; if (hibernate_ups || shutdown_ups) { // If we're hibernating or shutting down the UPS, setup is a one-shot. // If it fails, we're toast; no retries if (!setup_device(ups)) Error_abort("Unable to open UPS device for hibernate or shutdown"); if (hibernate_ups) initiate_hibernate(ups); else initiate_shutdown(ups); apcupsd_terminate(0); } /* * From now ... we must _only_ start up threads! * No more unchecked writes to UPSINFO because the threads must rely * on write locks and up to date data in the shared structure. */ /* Network status information server */ if (ups->netstats) { start_thread(ups, do_server, "apcnis", argv[0]); Dmsg(10, "NIS thread started.\n"); } log_event(ups, LOG_NOTICE, "apcupsd " APCUPSD_RELEASE " (" ADATE ") " APCUPSD_HOST " startup succeeded"); /* main processing loop */ do_device(ups); apcupsd_terminate(0); return 0; /* to keep compiler happy */ } extern int debug_level; /* * Initialize a daemon process completely detaching us from * any terminal processes. */ static void daemon_start(void) { #if !defined(HAVE_MINGW) int i, fd; pid_t cpid; mode_t oldmask; #ifndef HAVE_QNX_OS if ((cpid = fork()) < 0) Error_abort("Cannot fork to become daemon\n"); else if (cpid > 0) exit(0); /* parent exits */ /* Child continues */ setsid(); /* become session leader */ #else if (procmgr_daemon(EXIT_SUCCESS, PROCMGR_DAEMON_NOCHDIR | PROCMGR_DAEMON_NOCLOSE | PROCMGR_DAEMON_NODEVNULL | PROCMGR_DAEMON_KEEPUMASK) == -1) { Error_abort("Couldn't become daemon\n"); } #endif /* HAVE_QNX_OS */ /* Call closelog() to close syslog file descriptor */ closelog(); /* * In the PRODUCTION system, we close ALL file descriptors unless * debugging is on then we leave stdin, stdout, and stderr open. * We also take care to leave the trace fd open if tracing is on. * Furthermore, if tracing we redirect stdout and stderr to the * trace log. */ for (i=0; i 2) { close(fd); } else if (fd >= 0) { for (i = 1; fd + i <= 2; i++) dup2(fd, fd + i); } #endif /* HAVE_MINGW */ } apcupsd-3.14.14/src/cgi/000077500000000000000000000000001274230402600146545ustar00rootroot00000000000000apcupsd-3.14.14/src/cgi/Makefile000066400000000000000000000036711274230402600163230ustar00rootroot00000000000000topdir:=../.. include $(topdir)/autoconf/targets.mak common_srcs := upsfetch.c cgilib.c multimon_srcs := multimon.c upsstats_srcs := upsstats.c upsfstats_srcs := upsfstats.c upsimage_srcs := upsimage.c common_obj := $(call SRC2OBJ,$(common_srcs)) multimon_obj := $(call SRC2OBJ,$(multimon_srcs)) upsstats_obj := $(call SRC2OBJ,$(upsstats_srcs)) upsfstats_obj := $(call SRC2OBJ,$(upsfstats_srcs)) upsimage_obj := $(call SRC2OBJ,$(upsimage_srcs)) SRCS = $(common_srcs) $(multimon_srcs) $(upsstats_srcs) \ $(upsfstats_srcs) $(upsimage_srcs) # libgd needs -DNONDLL on Windows, otherwise it defaults to DLL upsimage.cgi: CPPFLAGS += -DNONDLL all-targets: multimon.cgi upsstats.cgi upsfstats.cgi upsimage.cgi multimon.cgi: $(common_obj) $(multimon_obj) $(APCLIBS) $(LINK) upsstats.cgi: $(common_obj) $(upsstats_obj) $(APCLIBS) $(LINK) upsfstats.cgi: $(common_obj) $(upsfstats_obj) $(APCLIBS) $(LINK) upsimage.cgi: $(common_obj) $(upsimage_obj) $(APCLIBS) $(LINK) $(LIBGD) all-install: install-cgi all-uninstall: uninstall-cgi install-cgi: $(call MKDIR,$(cgibin)) $(call INSTPROG,755,multimon.cgi,$(cgibin)) $(call INSTPROG,755,upsstats.cgi,$(cgibin)) $(call INSTPROG,755,upsfstats.cgi,$(cgibin)) $(call INSTPROG,755,upsimage.cgi,$(cgibin)) $(call MKDIR,$(sysconfdir)) $(call INSTNEW,644,apcupsd.css,$(sysconfdir)) $(call INSTNEW,644,$(topdir)/platforms/etc/hosts.conf,$(sysconfdir)) $(call INSTNEW,644,$(topdir)/platforms/etc/multimon.conf,$(sysconfdir)) uninstall-cgi: $(call UNINST,$(cgibin)/multimon.cgi) $(call UNINST,$(cgibin)/upsstats.cgi) $(call UNINST,$(cgibin)/upsfstats.cgi) $(call UNINST,$(cgibin)/upsimage.cgi) $(call UNINST,$(sysconfdir)/apcupsd.css) $(call UNINST,$(sysconfdir)/apcupsd.css.new) $(call UNINST,$(sysconfdir)/hosts.conf) $(call UNINST,$(sysconfdir)/hosts.conf.new) $(call UNINST,$(sysconfdir)/multimon.conf) $(call UNINST,$(sysconfdir)/multimon.conf.new) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/cgi/README000066400000000000000000000057141274230402600155430ustar00rootroot00000000000000* GPLed - see COPYING for details. * * These cgi scripts were based on v0.2 of those by * Russell Kroll * * This version of the scripts by * Jonathan Benson * Any feedback, comments, etc should be directed at me and NOT Russell * * This program has been extensively adapted for Apcupsd by * Kern Sibbald, 2000 * Any comments should be directed to * Many thanks to Jonathan for his initial port to apcupsd, it * has now become an official part of apcupsd. * I have modified the scripts by Russell Kroll that work with his upstools suite to suit the apcupsd available at: http://www.dyer.vanderbilt.edu/server/apcupsd/ I've also added various features (see below). - upsstats.cgi: Generates the HTML for the main status page. - upsimage.cgi: Called by IMG SRC tags in status pages. Features: (original) * Text output of various stats & 3 graphs * Battery Capacity * Utility Voltage * UPS Load * Handles 110V UPS only (added) * 2 more graphs * Battery Voltage * Output Voltage * Ability to select each graph * Ability to change temperature reading (deg C/F/K) * Should now handle 110/230V UPS (110V untested) * Automatic refresh every 30 secs * Random number added to end of IMG cgi call to ensure images are NOT cached OK, assuming you have configured and installed the program already, here is how you actually use it to keep an eye on things. ============ = upsstats = ============ upsstats is a CGI program, and as such, you must invoke it through your web server with a browser. Assuming you have it installed into your /cgi-bin directory, accessing the following URL will allow you to see what's going on in your UPS.. http://your.machine.dom/cgi-bin/upsstats.cgi Making a bookmark to this script or linking to it from another page is an easy way to return to it in the future. To change any of the graphs just pick your option from the pull down menu. The same goes for the temperature display. ============ = upsimage = ============ upsimage is also a CGI program like upsstats, but it is intended to be called by IMG SRC requests inside the page that upsstats generates. You can source the images from it directly if you like, but they may look rather odd outside the table scheme of the normal upsstats page. Most users will probably never need to touch upsimage directly. =============== = Other Notes = =============== upsimage uses the gd library from http://www.boutell.com/ for quick generation of GIF images. If you have something that needs speedy graphical representations of data that's being written in C, you should check it out. apcupsd-3.14.14/src/cgi/apcupsd.css000066400000000000000000000011371274230402600170270ustar00rootroot00000000000000body { color: black; background: white; } div.Center { text-align: center; } img { border-style: none; } pre { text-align: left; } strong { color: red; } table.Outer { color: black; background: #60a0a0; empty-cells: show; border: solid #60a0a0 } th.Outer { color: black; background: #60b0b0 } .Title { font-size: 18pt; } .SubTitle { font-size: 12pt; } .Empty { color: black; background: aqua; } .Fault { color: black; background: red; } .Label { color: black; background: aqua; } .Normal { color: black; background: lime; } .Warning { color: black; background: yellow; } apcupsd-3.14.14/src/cgi/cgiconfig.h.in000066400000000000000000000053371274230402600173720ustar00rootroot00000000000000/* * cgiconfig.h.in -- header file for apcupsd cgi interface * * Copyright (C) 1999-2002 Riccardo Facchetti * * apcupsd.c -- Simple Daemon to catch power failure signals from a * BackUPS, BackUPS Pro, or SmartUPS (from APCC). * -- Now SmartMode support for SmartUPS and BackUPS Pro. * * Copyright (C) 1996-99 Andre M. Hedrick * All rights reserved. */ /* * GNU GENERAL PUBLIC LICENSE * Version 2, June 1991 * * Copyright (C) 1989, 1991 Free Software Foundation, Inc. * 675 Mass Ave, Cambridge, MA 02139, USA * Everyone is permitted to copy and distribute verbatim copies * of this license document, but changing it is not allowed. * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * IN NO EVENT SHALL ANY AND ALL PERSONS INVOLVED IN THE DEVELOPMENT OF THIS * PACKAGE, NOW REFERRED TO AS "APCUPSD-Team" BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF ANY OR ALL * OF THE "APCUPSD-Team" HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE "APCUPSD-Team" SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE "APCUPSD-Team" HAS NO OBLIGATION TO PROVIDE * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * THE "APCUPSD-Team" HAS ABSOLUTELY NO CONNECTION WITH THE COMPANY * AMERICAN POWER CONVERSION, "APCC". THE "APCUPSD-Team" DID NOT AND * HAS NOT SIGNED ANY NON-DISCLOSURE AGREEMENTS WITH "APCC". ANY AND ALL * OF THE LOOK-A-LIKE ( UPSlink(tm) Language ) WAS DERIVED FROM THE * SOURCES LISTED BELOW. * */ #include "apc.h" extern "C" { #if defined(SYS_IMGFMT_PNG) || defined(SYS_IMGFMT_GIF) #include <@GDHEAD@gd.h> #include <@GDHEAD@gdfontl.h> #else #include "gd.h" #include "gdfontl.h" #endif } apcupsd-3.14.14/src/cgi/cgilib.c000066400000000000000000000157461274230402600162660ustar00rootroot00000000000000/* 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "cgilib.h" #include "cgiconfig.h" /* * Attempts to extract the arguments from QUERY_STRING * it does a "callback" to the parsearg() routine for * each argument found. * * Returns 0 on failure * 1 on success */ int extractcgiargs() { char *query, *ptr, *eq, *varname, *value, *amp; query = getenv ("QUERY_STRING"); if (query == NULL) return 0; /* not run as a cgi script! */ /* varname=value&varname=value&varname=value ... */ ptr = query; while (ptr) { varname = ptr; eq = strchr (varname, '='); if (!eq) { return 0; /* Malformed string argument */ } *eq = '\0'; value = eq + 1; amp = strchr (value, '&'); if (amp) { ptr = amp + 1; *amp = '\0'; } else ptr = NULL; parsearg (varname, value); } return 1; } /* * Checks if the host to be monitored is in xxx/hosts.conf * Returns: * 0 on failure * 1 on success (default if not hosts.conf file) */ int checkhost(const char *check) { FILE *hostlist; char fn[256], buf[500], addr[256]; asnprintf(fn, sizeof(fn), "%s/hosts.conf", SYSCONFDIR); hostlist = fopen(fn, "r"); if (hostlist == NULL) { return 1; /* default to allow */ } while (fgets(buf, (size_t) sizeof(buf), hostlist)) { if (strncmp("MONITOR", buf, 7) == 0) { sscanf (buf, "%*s %s", addr); if (strncmp(addr, check, strlen(check)) == 0) { (void) fclose (hostlist); return 1; /* allowed */ } } } (void) fclose (hostlist); return 0; /* denied */ } /* * Output a string taking care to assure that any html meta characters * are output properly. * * Note: XHTML added the meta character ', but for backwards compatibility * with HTML 4.0, output it as ' */ void html_puts(const char *str) { const unsigned char *p = (const unsigned char *)str; while (*p != '\0') { if (*p >= 0x7f) { printf ("&#%d;", (int) *p); } else { switch (*p) { case '\"': (void) fputs(""", stdout); break; case '&': (void) fputs("&", stdout); break; case '\'': (void) fputs("'", stdout); break; case '<': (void) fputs("<", stdout); break; case '>': (void) fputs(">", stdout); break; default: (void) putchar(*p); break; } } p++; } } /* * Print the standard http header, html header which is common to all * html pages. */ void html_begin(const char *title, int refresh) { int http_version; char *server_protocol; FILE *hostlist; char fn[256], buf[500]; server_protocol = getenv("SERVER_PROTOCOL"); if (server_protocol == NULL) { http_version = 10; } else if (strcmp(server_protocol, "HTTP/1.0") == 0) { http_version = 10; } else if (strcmp(server_protocol, "HTTP/1.1") == 0) { http_version = 11; } else { http_version = 11; } (void) puts ("Content-Type: text/html; charset=utf-8"); (void) puts ("Content-Language: en"); if (http_version > 10) { (void) puts ("Cache-Control: no-cache"); } else { (void) puts ("Pragma: no-cache"); } (void) puts (""); (void) puts(""); (void) puts(""); (void) puts(""); (void) puts (""); (void) fputs ("", stdout); html_puts((char *)title); (void) puts (""); if (http_version > 10) { (void) puts (" "); } /* Always put the Pragma: no-cache tag in the document. Even if the request * was received from a HTTP 1.1 proxy, the requesting client may have * made the request via HTTP 1.0. */ (void) puts (" "); /* * Add a generator tag so that when bugs are logged, we know what version * of the code we are dealing with. */ (void) fputs (" "); if (refresh != 0) { printf (" \n", refresh); } asnprintf(fn, sizeof(fn), "%s/apcupsd.css", SYSCONFDIR); hostlist = fopen(fn, "r"); if (hostlist != NULL) { (void) puts (" "); } (void) puts (""); (void) puts (""); } /* * Print the standard footer which appears on every html page and close out * the html document. */ void html_finish(void) { #ifdef VALIDATE_HTML (void) puts ("
"); (void) puts (""); (void) puts ("\"Valid"); (void) puts (""); (void) puts ("\"Valid"); (void) puts ("
"); #endif (void) puts (""); } apcupsd-3.14.14/src/cgi/cgilib.h000066400000000000000000000027321274230402600162620ustar00rootroot00000000000000/* 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* other programs that link to this should provide parsearg() ... */ void parsearg (const char *var, const char *value); /* actually extract the values from QUERY_STRING */ int extractcgiargs(void); /* see if a host is allowed per the hosts.conf */ int checkhost(const char *check); /* * Output a string taking care to assure that any html meta characters * are output properly. */ void html_puts(const char *s); /* * Print the standard http header, html header which is common to all * html pages. */ void html_begin(const char *title, int refresh); /* * Print the standard footer which appears on every html page and close out * the html document. */ void html_finish(void); apcupsd-3.14.14/src/cgi/multimon.c000066400000000000000000000424321274230402600166710ustar00rootroot00000000000000/* multimon - CGI program to monitor several UPSes from one page 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include "upsfetch.h" #include "cgiconfig.h" #include "cgilib.h" #ifndef MAXPATHLEN #define MAXPATHLEN 256 #endif #ifndef DEFAULT_REFRESH #define DEFAULT_REFRESH 30 #endif static void do_model (const char *monhost, const char *suffix); static void do_system (const char *monhost, const char *suffix); static void do_fulldata (const char *monhost, const char *suffix); static void do_status (const char *monhost, const char *suffix); static void do_upstemp (const char *monhost, const char *suffix); static void do_upstempc (const char *monhost, const char *suffix); static void do_upstempf (const char *monhost, const char *suffix); static void do_humidity (const char *monhost, const char *suffix); static void do_ambtemp (const char *monhost, const char *suffix); static void do_ambtempc (const char *monhost, const char *suffix); static void do_ambtempf (const char *monhost, const char *suffix); static void do_utility (const char *monhost, const char *suffix); static const struct { const char *name; void (*func)(const char *monhost, const char *suffix); } fields[] = { { "MODEL", do_model }, { "SYSTEM", do_system }, { "STATUS", do_status }, { "DATA", do_fulldata }, { "UPSTEMP", do_upstemp }, { "UPSTEMPC", do_upstempc }, { "UPSTEMPF", do_upstempf }, { "HUMIDITY", do_humidity }, { "AMBTEMP", do_ambtemp }, { "AMBTEMPC", do_ambtempc }, { "AMBTEMPF", do_ambtempf }, { "UTILITY", do_utility }, { NULL, (void(*)(const char *, const char *))(NULL) } }; static const struct { const char *name; const char *desc; const int severity; } stattab[] = { { "OFF", "OFF", 1 }, { "OL", "ONLINE", 0 }, { "OB", "ON BATTERY", 2 }, { "LB", "LOW BATTERY", 2 }, { "RB", "REPLACE BATTERY", 2 }, { "NB", "NO BATTERY", 2 }, { "OVER", "OVERLOAD", 2 }, { "TRIM", "VOLTAGE TRIM", 1 }, { "BOOST", "VOLTAGE BOOST", 1 }, { "CAL", "CALIBRATION", 1 }, { "CL", "COMM LOST", 2 }, { "SD", "SHUTTING DOWN", 2 }, { "SLAVE", "SLAVE", 0 }, { NULL, NULL, 0 } }; struct ftype_t; struct ftype_t { const char *var; const char *name; const char *suffix; ftype_t *next; }; static ftype_t *firstfield = NULL; static int numfields = 0; static int use_celsius; static char *desc; static int refresh = DEFAULT_REFRESH; void parsearg(const char *var, const char *value) { if (strcmp(var, "refresh") == 0) { refresh = atoi(value); if (refresh < 0) { refresh = DEFAULT_REFRESH; } } } static void report_error(const char *str) { printf("

%s

\n", str); html_finish(); exit(EXIT_FAILURE); } /* handler for "MODEL" */ static void do_model (const char *monhost, const char *suffix) { char model[256]; if (getupsvar(monhost, "model", model, sizeof(model)) < 0) { (void) puts ("-"); } else { fputs ("", stdout); html_puts(model); (void) puts(""); } } /* handler for "SYSTEM" */ static void do_system(const char *monhost, const char *suffix) { /* provide system name and link to upsstats */ printf (""); printf ("%s\n", monhost, use_celsius ? 'C' : 'F', desc); } /* handler for "STATUS" */ static void do_status(const char *monhost, const char *suffix) { char status[64], *stat, stattxt[128], temp[128]; const char *class_type; int i, severity; long ups_status; if (getupsvar (monhost, "status", status, sizeof(status)) <= 0) { printf ("Unavailable\n"); return; } stattxt[0] = '\0'; severity = 0; ups_status = strtol(status, 0, 16); status[0] = '\0'; if (ups_status & UPS_calibration) strcat(status, "CAL "); if (ups_status & UPS_trim) strcat(status, "TRIM "); if (ups_status & UPS_boost) strcat(status, "BOOST "); if (ups_status & UPS_online) strcat(status, "OL "); if (ups_status & UPS_onbatt) strcat(status, "OB "); if (ups_status & UPS_overload) strcat(status, "OVER "); if (ups_status & UPS_battlow) strcat(status, "LB "); if (ups_status & UPS_replacebatt) strcat(status, "RB "); if (!(ups_status & UPS_battpresent)) strcat(status, "NB "); if (ups_status & UPS_commlost) strcat(status, "CL "); if (ups_status & UPS_shutdown) strcat(status, "SD "); if (ups_status & UPS_slave) strcat(status, "SLAVE "); stat = strtok (status, " "); while (stat != NULL) { for (i = 0; stattab[i].name != NULL; i++) { if (strcmp(stattab[i].name, stat) == 0) { snprintf (temp, sizeof(temp), "%s %s
", stattxt, stattab[i].desc); snprintf (stattxt, sizeof(stattxt), "%s", temp); if (stattab[i].severity > severity) severity = stattab[i].severity; } } stat = strtok (NULL, " "); } switch (severity) { case 0: class_type = "Normal"; break; case 1: class_type = "Warning"; break; case 2: default: class_type = "Fault"; break; } printf ("%s\n", class_type, stattxt); } /* handler for "DATA" */ static void do_fulldata (const char *monhost, const char *suffix) { printf (""); printf ("%s\n", monhost, suffix); } /* handler for "UPSTEMPC" */ static void do_upstempc(const char *monhost, const char *suffix) { char upstemp[64]; if (getupsvar(monhost, "upstemp", upstemp, sizeof(upstemp)) > 0) { printf ("%s° C\n", upstemp); } else { (void) puts ("-"); } } /* handler for "UPSTEMPF" */ static void do_upstempf(const char *monhost, const char *suffix) { char upstemp[64]; float tempf; if (getupsvar(monhost, "upstemp", upstemp, sizeof(upstemp)) > 0) { tempf = (strtod (upstemp, 0) * 1.8) + 32; printf ("%.1f° F\n", tempf); } else { (void) puts ("-"); } } /* handler for "UPSTEMP" */ static void do_upstemp(const char *monhost, const char *suffix) { if (use_celsius) { do_upstempc(monhost, suffix); } else { do_upstempf(monhost, suffix); } } /* handler for "HUMIDITY" */ static void do_humidity(const char *monhost, const char *suffix) { char humidity[64]; float ambhum; if (getupsvar (monhost, "humidity", humidity, sizeof(humidity)) > 0) { ambhum = strtod (humidity, 0); printf ("%.1f %%\n", ambhum); } else { (void) puts ("-"); } } /* handler for "AMBTEMPC" */ static void do_ambtempc(const char *monhost, const char *suffix) { char ambtemp[64]; if (getupsvar (monhost, "ambtemp", ambtemp, sizeof(ambtemp)) > 0) { printf ("%s° C\n", ambtemp); } else { (void) puts ("-"); } } /* handler for "AMBTEMPF" */ static void do_ambtempf (const char *monhost, const char *suffix) { char ambtemp[64]; float tempf; if (getupsvar (monhost, "ambtemp", ambtemp, sizeof(ambtemp)) > 0) { tempf = (strtod (ambtemp, 0) * 1.8) + 32; printf ("%.1f° F\n", tempf); } else { (void) puts ("-"); } } /* handler for "AMBTEMP" */ static void do_ambtemp(const char *monhost, const char *suffix) { if (use_celsius) { do_ambtempc(monhost, suffix); } else { do_ambtempf(monhost, suffix); } } /* handler for "UTILITY" */ static void do_utility(const char *monhost, const char *suffix) { char utility[64], lowxfer[64], highxfer[64]; int lowx, highx, util; if (getupsvar (monhost, "utility", utility, sizeof(utility)) > 0) { /* try to get low and high transfer points for color codes */ lowx = highx = 0; if (getupsvar (monhost, "lowxfer", lowxfer, sizeof(lowxfer)) > 0) lowx = atoi(lowxfer); if (getupsvar (monhost, "highxfer", highxfer, sizeof(highxfer)) > 0) highx = atoi(highxfer); printf (" highx)) printf ("Fault"); else printf ("Normal"); } else printf ("Normal"); printf ("\">%s VAC\n", utility); } else { (void) puts ("-"); } } /* Get and print information for requested host */ static void getinfo(char *monhost) { ftype_t *tmp; char tmpbuf[256]; int i, found; (void) puts (""); /* grab a dummy variable to see if the host is up */ if (getupsvar(monhost, "date", tmpbuf, sizeof(tmpbuf)) <= 0) { printf ("%s\n", desc); printf ("Not available: %s\n", numfields - 1, errmsg); return; } /* process each field one by one */ for (tmp = firstfield; tmp != NULL; tmp = tmp->next) { found = 0; /* search for a recognized special field name */ for (i = 0; fields[i].name != NULL; i++) { if (strcmp(fields[i].name, tmp->var) == 0) { fields[i].func(monhost, tmp->suffix); found = 1; } } if (found) continue; if (getupsvar(monhost, tmp->var, tmpbuf, sizeof(tmpbuf)) > 0) { if (tmp->suffix == NULL) { printf ("%s\n", tmpbuf); } else { printf ("%s %s\n", tmpbuf, tmp->suffix); } } else { (void) puts ("-"); } } (void) puts (""); } /* add a field to the linked list */ static void addfield(const char *var, const char *name, const char *suffix) { ftype_t *tmp, *last; tmp = last = firstfield; while (tmp != NULL) { last = tmp; tmp = tmp->next; } tmp = (ftype_t *)malloc (sizeof (ftype_t)); tmp->var = var; tmp->name = name; tmp->suffix = suffix; tmp->next = NULL; if (last == NULL) { firstfield = tmp; } else { last->next = tmp; } numfields++; } /* parse a FIELD line from the buf and call addfield */ static void parsefield(char *buf) { char *ptr, *var, *name = NULL, *suffix = NULL, *tmp; int i = 0, in_string = 0; int len = strlen(buf) + 1; tmp = (char *)malloc(len); /* "" "" */ ptr = strtok(buf, " "); if (ptr == NULL) { report_error("multimon.conf: " "No separating space in FIELD line."); } var = strdup(ptr); ptr = buf + strlen(var) + 1; while (*ptr) { if (*ptr == '"') { in_string = !in_string; if (!in_string) { tmp[i] = '\0'; i = 0; if (suffix) { snprintf(tmp, len, "multimon.conf: " "More than two strings " "in field %s.", var); report_error(tmp); } else if (name) { suffix = strdup(tmp); } else { name = strdup(tmp); } } } else if (in_string) { if (*ptr == '\\') { ++ptr; if (*ptr == '\0') { snprintf(tmp, len, "multimon.conf: " "Backslash at end of line " "in field %s.", var); report_error(tmp); } } tmp[i++] = *ptr; } ++ptr; } if (in_string) { snprintf(tmp, len, "multimon.conf: " "Unbalanced quotes in field %s!", var); report_error(tmp); } free(tmp); addfield(var, name, suffix); } static void readconf(void) { FILE *conf; char buf[512], fn[MAXPATHLEN]; snprintf (fn, sizeof(fn), "%s/multimon.conf", SYSCONFDIR); conf = fopen (fn, "r"); /* the config file is not required */ if (conf == NULL) return; while (fgets (buf, sizeof(buf), conf)) { buf[strlen(buf) - 1] = '\0'; if (strncmp (buf, "FIELD", 5) == 0) { parsefield (&buf[6]); } else if (strncmp (buf, "TEMPC", 5) == 0) { use_celsius = 1; } else if (strncmp (buf, "TEMPF", 5) == 0) { use_celsius = 0; } } fclose (conf); } /* create default field configuration */ static void defaultfields(void) { addfield ("SYSTEM", "System", ""); addfield ("MODEL", "Model", ""); addfield ("STATUS", "Status", ""); addfield ("battpct", "Batt Chg", "%"); addfield ("UTILITY", "Utility", "VAC"); addfield ("loadpct", "UPS Load", "%"); addfield ("UPSTEMP", "UPS Temperature", ""); addfield ("DATA", "Data", "All data"); } int main(int argc, char **argv) { FILE *conf; time_t tod; char buf[256], fn[MAXPATHLEN], addr[256], timestr[256]; int restofs; ftype_t *tmp; /* set default according to compile time, but config may override */ #ifdef USE_CELSIUS use_celsius = 1; #else use_celsius = 0; #endif readconf(); if (firstfield == NULL) /* nothing from config file? */ defaultfields(); (void) extractcgiargs(); html_begin("Multimon: UPS Status Page", refresh); printf ("\n"); time (&tod); strftime (timestr, sizeof(timestr), "%a %b %d %X %Z %Y", localtime(&tod)); printf ("\n", timestr); /* print column names */ printf ("\n"); for (tmp = firstfield; tmp != NULL; tmp = tmp->next) printf ("\n", tmp->name); (void) puts (""); /* ups status */ snprintf (fn, sizeof(fn), "%s/hosts.conf", SYSCONFDIR); conf = fopen (fn, "r"); if (conf == NULL) { printf ("\n", numfields); } else { while (fgets (buf, sizeof(buf), conf)) { if (sscanf(buf, "MONITOR %s %n", addr, &restofs) == 1) { desc = buf + restofs; if (*desc == '\"') restofs = strcspn(++desc, "\n\r\""); else restofs = strcspn(desc, "\n\r"); desc[restofs] = '\0'; if (*desc == '\0') { strlcpy(buf, "UNKNOWN", sizeof(buf)); desc = buf; } getinfo(addr); /* get and print info for this host */ } } fclose (conf); } (void) puts ("
\n", numfields); (void) puts ("APCUPSD UPS Network Monitor"); printf ("
%s
%s
Error: Cannot open hosts file
"); html_finish(); exit(EXIT_SUCCESS); } apcupsd-3.14.14/src/cgi/upsfetch.c000066400000000000000000000173221274230402600166460ustar00rootroot00000000000000/* * upsfetch - utility program to retrieve data from apcupsd.status * * Original Author: Russell Kroll * * This source creates a handy object file that can be linked into other * programs for easy retrieval of common UPS parameters from the apcupsd * status file. * * Modified: Jonathan Benson * 19/6/98 to suit apcupsd * 23/6/98 added more graphs and menu options * * Modified: Kern Sibbald * 2 Nov 99 to work with apcupsd named pipes * 5 Nov 99 added more graphs * 11 Nov 99 to work with apcnetd networking * also modified it to be a bit closer * to the original version. */ #include #include #include #include "cgiconfig.h" #include "apcconfig.h" #include "nis.h" static int fill_buffer(sock_t sockfd); char statbuf[4096]; size_t statlen = 0; static char last_host[256] = ""; char errmsg[200] = ""; /* List of variables that can be read by getupsvar() * First field is that name given to getupsvar(), * Second field is our internal name as produced by the STATUS * output from apcupsd. * Third field, if 0 returns everything to the end of the * line, and if 1 returns only to first space (e.g. integers, * and floating point values. */ static const struct { const char *request; const char *upskeyword; int nfields; } cmdtrans[] = { {"model", "MODEL", 0}, {"upsmodel", "UPSMODEL", 0}, {"date", "DATE", 0}, {"battcap", "BCHARGE", 1}, {"mbattchg", "MBATTCHG", 1}, {"battvolt", "BATTV", 1}, {"nombattv", "NOMBATTV", 1}, {"utility", "LINEV", 1}, {"upsload", "LOADPCT", 1}, {"loadpct", "LOADPCT", 1}, {"outputv", "OUTPUTV", 1}, {"status", "STATFLAG", 1}, {"linemin", "MINLINEV", 1}, {"linemax", "MAXLINEV", 1}, {"upstemp", "ITEMP", 1}, {"humidity", "HUMIDITY", 1}, {"ambtemp", "AMBTEMP", 1}, {"outputfreq", "LINEFREQ", 1}, {"translo", "LOTRANS", 1}, {"transhi", "HITRANS", 1}, {"runtime", "TIMELEFT", 1}, {"mintimel", "MINTIMEL", 1}, {"retpct", "RETPCT", 1}, /* min batt to turn on UPS */ {"sense", "SENSE", 1}, {"hostname", "HOSTNAME", 1}, {"battdate", "BATTDATE", 1}, {"serialno", "SERIALNO", 1}, {"lastxfer", "LASTXFER", 0}, /* reason for last xfer to batteries */ {"selftest", "SELFTEST", 1}, /* results of last self test */ {"laststest", "LASTSTEST", 0}, {"version", "VERSION", 1}, {"upsname", "UPSNAME", 1}, {"lowbatt", "DLOWBATT", 1}, /* low battery power off delay */ {"battpct", "BCHARGE", 1}, {"highxfer", "HITRANS", 1}, {"lowxfer", "LOTRANS", 1}, {"cable", "CABLE", 0}, {"firmware", "FIRMWARE", 0}, {NULL, NULL, 0} }; /* * Read data into memory buffer to be used by getupsvar() * Returns 0 on error * Returns 1 if data fetched */ static int fetch_data(const char *host) { int nis_port = NISPORT; sock_t sockfd; int stat; char *p; char lhost[200]; if (statlen != 0 && (strcmp(last_host, host) == 0)) return 1; /* alread have data this host */ strncpy(last_host, host, sizeof(last_host)); last_host[sizeof(last_host) - 1] = '\0'; statlen = 0; strncpy(lhost, host, sizeof(lhost)-1); lhost[sizeof(lhost)-1] = '\0'; p = strchr(lhost, ':'); if (p) { *p++ = '\0'; nis_port = atoi(p); } if ((sockfd = net_open(lhost, NULL, nis_port)) < 0) { (void) snprintf(errmsg, sizeof (errmsg), "upsfetch: tcp_open failed for %s port %d", lhost, nis_port); return 0; } stat = fill_buffer(sockfd); /* fill statbuf */ if (stat == 0) { *last_host = '\0'; statlen = 0; } net_close(sockfd); return stat; } /* * Read data into memory buffer to be used by getupsvar() * Returns 0 on error * Returns 1 if data fetched */ int fetch_events(const char *host) { int nis_port = NISPORT; char buf[500]; sock_t sockfd; int n, stat = 1; char *p; char lhost[200]; size_t len; statlen = 0; statbuf[0] = '\0'; strncpy(lhost, host, sizeof(lhost)-1); lhost[sizeof(lhost)-1] = '\0'; p = strchr(lhost, ':'); if (p) { *p++ = '\0'; nis_port = atoi(p); } if ((sockfd = net_open(lhost, NULL, nis_port)) < 0) { snprintf(errmsg, sizeof(errmsg), "upsfetch: tcp_open failed for %s port %d", lhost, nis_port); fputs(errmsg, stdout); return 0; } if (net_send(sockfd, "events", 6) != 6) { snprintf(errmsg, sizeof(errmsg), "fill_buffer: write error on socket\n"); fputs(errmsg, stdout); net_close(sockfd); return 0; } /* * Now read the events and invert them for the list box, * with most recend event at the beginning. * by dg2fer. */ while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) { /* terminate string for strlen()-calls in next lines */ buf[n] = '\0'; /* ensure string terminated */ len = strlen(buf); /* if message is bigger than the buffer, truncate it */ if (len > sizeof(statbuf)-1) len = sizeof(statbuf)-1; /* move previous messages to the end of the buffer */ memmove(statbuf+len, statbuf, sizeof(statbuf)-len-1); /* copy new message */ memcpy(statbuf, buf, len); statbuf[sizeof(statbuf)-1] = '\0'; } if (n < 0) { stat = 0; } *last_host = '\0'; net_close(sockfd); return stat; } /* In our version, we have prefetched all the data, so the * host argument is ignored here. * Returns 1 if var found * answer has var * Returns 0 if variable name not found * answer has "Not found" is variable name not found * answer may have "N/A" if the UPS does not support this * feature * Returns -1 if network problem * answer has "N/A" if host is not available or network error */ int getupsvar(const char *host, const char *request, char *answer, size_t anslen) { int i; const char *stat_match = NULL; char *find; int nfields = 0; if (fetch_data(host) == 0) { strncpy(answer, "N/A", anslen); answer[anslen - 1] = '\0'; return -1; } for (i=0; cmdtrans[i].request; i++) if (strcmp(cmdtrans[i].request, request) == 0) { stat_match = cmdtrans[i].upskeyword; nfields = cmdtrans[i].nfields; } if (stat_match != NULL) { if ((find=strstr(statbuf, stat_match)) != NULL) { if (nfields == 1) /* get one field */ sscanf (find, "%*s %*s %s", answer); else { /* get everything to eol */ i = 0; find += 11; /* skip label */ while (*find != '\n') answer[i++] = *find++; answer[i] = '\0'; } if (strcmp(answer, "N/A") == 0) return 0; return 1; } } strncpy(answer, "Not found", anslen); answer[anslen - 1] = '\0'; return 0; } /* Fill buffer with data from UPS network daemon * Returns 0 on error * Returns 1 if OK */ static int fill_buffer(sock_t sockfd) { int n, stat = 1; char buf[1000]; statbuf[0] = '\0'; statlen = 0; if (net_send(sockfd, "status", 6) != 6) { snprintf(errmsg, sizeof(errmsg), "fill_buffer: write error on socket\n"); return 0; } while ((n = net_recv(sockfd, buf, sizeof(buf)-1)) > 0) { buf[n] = '\0'; strncat(statbuf, buf, sizeof(statbuf)-statlen-1); statlen = strlen(statbuf); } if (n < 0) stat = 0; return stat; } apcupsd-3.14.14/src/cgi/upsfetch.h000066400000000000000000000023171274230402600166510ustar00rootroot00000000000000/* upsfetch.h - prototypes for important functions used when linking 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __UPSFETCH_H #define __UPSFETCH_H #include extern char statbuf[4096]; extern size_t statlen; extern char errmsg[200]; /* Read data into memory buffer to be used by getupsvar() */ int fetch_events (const char *host); /* get from and put the reply in */ int getupsvar (const char *host, const char *varname, char *buf, size_t buflen); #endif apcupsd-3.14.14/src/cgi/upsfstats.c000066400000000000000000000030711274230402600170550ustar00rootroot00000000000000/* * Program to print the full status output from apcupsd * * Kern Sibbald, 17 November 1999 * * */ #include #include #include #include #include "cgiconfig.h" #include "cgilib.h" #include "upsfetch.h" #ifndef DEFAULT_REFRESH #define DEFAULT_REFRESH 30 #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif static char monhost[MAXHOSTNAMELEN] = "127.0.0.1"; static int refresh = DEFAULT_REFRESH; void parsearg(const char *var, const char *value) { if (strcmp(var, "host") == 0) { strncpy (monhost, value, sizeof(monhost)); monhost[sizeof(monhost) - 1] = '\0'; } else if (strcmp(var, "refresh") == 0) { refresh = atoi(value); if (refresh < 0) { refresh = DEFAULT_REFRESH; } } } int main(int argc, char **argv) { char answer[256]; (void) extractcgiargs(); html_begin("APCUPSD Full Status Page", refresh); if (!checkhost(monhost)) { fputs ("

Access to host ", stdout); html_puts(monhost); puts (" is not authorized.

"); html_finish(); exit (EXIT_FAILURE); } /* check if host is available */ if (getupsvar (monhost, "date", answer, sizeof(answer)) < 0) { fputs ("

Unable to communicate with the UPS on ", stdout); html_puts(monhost); puts (".

"); html_finish(); exit (EXIT_FAILURE); } fputs ("
", stdout);
    html_puts (statbuf);
    puts ("
"); html_finish(); exit(EXIT_SUCCESS); } apcupsd-3.14.14/src/cgi/upsimage.c000066400000000000000000000271471274230402600166450ustar00rootroot00000000000000/* * upsimage - cgi program to create graphical ups information reports * * Original Author: Russell Kroll * * When used together, upsstats and upsimage create interesting looking web * pages with graphical representations of the battery capacity, utility * voltage, and UPS load. * * This program utilizes the gd graphics library for snappy IMG generation. * I highly recommend this package for anyone doing similar graphics * "on the fly" in C. * * This binary needs to be installed some place where upsstats can find it. * * Modified: Jonathan Benson * 19/6/98 to suit apcupsd * 23/6/98 added more graphs and menu options * * Modified by Kern Sibbald to include additional graphs as well as * to adapt the graphs to varing conditions (voltage, ...). Also, * consolidate a lot of code into subroutines. * * Modified by Riccardo Facchetti to support both GIF and PNG formats. * */ #include "apc.h" #if !defined(SYS_IMGFMT_PNG) && !defined(SYS_IMGFMT_GIF) && !defined(IMGFMT_GIF) # error "A graphic file format must be defined to compile this program." #endif #include #include #include #include "cgiconfig.h" #include "cgilib.h" static char mycmd[16] = ""; static char upsval[16] = ""; static char upsval2[16] = ""; static char upsval3[16] = ""; static int green, black, white, grey, darkgrey, red; static void allocate_colors(gdImagePtr im) { black = gdImageColorAllocate (im, 0, 0, 0); green = gdImageColorAllocate (im, 0, 255, 0); white = gdImageColorAllocate (im, 255, 255, 255); grey = gdImageColorAllocate (im, 200, 200, 200); darkgrey = gdImageColorAllocate (im, 50, 50, 50); red = gdImageColorAllocate (im, 255, 0, 0); } static void DrawTickLines(gdImagePtr im) { gdImageLine (im, 50, 60, 150, 60, darkgrey); gdImageLine (im, 50, 120, 150, 120, darkgrey); gdImageLine (im, 50, 180, 150, 180, darkgrey); gdImageLine (im, 50, 240, 150, 240, darkgrey); gdImageLine (im, 50, 300, 150, 300, darkgrey); } static void DrawText(gdImagePtr im, int min, int step) { int next; char text[10]; next = min; (void) snprintf(text, sizeof(text), "%d", next); gdImageString(im, gdFontLarge, 0, 295, (unsigned char *)text, black); next += step; (void) snprintf(text, sizeof(text), "%d", next); gdImageString(im, gdFontLarge, 0, 235, (unsigned char *)text, black); next += step; (void) snprintf(text, sizeof(text), "%d", next); gdImageString(im, gdFontLarge, 0, 175, (unsigned char *)text, black); next += step; (void) snprintf(text, sizeof(text), "%d", next); gdImageString(im, gdFontLarge, 0, 115, (unsigned char *)text, black); next += step; (void) snprintf(text, sizeof(text), "%d", next); gdImageString(im, gdFontLarge, 0, 55, (unsigned char *)text, black); next += step; (void) snprintf(text, sizeof(text), "%d", next); gdImageString(im, gdFontLarge, 0, 0, (unsigned char *)text, black); } static gdImagePtr InitImage(void) { gdImagePtr im; im = gdImageCreate(150, 350); allocate_colors(im); gdImageColorTransparent (im, grey); gdImageFilledRectangle (im, 0, 0, 150, 350, grey); gdImageFilledRectangle (im, 50, 0, 150, 300, green); return im; } void parsearg(const char *var, const char *value) { if (strcmp(var, "display") == 0) { strncpy (mycmd, value, sizeof(mycmd)); mycmd[sizeof(mycmd) - 1] = '\0'; } else if (strcmp(var, "value") == 0) { strncpy (upsval, value, sizeof(upsval)); upsval[sizeof(upsval) - 1] = '\0'; } else if (strcmp(var, "value2") == 0) { strncpy (upsval2, value, sizeof(upsval2)); upsval2[sizeof(upsval2) - 1] = '\0'; } else if (strcmp(var, "value3") == 0) { strncpy (upsval3, value, sizeof(upsval3)); upsval3[sizeof(upsval3) - 1] = '\0'; } } static void imgheader (void) { #ifdef SYS_IMGFMT_PNG puts ("Content-Type: image/png"); #else puts ("Content-Type: image/gif"); #endif /* * Since this image is generated based on the parameters passed in * the URL, caching is acceptable. No need for Cache-Control. */ puts (""); } static void TermImage(gdImagePtr im) { DrawTickLines(im); imgheader(); #ifdef SYS_IMGFMT_PNG gdImagePng (im, stdout); #else gdImageGif (im, stdout); #endif gdImageDestroy (im); } static void drawbattcap(const char *battcaps, const char *minbchgs) { gdImagePtr im; char batttxt[16]; int battpos; double battcap; int minbchgpos; double minbchg; battcap = strtod(battcaps, NULL); minbchg = strtod(minbchgs, NULL); im = InitImage(); DrawText(im, 0, 20); minbchgpos = (int)(300 - (minbchg * 3)); gdImageFilledRectangle(im, 50, minbchgpos, 150, 300, red); battpos = (int)(300 - (battcap * 3)); gdImageFilledRectangle(im, 75, battpos, 125, 300, black); (void) snprintf(batttxt, sizeof(batttxt), "%.1f %%", battcap); gdImageString(im, gdFontLarge, 70, 320, (unsigned char *)batttxt, black); TermImage(im); } static void drawbattvolt(const char *battvolts, const char *nombattvs) { gdImagePtr im; char batttxt[16]; int battpos; int hipos, lowpos; double battvolt; double nombattv; double hip, lowp; /* hi and low red line conditions */ int minv, maxv, deltav; im = InitImage(); battvolt = strtod(battvolts, NULL); nombattv = strtod(nombattvs, NULL); /* NOTE, if you tweek minv and maxv, ensure that the difference * is evenly divisible by 5 or the scales will be wrong!!! */ switch ((int)nombattv) { case 12: minv = 3; maxv = 18; hip = 12 + 3; /* high redline -- guess */ lowp = 12 - 3; /* low redline -- guess */ break; case 24: minv = 15; maxv = 30; hip = 24 + 5; lowp = 24 - 5; break; case 48: minv = 30; maxv = 60; hip = 48 + 7; lowp = 48 - 7; break; default: minv = 0; maxv = (int)(battvolt/10 + 1) * 10; hip = battvolt + 5; lowp = battvolt - 5; break; } deltav = maxv - minv; DrawText(im, minv, (deltav)/5); /* Do proper scaling of battery voltage and redline positions */ battpos = (int)(300 - (((battvolt - minv) / deltav ) * 300)); hipos = (int)( 300 - (((hip - minv) / deltav) * 300) ); lowpos = (int)( 300 - (((lowp - minv) / deltav) * 300) ); gdImageFilledRectangle (im, 50, 0, 150, hipos, red); gdImageFilledRectangle (im, 50, lowpos, 150, 300, red); gdImageFilledRectangle (im, 75, battpos, 125, 300, black); (void) snprintf (batttxt, sizeof(batttxt), "%.1f VDC", battvolt); gdImageString(im, gdFontLarge, 70, 320, (unsigned char *)batttxt, black); TermImage(im); } #if 0 static void noimage (void) { gdImagePtr im; im = gdImageCreate (150, 350); allocate_colors(im); gdImageColorTransparent (im, grey); gdImageFilledRectangle (im, 0, 0, 150, 300, grey); gdImageString (im, gdFontLarge, 0, 0, (unsigned char *)"Data not available", black); imgheader(); #ifdef SYS_IMGFMT_PNG gdImagePng (im, stdout); #else gdImageGif (im, stdout); #endif gdImageDestroy (im); } #endif static void drawupsload(const char *upsloads) { gdImagePtr im; char loadtxt[16]; int loadpos; double upsload; upsload = strtod(upsloads, NULL); im = InitImage(); DrawText(im, 0, 25); gdImageFilledRectangle (im, 50, 0, 150, 60, red); gdImageFilledRectangle (im, 50, 60, 150, 300, green); loadpos = (int)(300 - ((upsload / 125) * 300)); gdImageFilledRectangle(im, 75, loadpos, 125, 300, black); (void) snprintf(loadtxt, sizeof(loadtxt), "%.1f %%", upsload); gdImageString(im, gdFontLarge, 70, 320, (unsigned char *)loadtxt, black); TermImage(im); } /* * Input Voltage */ static void drawutility (const char *utilitys, const char *translos, const char *transhis) { gdImagePtr im; char utiltxt[16]; int utilpos, translopos, transhipos; double utility, translo, transhi; int minv, deltav; utility = strtod(utilitys, NULL); translo = strtod(translos, NULL); transhi = strtod(transhis, NULL); im = InitImage(); if (utility > 180) { /* Europe 230V */ minv = 200; deltav = 75; } else if (utility > 110) { /* US 110-120 V */ minv = 90; deltav = 50; } else if (utility > 95) { /* Japan 100V */ minv = 80; deltav = 50; } else { /* No voltage */ minv = 0; deltav = 50; } DrawText(im, minv, deltav/5); utilpos = (int)(300 - (((utility - minv) / deltav) * 300) ); translopos = (int)(300 - (((translo - minv) / deltav) * 300) ); transhipos = (int)(300 - (((transhi - minv) / deltav) * 300) ); gdImageFilledRectangle(im, 50, 0, 150, transhipos, red); gdImageFilledRectangle(im, 50, translopos, 150, 300, red); gdImageFilledRectangle (im, 75, utilpos, 125, 300, black); (void) snprintf (utiltxt, sizeof(utiltxt), "%.1f VAC", utility); gdImageString (im, gdFontLarge, 65, 320, (unsigned char *)utiltxt, black); TermImage(im); } /* * Output Voltage */ static void drawupsout (const char *upsouts) { gdImagePtr im; char utiltxt[16]; int uoutpos; double upsout; int minv, deltav; upsout = strtod(upsouts, NULL); im = InitImage(); if (upsout > 180) { minv = 200; deltav = 75; } else if (upsout > 110) { minv = 90; deltav = 50; } else if (upsout > 95) { minv = 80; deltav = 50; } else { minv = 0; deltav = 50; } DrawText(im, minv, deltav/5); uoutpos = (int)(300 - (((upsout - minv) / deltav) * 300) ); gdImageFilledRectangle(im, 75, uoutpos, 125, 300, black); (void) snprintf(utiltxt, sizeof(utiltxt), "%.1f VAC", upsout); gdImageString(im, gdFontLarge, 65, 320, (unsigned char *)utiltxt, black); TermImage(im); } static void drawruntime (const char *upsrunts, const char *lowbatts) { gdImagePtr im; char utiltxt[16]; int uoutpos, lowbattpos; double upsrunt; double lowbatt; int step, maxt; upsrunt = strtod(upsrunts, NULL); lowbatt = strtod(lowbatts, NULL); im = InitImage(); step = (int)(upsrunt + 4) / 5; if (step <= 0) step = 1; /* make sure we have a positive step */ DrawText(im, 0, step); maxt = step * 5; uoutpos = 300 - (int)(upsrunt * 300 ) / maxt; lowbattpos = 300 - (int)(lowbatt * 300) / maxt; gdImageFilledRectangle(im, 50, lowbattpos, 150, 300, red); gdImageFilledRectangle(im, 75, uoutpos, 125, 300, black); (void) snprintf(utiltxt, sizeof(utiltxt), "%.1f mins", upsrunt); gdImageString(im, gdFontLarge, 65, 320, (unsigned char *)utiltxt, black); TermImage(im); } int main (int argc, char **argv) { #ifdef WIN32 setmode(fileno(stdout), O_BINARY); #endif (void) extractcgiargs(); if (strcmp(mycmd, "upsload") == 0) { drawupsload(upsval); } else if (strcmp(mycmd, "battcap") == 0) { drawbattcap(upsval, upsval2); } else if (strcmp(mycmd, "battvolt") == 0) { drawbattvolt(upsval, upsval2); } else if (strcmp(mycmd, "utility") == 0) { drawutility(upsval, upsval2, upsval3); } else if (strcmp(mycmd, "outputv") == 0) { drawupsout(upsval); } else if (strcmp(mycmd, "runtime") == 0) { drawruntime(upsval, upsval2); } else { puts("Status: 400 Bad request"); puts("Content-Type: text/plain; charset=utf-8\n"); puts("400 Bad request"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } apcupsd-3.14.14/src/cgi/upsstats.c000066400000000000000000000407501274230402600167140ustar00rootroot00000000000000/* * upsstats - cgi program to generate the main UPS info page * * Author: Russell Kroll * * To use: install the binary in a directory where CGI programs may be * executed by your web server. On many systems something like * /usr/local/etc/httpd/cgi-bin will work nicely. I recommend * calling the binary "upsstats.cgi" in that directory. * * Assuming a path like the above, the following link will suffice: * UPS Status * * This program assumes that upsimage.cgi will be in the same * directory. The install-cgi target will take care of putting * things in the right place if you set the paths properly in the * Makefile. * * Modified: Jonathan Benson * 19/6/98 to suit apcupsd * 23/6/98 added more graphs and menu options * * Modified: Kern Sibbald * Nov 1999 to work with apcupsd networking and * to include as much of the NUT code * as possible. * added runtim status */ #include #include #include #include #include "cgiconfig.h" #include "cgilib.h" #include "upsfetch.h" #ifndef DEFAULT_REFRESH #define DEFAULT_REFRESH 30 #endif #ifndef MAXHOSTNAMELEN #define MAXHOSTNAMELEN 64 #endif static char monhost[MAXHOSTNAMELEN] = "127.0.0.1"; static int img1 = 1; static int img2 = 6; static int img3 = 5; static char temps[16] = "C"; static int refresh = DEFAULT_REFRESH; void parsearg(const char *var, const char *value) { if (strcmp(var, "host") == 0) { strncpy (monhost, value, sizeof(monhost)); monhost[sizeof(monhost) - 1] = '\0'; } else if (strcmp(var, "img1") == 0) { img1 = atoi(value); if ((img1 <= 0) || (img1 > 6)) { img1 = 1; } } else if (strcmp(var, "img2") == 0) { img2 = atoi(value); if ((img2 <= 0) || (img2 > 6)) { img2 = 6; } } else if (strcmp(var, "img3") == 0) { img3 = atoi(value); if ((img3 <= 0) || (img3 > 6)) { img3 = 5; } } else if (strcmp(var, "temp") == 0) { strncpy (temps, value, sizeof(temps)); temps[sizeof(temps) - 1] = '\0'; } else if (strcmp(var, "refresh") == 0) { refresh = atoi(value); if (refresh < 0) { refresh = DEFAULT_REFRESH; } } } void send_image(int report, int defrpt) { char answer[256], answer2[256], answer3[256]; if (report < 1 || report > 6) report = defrpt; fputs ("\"Battery"); } static void image_menu(int select) { fputs (" "); fputs (" "); fputs (" "); fputs (" "); fputs (" "); fputs (" "); } int main(int argc, char **argv) { int status; double tempf; char *p; char answer[256]; (void) extractcgiargs(); p = strstr(monhost, "%3"); if (p) { *p++ = ':'; /* set colon */ memmove(p, p+2, sizeof(monhost)-(p-monhost)); /* get rid of hex 3A */ } snprintf(answer, sizeof(answer), "%s UPS Status", monhost); html_begin(answer, refresh); if (!checkhost(monhost)) { fputs ("

Access to host ", stdout); html_puts(monhost); puts (" is not authorized.

"); html_finish(); exit (EXIT_FAILURE); } /* check if host is available */ if (getupsvar(monhost, "date", answer, sizeof(answer)) <= 0) { fputs ("

Unable to communicate with the UPS on ", stdout); html_puts(monhost); puts (".

"); html_finish(); exit (EXIT_FAILURE); } puts ("
"); puts (""); getupsvar(monhost, "date", answer, sizeof(answer)); fputs (""); puts (""); puts (""); puts (""); puts (""); puts (""); puts (""); puts (""); puts (""); puts (""); puts (""); puts (""); puts ("
", stdout); html_puts(answer); puts (""); printf ("
\n"); printf (" \n", monhost); printf (" \n"); printf (" \n",img2); printf (" \n",img3); printf (" \n",temps); printf (" \n",refresh); puts ("
"); puts ("
"); printf ("
\n"); printf (" \n", monhost); printf (" \n",img1); printf (" \n"); printf (" \n",img3); printf (" \n",temps); printf (" \n",refresh); puts ("
"); puts ("
"); printf ("
\n"); printf (" \n", monhost); printf (" \n",img1); printf (" \n",img2); printf (" \n"); printf (" \n",temps); printf (" \n",refresh); puts ("
"); puts ("
");

     getupsvar (monhost, "hostname", answer, sizeof(answer));
     fputs ("Monitoring: ", stdout);
     html_puts (answer);
     fputs ("\n", stdout);

     getupsvar (monhost, "model", answer, sizeof(answer));  
     fputs (" UPS Model: ", stdout);
     html_puts (answer);
     fputs ("\n", stdout);

     getupsvar (monhost, "upsname", answer, sizeof(answer));
     fputs ("  UPS Name: ", stdout);
     html_puts (answer);
     fputs ("\n", stdout);

     getupsvar (monhost, "version", answer, sizeof(answer));
     fputs ("   APCUPSD: Version ", stdout);
     html_puts (answer);
     fputs ("\n", stdout);

     fputs ("    Status: ", stdout);

     if (getupsvar (monhost, "status", answer, sizeof(answer)) <= 0) {
             puts ("Not available");
     } else {
         status = strtol(answer, 0, 16);
         if (status & UPS_calibration) 
             fputs ("CALIBRATION ", stdout); 
         if (status & UPS_trim)
             fputs ("TRIM ", stdout);
         if (status & UPS_boost)
             fputs ("BOOST ", stdout);
         if (status & UPS_online)
             fputs ("ONLINE ", stdout); 
         if (status & UPS_onbatt) 
             fputs ("ON BATTERY ", stdout); 
         if (status & UPS_overload)
             fputs ("OVERLOADED ", stdout);
         if (status & UPS_battlow) 
             fputs ("BATTERY LOW ", stdout); 
         if (status & UPS_replacebatt)
             fputs ("REPLACE BATTERY ", stdout);
         if (status & UPS_commlost)
             fputs("COMM LOST ", stdout); 
         if (status & UPS_shutdown)
             fputs("SHUTDOWN ", stdout);
         if (status & UPS_slave)
             fputs("SLAVE ", stdout);
         if (!(status & UPS_battpresent))
             fputs("NOBATT ", stdout);
         fputs ("\n", stdout); 
     }

     puts ("
"); send_image(img1, 1); puts (""); send_image(img2, 6); puts (""); send_image(img3, 5); puts ("
");

     getupsvar (monhost, "selftest", answer, sizeof(answer));
     fputs ("Last UPS Self Test: ", stdout);
     html_puts (answer);
     fputs ("\n", stdout);

     getupsvar(monhost, "laststest", answer, sizeof(answer));
     /* To reduce the length of the output, we drop the 
      * seconds and the trailing year.
      */
     for (p=answer; *p && *p != ':'; p++) ;
     if (*p == ':')
        p++;
     for ( ; *p && *p != ':'; p++) ;
     *p = '\0';
     fputs ("Last Test Date: ", stdout);
     html_puts (answer);
     fputs ("\n", stdout);

     puts ("
");

     getupsvar (monhost, "utility", answer, sizeof(answer));
     fputs ("Utility Voltage: ", stdout);
     html_puts (answer);
     puts (" VAC");

     getupsvar (monhost, "linemin", answer, sizeof(answer));
     fputs ("   Line Minimum: ", stdout);
     html_puts (answer);
     puts (" VAC");

     getupsvar (monhost, "linemax", answer, sizeof(answer));
     fputs ("   Line Maximum: ", stdout);
     html_puts (answer);
     puts (" VAC");

     getupsvar (monhost, "outputfreq", answer, sizeof(answer));
     fputs ("    Output Freq: ", stdout);
     html_puts (answer);
     puts (" Hz");

     if (getupsvar(monhost, "ambtemp", answer, sizeof(answer)) > 0) {
         if (strcmp(answer, "Not found" ) != 0) {
             if (strcmp(temps,"F") == 0) {
                tempf = (strtod (answer, 0) * 1.8) + 32;
                printf ("     Amb. Temp.: %.1f° F\n", tempf);
             } else if (strcmp(temps,"K") == 0) {
                tempf = (strtod (answer, 0)) + 273;
                printf ("     Amb. Temp.: %.1f° K\n", tempf);
             } else {
                printf ("     Amb. Temp.: %s° C\n", answer);
             } 
         }
     }

     if ( getupsvar (monhost, "humidity", answer, sizeof(answer)) > 0) {
         if (strcmp(answer, "Not found") != 0) {
              fputs ("  Amb. Humidity: ", stdout);
              html_puts (answer);
              puts (" %");
         }
     }

     printf ("
\n\n\n\n\n\n
\n
\n");

    if (getupsvar (monhost, "upstemp", answer, sizeof(answer)) > 0) {
         if (strcmp(temps,"F") == 0) {
              tempf = (strtod (answer, 0) * 1.8) + 32;
              printf ("       UPS Temp: %.1f \n
\n
\n", tempf); printf ("
\n"); printf (" \n",monhost); printf (" \n",img1); printf (" \n",img2); printf (" \n",img3); printf (" \n",refresh); printf ("
\n", tempf); printf ("
\n"); printf (" \n",monhost); printf (" \n",img1); printf (" \n",img2); printf (" \n",img3); printf (" \n",refresh); printf ("
\n", answer); printf ("
\n"); printf (" \n",monhost); printf (" \n",img1); printf (" \n",img2); printf (" \n",img3); printf (" \n",refresh); printf (" "); puts ("
"); puts ("
"); puts ("
Recent Events
"); puts (""); puts ("
"); html_finish(); return 0; } apcupsd-3.14.14/src/device.c000066400000000000000000000213251274230402600155200ustar00rootroot00000000000000/* * apcdevice.c * * Generic device handling * * Written by Riccardo Fachetti 2000 from Kern's design */ /* * Copyright (C) 2000-2004 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * This is a sort of helper routine between apcupsd core and the drivers. * The raw calls into the drivers are through function pointers in the * ups device structure, and are #defined to the following: * * device_open(ups) * device_setup(ups) * device_close(ups) * device_kill_power(ups) * device_shutdown(ups) * device_read_static_data(ups) * device_read_volatile_data(ups) * device_get_capabilities(ups) * device_check_state(ups) * device_program_eeprom(ups) * device_entry_point(ups, command, data) * * see include/apc_drivers.h for more details on each routine. */ #include "apc.h" /* Forward referenced function */ static int device_wait_time(UPSINFO *ups); /*********************************************************************/ bool setup_device(UPSINFO *ups) { return device_open(ups) && device_setup(ups) && device_get_capabilities(ups); } /*********************************************************************/ void initiate_hibernate(UPSINFO *ups) { int pwdf; int killcount; if (ups->mode.type == DUMB_UPS) { /* Make sure we are on battery */ for (killcount = 0; killcount < 3; killcount++) device_read_volatile_data(ups); } /* * ****FIXME***** This big if is BROKEN in the * case that there is no real power failure. * * We really need to find out if we are on batteries * and if not, delete the PWRFAIL file. Note, the code * above only tests UPS_onbatt flag for dumb UPSes. */ pwdf = open(ups->pwrfailpath, O_RDONLY|O_CLOEXEC); if ((pwdf == -1 && ups->mode.type != DUMB_UPS) || (pwdf == -1 && ups->is_onbatt() && ups->mode.type == DUMB_UPS)) { /* * At this point, we really should not be attempting * a kill power since either the powerfail file is * not defined, or we are not on batteries. */ /* Now complain */ log_event(ups, LOG_WARNING, "Cannot find %s file.\n Killpower requested in " "non-power fail condition or bug.\n Killpower request " "ignored at %s:%d\n", ups->pwrfailpath, __FILE__, __LINE__); Error_abort( "Cannot find %s file.\n Killpower requested in " "non-power fail condition or bug.\n Killpower request " "ignored at %s:%d\n", ups->pwrfailpath, __FILE__, __LINE__); } else { /* We are on batteries, so do the kill_power */ if (ups->upsclass.type == SHAREMASTER) { log_event(ups, LOG_WARNING, "Waiting 30 seconds for slave(s) to shutdown."); sleep(30); } /* close the powerfail file */ if (pwdf != -1) close(pwdf); log_event(ups, LOG_WARNING, "Attempting to kill the UPS power!"); if (ups->upsclass.type == SHARESLAVE) { sleep(10); log_event(ups, LOG_WARNING, "Waiting For ShareUPS Master to shutdown"); sleep(60); log_event(ups, LOG_WARNING, "Failed to have power killed by Master!"); /* * ***FIXME*** this really should not do a reboot here, * but rather a halt or nothing -- KES */ /* generate_event(ups, CMDDOREBOOT); */ log_event(ups, LOG_WARNING, "Perform CPU-reset or power-off"); return; } else { /* it must be a SmartUPS or BackUPS */ device_kill_power(ups); } } } /*********************************************************************/ void initiate_shutdown(UPSINFO *ups) { log_event(ups, LOG_WARNING, "Attempting to shutdown the UPS!"); device_shutdown(ups); } /* * After the device is initialized, we come here * to read all the information we can about the UPS. */ void prep_device(UPSINFO *ups) { device_read_static_data(ups); /* If no UPS name found, use hostname, or "default" */ if (ups->upsname[0] == 0) { /* no name given */ gethostname(ups->upsname, sizeof(ups->upsname) - 1); if (ups->upsname[0] == 0) /* error */ strlcpy(ups->upsname, "default", sizeof(ups->upsname)); } /* Strip unprintable characters from UPS model */ for (char *ptr = ups->upsmodel; *ptr; ptr++) { if (!isprint(*ptr)) *ptr = ' '; } } /* Called once every 5 seconds to read all UPS info */ int fillUPS(UPSINFO *ups) { device_read_volatile_data(ups); return 0; } static void open_ups(UPSINFO *ups) { // Don't issue a COMMLOST event until we've been running for a little while static const time_t COMMLOST_EVENT_GRACE_PERIOD = 60; time_t event_time = 0; while (!device_open(ups)) { // Failed to communicate with UPS: we're COMMLOST now ups->set_commlost(); // Do not generate COMMLOST event until we've retried a few times time_t now = time(NULL); if (now - ups->start_time >= COMMLOST_EVENT_GRACE_PERIOD) { // Generate an event once if (event_time == 0) { generate_event(ups, CMDCOMMFAILURE); event_time = now; } // Log every 10 minutes thereafter if ((now - event_time) >= 10*60) { event_time = now; log_event(ups, event_msg[CMDCOMMFAILURE].level, event_msg[CMDCOMMFAILURE].msg); } } sleep(5); } // If we were commlost, we're not any more if (ups->is_commlost()) { ups->clear_commlost(); if (event_time) generate_event(ups, CMDCOMMOK); } // Complete remainder of UPS setup device_setup(ups); device_get_capabilities(ups); prep_device(ups); } /* NOTE! This is the starting point for a separate process (thread). */ void do_device(UPSINFO *ups) { /* Open the UPS device and ensure we can talk to it. This does not return until the UPS is successfully contacted */ open_ups(ups); /* get all data so apcaccess is happy */ fillUPS(ups); while(1) { /* compute appropriate wait time */ ups->wait_time = device_wait_time(ups); Dmsg(70, "Before do_action: 0x%x (OB:%d).\n", ups->Status, ups->is_onbatt()); /* take event actions */ do_action(ups); Dmsg(70, "Before fillUPS: 0x%x (OB:%d).\n", ups->Status, ups->is_onbatt()); /* Get all info available from UPS by asking it questions */ fillUPS(ups); Dmsg(70, "Before do_action: 0x%x (OB:%d).\n", ups->Status, ups->is_onbatt()); /* take event actions */ do_action(ups); Dmsg(70, "Before do_reports: 0x%x (OB:%d).\n", ups->Status, ups->is_onbatt()); do_reports(ups); /* compute appropriate wait time */ ups->wait_time = device_wait_time(ups); Dmsg(70, "Before device_check_state: 0x%x (OB:%d).\n", ups->Status, ups->is_onbatt()); /* * Check the UPS to see if has changed state. * This routine waits a reasonable time to prevent * consuming too much CPU time. */ device_check_state(ups); } } /* * Each device handler when called at device_check_state() waits * a specified time for the next event. In general, we want this * to be as long as possible (i.e. about a minute) to prevent * excessive "polling" because when device_check_state() returns, * repoll the UPS (fillUPS). * This routine attempts to determine a reasonable "sleep" time * for the device. */ static int device_wait_time(UPSINFO *ups) { int wait_time; if (ups->is_fastpoll() || !ups->is_battpresent()) wait_time = TIMER_FAST; else if (ups->is_commlost()) wait_time = TIMER_FAST*5; else wait_time = ups->polltime; /* normally 60 seconds */ /* Make sure we do data and stats when asked */ if (ups->datatime && ups->datatime < wait_time) wait_time = ups->datatime; if (ups->stattime && ups->stattime < wait_time) wait_time = ups->stattime; /* Sanity check */ if (wait_time < TIMER_FAST) wait_time = TIMER_FAST; return wait_time; } apcupsd-3.14.14/src/drivers/000077500000000000000000000000001274230402600155705ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/Makefile000066400000000000000000000004421274230402600172300ustar00rootroot00000000000000topdir:=../.. SUBDIRS = $(SMARTDRV) $(DUMBDRV) $(NETDRV) $(PCNETDRV) $(USBDRV) \ $(SNMPLTDRV) $(TESTDRV) $(MODBUSDRV) include $(topdir)/autoconf/targets.mak SRCS = drivers.c all-targets: libdrivers.a libdrivers.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/apcsmart/000077500000000000000000000000001274230402600174025ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/apcsmart/Makefile000066400000000000000000000002771274230402600210500ustar00rootroot00000000000000topdir:=../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) all-targets: libapcsmartdrv.a libapcsmartdrv.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/apcsmart/apcsmart.h000066400000000000000000000042231274230402600213660ustar00rootroot00000000000000/* * apcsmart.h * * Public header file for the APC Smart protocol driver */ /* * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _APCSMART_H #define _APCSMART_H class ApcSmartUpsDriver: public UpsDriver { public: ApcSmartUpsDriver(UPSINFO *ups); virtual ~ApcSmartUpsDriver() {} static UpsDriver *Factory(UPSINFO *ups) { return new ApcSmartUpsDriver(ups); } virtual bool get_capabilities(); virtual bool read_volatile_data(); virtual bool read_static_data(); virtual bool kill_power(); virtual bool check_state(); virtual bool Open(); virtual bool Close(); virtual bool setup(); virtual bool entry_point(int command, void *data); virtual bool program_eeprom(int command, const char *data); virtual bool shutdown(); // Public for apctest char *smart_poll(char cmd); int getline(char *s, int len); void writechar(char a); private: static SelfTestResult decode_testresult(char* str); static LastXferCause decode_lastxfer(char *str); static const char *get_model_from_oldfwrev(const char *s); void UPSlinkCheck(); int apcsmart_ups_shutdown_with_delay(int shutdown_delay); int apcsmart_ups_get_shutdown_delay(); void apcsmart_ups_warn_shutdown(int shutdown_delay); void change_ups_battery_date(const char *newdate); void change_ups_name(const char *newname); void change_extended(); int change_ups_eeprom_item(const char *title, const char cmd, const char *setting); struct termios _oldtio; struct termios _newtio; bool _linkcheck; }; #endif /* _APCSMART_H */ apcupsd-3.14.14/src/drivers/apcsmart/smart.c000066400000000000000000000620531274230402600207020ustar00rootroot00000000000000 /* * apcsmart.c -- The decoding of the chatty little beasts. * THE LOOK-A-LIKE ( UPSlink(tm) Language ) * * apcupsd.c -- Simple Daemon to catch power failure signals from a * BackUPS, BackUPS Pro, or SmartUPS (from APCC). * -- Now SmartMode support for SmartUPS and BackUPS Pro. * * Copyright (C) 1996-99 Andre M. Hedrick * All rights reserved. * */ /* * Parts of the information below was taken from apcd.c & apcd.h * * Definitons file for APC SmartUPS daemon * * Copyright (c) 1995 Pavel Korensky * All rights reserved * * IN NO EVENT SHALL PAVEL KORENSKY BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF PAVEL KORENSKY * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * PAVEL KORENSKY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" * BASIS, AND PAVEL KORENSKY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Pavel Korensky pavelk@dator3.anet.cz * * 8.11.1995 * * P.S. I have absolutely no connection with company APC. I didn't sign any * non-disclosure agreement and I didn't got the protocol description anywhere. * The whole protocol decoding was made with a small program for capturing * serial data on the line. So, I think that everybody can use this software * without any problem. * */ /* Copyright (C) 1999-2004 Kern Sibbald 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA. */ #include "apc.h" #include "apcsmart.h" /* How long to wait before declaring commlost */ #define COMMLOST_TIMEOUT_MS (20*1000) /* Convert UPS response to enum and string */ SelfTestResult ApcSmartUpsDriver::decode_testresult(char* str) { /* * Responses are: * "OK" - good battery, * "BT" - failed due to insufficient capacity, * "NG" - failed due to overload, * "NO" - no results available (no test performed in last 5 minutes) */ if (str[0] == 'O' && str[1] == 'K') return TEST_PASSED; else if (str[0] == 'B' && str[1] == 'T') return TEST_FAILCAP; else if (str[0] == 'N' && str[1] == 'G') return TEST_FAILLOAD; return TEST_NONE; } /* Convert UPS response to enum and string */ LastXferCause ApcSmartUpsDriver::decode_lastxfer(char *str) { Dmsg(80, "Transfer reason: %c\n", *str); switch (*str) { case 'N': return XFER_NA; case 'R': return XFER_RIPPLE; case 'H': return XFER_OVERVOLT; case 'L': return XFER_UNDERVOLT; case 'T': return XFER_NOTCHSPIKE; case 'O': return XFER_NONE; case 'K': return XFER_FORCED; case 'S': return XFER_SELFTEST; default: return XFER_UNKNOWN; } } ApcSmartUpsDriver::ApcSmartUpsDriver(UPSINFO *ups) : UpsDriver(ups), _linkcheck(false) { memset(&_oldtio, 0, sizeof(_oldtio)); memset(&_newtio, 0, sizeof(_newtio)); } void ApcSmartUpsDriver::writechar(char a) { write(_ups->fd, &a, 1); } /********************************************************************* * * Send a charcter to the UPS and get * its response. Returns a pointer to the response string. * */ char *ApcSmartUpsDriver::smart_poll(char cmd) { static char answer[2000]; int stat, retry; *answer = 0; if (_ups->fd == -1) return answer; /* Don't retry Y/SM command */ retry = (cmd == 'Y') ? 0 : 2; do { write(_ups->fd, &cmd, 1); stat = getline(answer, sizeof answer); /* If nothing returned, the link is probably down */ if (*answer == 0 && stat == FAILURE) { UPSlinkCheck(); /* wait for link to come up */ *answer = 0; /* UPSlinkCheck invokes us recursively, so clean up */ } } while (*answer == 0 && stat == FAILURE && retry--); return answer; } /* * If s == NULL we are just waiting on FD for status changes. * If s != NULL we are asking the UPS to tell us the value of something. * * If s == NULL there is a much more fine-grained locking. */ int ApcSmartUpsDriver::getline(char *s, int len) { int i = 0; int ending = 0; char c; int retval; int wait; if (s != NULL) wait = TIMER_FAST; /* 1 sec, expect fast response */ else wait = _ups->wait_time; #ifdef HAVE_MINGW /* Set read() timeout since we have no select() support. */ { COMMTIMEOUTS ct; HANDLE h = (HANDLE)_get_osfhandle(_ups->fd); ct.ReadIntervalTimeout = MAXDWORD; ct.ReadTotalTimeoutMultiplier = MAXDWORD; ct.ReadTotalTimeoutConstant = wait * 1000; ct.WriteTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; SetCommTimeouts(h, &ct); } #endif while (!ending) { #if !defined(HAVE_MINGW) fd_set rfds; struct timeval tv; FD_ZERO(&rfds); FD_SET(_ups->fd, &rfds); tv.tv_sec = wait; tv.tv_usec = 0; errno = 0; retval = select((_ups->fd) + 1, &rfds, NULL, NULL, &tv); switch (retval) { case 0: /* No chars available in TIMER seconds. */ return FAILURE; case -1: if (errno == EINTR || errno == EAGAIN) { /* assume SIGCHLD */ continue; } else if (errno == EBADF) { return FAILURE; /* We're probably shutting down */ } Error_abort("Select error on UPS FD. %s\n", strerror(errno)); break; default: break; } #endif do { retval = read(_ups->fd, &c, 1); } while (retval == -1 && (errno == EAGAIN || errno == EINTR)); if (retval <= 0) { return FAILURE; } switch (c) { /* * Here we can be called in two ways: * * s == NULL * The shm lock is not held so we must hold it here. * * s != NULL * We are called from a routine that have * already held the shm lock so no need to hold it * another time. Simply update the UPS structure * fields and the shm will be updated when * write_unlock is called by the calling * routine. * * If something changes on the UPS, a special character is * sent over the serial line but no \n\r sequence is sent: * only a single character. This way if s == NULL, if we * receive a character like this we must return immediately * and not wait for a string completion. */ case UPS_ON_BATT: /* UPS_ON_BATT = '!' */ if (s == NULL) write_lock(_ups); _ups->clear_online(); Dmsg(80, "Got UPS ON BATT.\n"); if (s == NULL) { write_unlock(_ups); ending = 1; } break; case UPS_REPLACE_BATTERY: /* UPS_REPLACE_BATTERY = '#' */ if (s == NULL) write_lock(_ups); _ups->set_replacebatt(); Dmsg(80, "Got UPS REPLACE_BATT.\n"); if (s == NULL) { write_unlock(_ups); ending = 1; } break; case UPS_ON_LINE: /* UPS_ON_LINE = '$' */ if (s == NULL) write_lock(_ups); _ups->set_online(); Dmsg(80, "Got UPS ON LINE.\n"); if (s == NULL) { write_unlock(_ups); ending = 1; } break; case BATT_LOW: /* BATT_LOW = '%' */ if (s == NULL) write_lock(_ups); _ups->set_battlow(); Dmsg(80, "Got UPS BATT_LOW.\n"); if (s == NULL) { write_unlock(_ups); ending = 1; } break; case BATT_OK: /* BATT_OK = '+' */ if (s == NULL) write_lock(_ups); _ups->clear_battlow(); Dmsg(80, "Got UPS BATT_OK.\n"); if (s == NULL) { write_unlock(_ups); ending = 1; } break; case UPS_EPROM_CHANGE: /* UPS_EPROM_CHANGE = '|' */ case UPS_TRAILOR: /* UPS_TRAILOR = ':' */ break; /* NOTE: The UPS terminates what it sends to us * with a \r\n. Thus the line feed signals the * end of what we are to receive. */ case UPS_LF: /* UPS_LF = '\n' */ if (s != NULL) ending = 1; /* This what we waited for */ break; case UPS_CR: /* UPS_CR = '\r' */ break; default: if (s != NULL) { if (i + 1 < len) s[i++] = c; else ending = 1; /* no more room in buffer */ } break; } } if (s != NULL) { s[i] = '\0'; } return SUCCESS; } /*********************************************************************/ /* Note this routine MUST be called with the UPS write lock held! */ void ApcSmartUpsDriver::UPSlinkCheck() { struct timeval now, prev, start; if (_linkcheck) return; _linkcheck = true; /* prevent recursion */ tcflush(_ups->fd, TCIOFLUSH); if (strcmp(smart_poll('Y'), "SM") == 0) { _linkcheck = false; _ups->clear_commlost(); return; } write_unlock(_ups); gettimeofday(&start, NULL); prev = start; tcflush(_ups->fd, TCIOFLUSH); while (strcmp(smart_poll('Y'), "SM") != 0) { /* Declare commlost only if COMMLOST_TIMEOUT_MS has expired */ gettimeofday(&now, NULL); if (TV_DIFF_MS(start, now) >= COMMLOST_TIMEOUT_MS) { /* Generate commlost event if we've not done so yet */ if (!_ups->is_commlost()) { _ups->set_commlost(); generate_event(_ups, CMDCOMMFAILURE); prev = now; } /* Log an event every 10 minutes */ if (TV_DIFF_MS(prev, now) >= 10*60*1000) { log_event(_ups, event_msg[CMDCOMMFAILURE].level, event_msg[CMDCOMMFAILURE].msg); prev = now; } } /* * If we've declared COMMLOST, close the port and reopen it after we * sleep a little while. This is helpful for cases where the serial * device is removable and the user might have yanked it out and the dev * node will change when they plug it back in. */ if (_ups->is_commlost()) Close(); /* * This sleep should not be necessary since the smart_poll() * routine normally waits TIMER_FAST (1) seconds. However, * in case the serial port is broken and generating spurious * characters, we sleep to reduce CPU consumption. */ sleep(1); /* * Open the port again. This might fail, in which case _ups->fd will be * invalid which will cause smart_poll() to fail and we'll end up back * here again. When Open() eventually succeeds and smart_poll() starts * to function, we'll exit COMMLOST state. */ if (_ups->is_commlost()) Open(); tcflush(_ups->fd, TCIOFLUSH); } write_lock(_ups); if (_ups->is_commlost()) { _ups->clear_commlost(); generate_event(_ups, CMDCOMMOK); } _linkcheck = false; } /********************************************************************* * * This subroutine is called to load our shared memory with * information that is changing inside the UPS depending * on the state of the UPS and the mains power. */ bool ApcSmartUpsDriver::read_volatile_data() { char *answer; write_lock(_ups); UPSlinkCheck(); /* make sure serial port is working */ _ups->poll_time = time(NULL); /* save time stamp */ /* UPS_STATUS */ if (_ups->UPS_Cap[CI_STATUS]) { char status[10]; int retries = 5; /* Number of retries on status read */ again: answer = smart_poll(_ups->UPS_Cmd[CI_STATUS]); Dmsg(80, "Got CI_STATUS: %s\n", answer); strlcpy(status, answer, sizeof(status)); /* * The Status command may return "SM" probably because firmware * is in a state where it still didn't updated its internal status * register. In this case retry to read the register. To be sure * not to get stuck here, we retry only 5 times. * * XXX * * If this fails, apcupsd may not be able to detect a status * change and will have unpredictable behavior. This will be fixed * once we will handle correctly the own apcupsd Status word. */ if (status[0] == 'S' && status[1] == 'M' && (retries-- > 0)) goto again; _ups->Status &= ~0xFF; /* clear APC byte */ _ups->Status |= strtoul(status, NULL, 16) & 0xFF; /* set APC byte */ } /* ONBATT_STATUS_FLAG -- line quality */ if (_ups->UPS_Cap[CI_LQUAL]) { answer = smart_poll(_ups->UPS_Cmd[CI_LQUAL]); Dmsg(80, "Got CI_LQUAL: %s\n", answer); strlcpy(_ups->linequal, answer, sizeof(_ups->linequal)); } /* Reason for last transfer to batteries */ if (_ups->UPS_Cap[CI_WHY_BATT]) { answer = smart_poll(_ups->UPS_Cmd[CI_WHY_BATT]); Dmsg(80, "Got CI_WHY_BATT: %s\n", answer); _ups->lastxfer = decode_lastxfer(answer); /* * XXX * * See if this is a self test rather than power failure * But not now ! * When we will be ready we will copy the code below inside * the driver entry point, for performing this check inside the * driver. */ } /* Results of last self test */ if (_ups->UPS_Cap[CI_ST_STAT]) { answer = smart_poll(_ups->UPS_Cmd[CI_ST_STAT]); Dmsg(80, "Got CI_ST_STAT: %s\n", answer); _ups->testresult = decode_testresult(answer); } /* LINE_VOLTAGE */ if (_ups->UPS_Cap[CI_VLINE]) { answer = smart_poll(_ups->UPS_Cmd[CI_VLINE]); Dmsg(80, "Got CI_VLINE: %s\n", answer); _ups->LineVoltage = atof(answer); } /* UPS_LINE_MAX */ if (_ups->UPS_Cap[CI_VMAX]) { answer = smart_poll(_ups->UPS_Cmd[CI_VMAX]); Dmsg(80, "Got CI_VMAX: %s\n", answer); _ups->LineMax = atof(answer); } /* UPS_LINE_MIN */ if (_ups->UPS_Cap[CI_VMIN]) { answer = smart_poll(_ups->UPS_Cmd[CI_VMIN]); Dmsg(80, "Got CI_VMIN: %s\n", answer); _ups->LineMin = atof(answer); } /* OUTPUT_VOLTAGE */ if (_ups->UPS_Cap[CI_VOUT]) { answer = smart_poll(_ups->UPS_Cmd[CI_VOUT]); Dmsg(80, "Got CI_VOUT: %s\n", answer); _ups->OutputVoltage = atof(answer); } /* BATT_FULL Battery level percentage */ if (_ups->UPS_Cap[CI_BATTLEV]) { answer = smart_poll(_ups->UPS_Cmd[CI_BATTLEV]); Dmsg(80, "Got CI_BATTLEV: %s\n", answer); _ups->BattChg = atof(answer); } /* BATT_VOLTAGE */ if (_ups->UPS_Cap[CI_VBATT]) { answer = smart_poll(_ups->UPS_Cmd[CI_VBATT]); Dmsg(80, "Got CI_VBATT: %s\n", answer); _ups->BattVoltage = atof(answer); } /* UPS_LOAD */ if (_ups->UPS_Cap[CI_LOAD]) { answer = smart_poll(_ups->UPS_Cmd[CI_LOAD]); Dmsg(80, "Got CI_LOAD: %s\n", answer); _ups->UPSLoad = atof(answer); } /* LINE_FREQ */ if (_ups->UPS_Cap[CI_FREQ]) { answer = smart_poll(_ups->UPS_Cmd[CI_FREQ]); Dmsg(80, "Got CI_FREQ: %s\n", answer); _ups->LineFreq = atof(answer); } /* UPS_RUNTIME_LEFT */ if (_ups->UPS_Cap[CI_RUNTIM]) { answer = smart_poll(_ups->UPS_Cmd[CI_RUNTIM]); Dmsg(80, "Got CI_RUNTIM: %s\n", answer); _ups->TimeLeft = atof(answer); } /* UPS_TEMP */ if (_ups->UPS_Cap[CI_ITEMP]) { answer = smart_poll(_ups->UPS_Cmd[CI_ITEMP]); Dmsg(80, "Got CI_ITEMP: %s\n", answer); _ups->UPSTemp = atof(answer); } /* DIP_SWITCH_SETTINGS */ if (_ups->UPS_Cap[CI_DIPSW]) { answer = smart_poll(_ups->UPS_Cmd[CI_DIPSW]); Dmsg(80, "Got CI_DIPSW: %s\n", answer); _ups->dipsw = strtoul(answer, NULL, 16); } /* Register 1 */ if (_ups->UPS_Cap[CI_REG1]) { answer = smart_poll(_ups->UPS_Cmd[CI_REG1]); Dmsg(80, "Got CI_REG1: %s\n", answer); _ups->reg1 = strtoul(answer, NULL, 16); } /* Register 2 */ if (_ups->UPS_Cap[CI_REG2]) { answer = smart_poll(_ups->UPS_Cmd[CI_REG2]); Dmsg(80, "Got CI_REG2: %s\n", answer); _ups->reg2 = strtoul(answer, NULL, 16); _ups->set_battpresent(!(_ups->reg2 & 0x20)); } /* Register 3 */ if (_ups->UPS_Cap[CI_REG3]) { answer = smart_poll(_ups->UPS_Cmd[CI_REG3]); Dmsg(80, "Got CI_REG3: %s\n", answer); _ups->reg3 = strtoul(answer, NULL, 16); } /* Humidity percentage */ if (_ups->UPS_Cap[CI_HUMID]) { answer = smart_poll(_ups->UPS_Cmd[CI_HUMID]); Dmsg(80, "Got CI_HUMID: %s\n", answer); _ups->humidity = atof(answer); } /* Ambient temperature */ if (_ups->UPS_Cap[CI_ATEMP]) { answer = smart_poll(_ups->UPS_Cmd[CI_ATEMP]); Dmsg(80, "Got CI_ATEMP: %s\n", answer); _ups->ambtemp = atof(answer); } /* Hours since self test */ if (_ups->UPS_Cap[CI_ST_TIME]) { answer = smart_poll(_ups->UPS_Cmd[CI_ST_TIME]); Dmsg(80, "Got CI_ST_TIME: %s\n", answer); _ups->LastSTTime = atof(answer); } smart_poll('Y'); smart_poll('Y'); write_unlock(_ups); return SUCCESS; } /********************************************************************* * * This subroutine is called to load our shared memory with * information that is static inside the UPS. Hence it * normally would only be called once when starting up the * UPS. */ bool ApcSmartUpsDriver::read_static_data() { char *answer; /* Everything from here on down is non-volitile, that is * we do not expect it to change while the UPS is running * unless we explicitly change it. */ /* SENSITIVITY */ if (_ups->UPS_Cap[CI_SENS]) { answer = smart_poll(_ups->UPS_Cmd[CI_SENS]); Dmsg(80, "Got CI_SENS: %s\n", answer); strlcpy(_ups->sensitivity, answer, sizeof(_ups->sensitivity)); } /* WAKEUP_DELAY */ if (_ups->UPS_Cap[CI_DWAKE]) { answer = smart_poll(_ups->UPS_Cmd[CI_DWAKE]); Dmsg(80, "Got CI_DWAKE: %s\n", answer); _ups->dwake = (int)atof(answer); } /* SLEEP_DELAY */ if (_ups->UPS_Cap[CI_DSHUTD]) { answer = smart_poll(_ups->UPS_Cmd[CI_DSHUTD]); Dmsg(80, "Got CI_DSHUTD: %s\n", answer); _ups->dshutd = (int)atof(answer); } /* LOW_TRANSFER_LEVEL */ if (_ups->UPS_Cap[CI_LTRANS]) { answer = smart_poll(_ups->UPS_Cmd[CI_LTRANS]); Dmsg(80, "Got CI_LTRANS: %s\n", answer); _ups->lotrans = (int)atof(answer); } /* HIGH_TRANSFER_LEVEL */ if (_ups->UPS_Cap[CI_HTRANS]) { answer = smart_poll(_ups->UPS_Cmd[CI_HTRANS]); Dmsg(80, "Got CI_HTRANS: %s\n", answer); _ups->hitrans = (int)atof(answer); } /* UPS_BATT_CAP_RETURN */ if (_ups->UPS_Cap[CI_RETPCT]) { answer = smart_poll(_ups->UPS_Cmd[CI_RETPCT]); Dmsg(80, "Got CI_RETPCT: %s\n", answer); _ups->rtnpct = (int)atof(answer); } /* ALARM_STATUS */ if (_ups->UPS_Cap[CI_DALARM]) { answer = smart_poll(_ups->UPS_Cmd[CI_DALARM]); Dmsg(80, "Got CI_DALARM: %s\n", answer); strlcpy(_ups->beepstate, answer, sizeof(_ups->beepstate)); } /* LOWBATT_SHUTDOWN_LEVEL */ if (_ups->UPS_Cap[CI_DLBATT]) { answer = smart_poll(_ups->UPS_Cmd[CI_DLBATT]); Dmsg(80, "Got CI_DLBATT: %s\n", answer); _ups->dlowbatt = (int)atof(answer); } /* UPS_NAME */ if (_ups->upsname[0] == 0 && _ups->UPS_Cap[CI_IDEN]) { answer = smart_poll(_ups->UPS_Cmd[CI_IDEN]); Dmsg(80, "Got CI_IDEN: %s\n", answer); strlcpy(_ups->upsname, answer, sizeof(_ups->upsname)); } /* UPS_SELFTEST */ if (_ups->UPS_Cap[CI_STESTI]) { answer = smart_poll(_ups->UPS_Cmd[CI_STESTI]); Dmsg(80, "Got CI_STESTI: %s\n", answer); strlcpy(_ups->selftest, answer, sizeof(_ups->selftest)); } /* UPS_MANUFACTURE_DATE */ if (_ups->UPS_Cap[CI_MANDAT]) { answer = smart_poll(_ups->UPS_Cmd[CI_MANDAT]); Dmsg(80, "Got CI_MANDAT: %s\n", answer); strlcpy(_ups->birth, answer, sizeof(_ups->birth)); } /* UPS_SERIAL_NUMBER */ if (_ups->UPS_Cap[CI_SERNO]) { answer = smart_poll(_ups->UPS_Cmd[CI_SERNO]); Dmsg(80, "Got CI_SERNO: %s\n", answer); strlcpy(_ups->serial, answer, sizeof(_ups->serial)); } /* UPS_BATTERY_REPLACE */ if (_ups->UPS_Cap[CI_BATTDAT]) { answer = smart_poll(_ups->UPS_Cmd[CI_BATTDAT]); Dmsg(80, "Got CI_BATTDAT: %s\n", answer); strlcpy(_ups->battdat, answer, sizeof(_ups->battdat)); } /* Nominal output voltage when on batteries */ if (_ups->UPS_Cap[CI_NOMOUTV]) { answer = smart_poll(_ups->UPS_Cmd[CI_NOMOUTV]); Dmsg(80, "Got CI_NOMOUTV: %s\n", answer); _ups->NomOutputVoltage = (int)atof(answer); } /* Nominal battery voltage */ if (_ups->UPS_Cap[CI_NOMBATTV]) { answer = smart_poll(_ups->UPS_Cmd[CI_NOMBATTV]); Dmsg(80, "Got CI_NOMBATTV: %s\n", answer); _ups->nombattv = atof(answer); } /* Firmware revision */ if (_ups->UPS_Cap[CI_REVNO]) { answer = smart_poll(_ups->UPS_Cmd[CI_REVNO]); Dmsg(80, "Got CI_REVNO: %s\n", answer); strlcpy(_ups->firmrev, answer, sizeof(_ups->firmrev)); } /* Number of external batteries installed */ if (_ups->UPS_Cap[CI_EXTBATTS]) { answer = smart_poll(_ups->UPS_Cmd[CI_EXTBATTS]); Dmsg(80, "Got CI_EXTBATTS: %s\n", answer); _ups->extbatts = (int)atof(answer); } /* Number of bad batteries installed */ if (_ups->UPS_Cap[CI_BADBATTS]) { answer = smart_poll(_ups->UPS_Cmd[CI_BADBATTS]); Dmsg(80, "Got CI_BADBATTS: %s\n", answer); _ups->badbatts = (int)atof(answer); } /* UPS model */ if (_ups->UPS_Cap[CI_UPSMODEL]) { answer = smart_poll(_ups->UPS_Cmd[CI_UPSMODEL]); if (_ups->UPS_Cmd[CI_UPSMODEL] == APC_CMD_OLDFWREV) { /* Derive UPS model from old fw rev */ strlcpy(_ups->upsmodel, get_model_from_oldfwrev(answer), sizeof(_ups->upsmodel)); } else { strlcpy(_ups->upsmodel, answer, sizeof(_ups->upsmodel)); } Dmsg(80, "Got CI_UPSMODEL: %s\n", _ups->upsmodel); } /* EPROM Capabilities */ if (_ups->UPS_Cap[CI_EPROM]) { answer = smart_poll(_ups->UPS_Cmd[CI_EPROM]); Dmsg(80, "Got CI_EPROM: %s\n", answer); strlcpy(_ups->eprom, answer, sizeof(_ups->eprom)); } return SUCCESS; } bool ApcSmartUpsDriver::entry_point(int command, void *data) { int retries = 5; /* Number of retries if reason is NA (see below) */ char ans[20]; switch (command) { case DEVICE_CMD_SET_DUMB_MODE: /* Set dumb mode for a smart UPS */ write(_ups->fd, "R", 1); /* enter dumb mode */ *ans = 0; getline(ans, sizeof(ans)); printf("Going dumb: %s\n", ans); break; case DEVICE_CMD_GET_SELFTEST_MSG: /* Results of last self test */ if (_ups->UPS_Cap[CI_ST_STAT]) { _ups->testresult = decode_testresult( smart_poll(_ups->UPS_Cmd[CI_ST_STAT])); } break; case DEVICE_CMD_CHECK_SELFTEST: Dmsg(80, "Checking self test.\n"); /* * XXX * * One day we will do this test inside the driver and not as an * entry point. */ /* Reason for last transfer to batteries */ if (_ups->UPS_Cap[CI_WHY_BATT]) { _ups->lastxfer = XFER_NA; while (_ups->lastxfer == XFER_NA && retries--) { _ups->lastxfer = decode_lastxfer( smart_poll(_ups->UPS_Cmd[CI_WHY_BATT])); if (_ups->lastxfer == XFER_NA) { Dmsg(80, "Transfer reason still not available.\n"); if (retries > 0) sleep(2); /* debounce */ /* * Be careful because if we go out of here without * knowing the reason of transfer (i.e. the reason * is "NA", apcupsd will think this is a power failure * even if it is a self test. Not much of a problem * as this should not happen. * We allow 5 retries for reading reason from UPS before * giving up. */ } else if (_ups->lastxfer == XFER_SELFTEST) { _ups->SelfTest = time(NULL); Dmsg(80, "Self Test time: %s", ctime(&_ups->SelfTest)); } } } break; default: return FAILURE; break; } return SUCCESS; } apcupsd-3.14.14/src/drivers/apcsmart/smarteeprom.c000066400000000000000000000361661274230402600221200ustar00rootroot00000000000000/* * apceeprom.c * * Do APC EEPROM changes. */ /* * Copyright (C) 2000-2004 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "apcsmart.h" /*********************************************************************/ bool ApcSmartUpsDriver::program_eeprom(int command, const char *data) { char setting[20]; setup(); get_capabilities(); switch (command) { case CI_BATTDAT: /* change battery date */ if (_ups->UPS_Cap[CI_BATTDAT]) { printf("Attempting to update UPS battery date ...\n"); change_ups_battery_date(data); } else { printf("UPS battery date configuration not supported by this UPS.\n"); return 0; } break; case CI_IDEN: if (_ups->UPS_Cap[CI_IDEN]) { printf("Attempting to rename UPS ...\n"); change_ups_name(data); } else { printf("UPS name configuration not supported by this UPS.\n"); return 0; } break; /* SENSITIVITY */ case CI_SENS: if (_ups->UPS_Cap[CI_SENS]) { asnprintf(setting, sizeof(setting), "%.1s", data); change_ups_eeprom_item("sensitivity", _ups->UPS_Cmd[CI_SENS], setting); } else { printf("UPS sensitivity configuration not supported by this UPS.\n"); return 0; } break; /* ALARM_STATUS */ case CI_DALARM: if (_ups->UPS_Cap[CI_DALARM]) { asnprintf(setting, sizeof(setting), "%.1s", data); change_ups_eeprom_item("alarm status", _ups->UPS_Cmd[CI_DALARM], setting); } else { printf("UPS alarm status configuration not supported by this UPS.\n"); return 0; } break; /* LOWBATT_SHUTDOWN_LEVEL */ case CI_DLBATT: if (_ups->UPS_Cap[CI_DLBATT]) { asnprintf(setting, sizeof(setting), "%02d", (int)atoi(data)); change_ups_eeprom_item("low battery warning delay", _ups->UPS_Cmd[CI_DLBATT], setting); } else { printf( "UPS low battery warning configuration not supported by this UPS.\n"); return 0; } break; /* WAKEUP_DELAY */ case CI_DWAKE: if (_ups->UPS_Cap[CI_DWAKE]) { asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data)); change_ups_eeprom_item("wakeup delay", _ups->UPS_Cmd[CI_DWAKE], setting); } else { printf("UPS wakeup delay configuration not supported by this UPS.\n"); return 0; } break; /* SLEEP_DELAY */ case CI_DSHUTD: if (_ups->UPS_Cap[CI_DSHUTD]) { asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data)); change_ups_eeprom_item("shutdown delay", _ups->UPS_Cmd[CI_DSHUTD], setting); } else { printf("UPS shutdown delay configuration not supported by this UPS.\n"); return 0; } break; /* LOW_TRANSFER_LEVEL */ case CI_LTRANS: if (_ups->UPS_Cap[CI_LTRANS]) { asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data)); change_ups_eeprom_item("lower transfer voltage", _ups->UPS_Cmd[CI_LTRANS], setting); } else { printf( "UPS low transfer voltage configuration not supported by this UPS.\n"); return 0; } break; /* HIGH_TRANSFER_LEVEL */ case CI_HTRANS: if (_ups->UPS_Cap[CI_HTRANS]) { asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data)); change_ups_eeprom_item("high transfer voltage", _ups->UPS_Cmd[CI_HTRANS], setting); } else { printf( "UPS high transfer voltage configuration not supported by this UPS.\n"); return 0; } break; /* UPS_BATT_CAP_RETURN */ case CI_RETPCT: if (_ups->UPS_Cap[CI_RETPCT]) { asnprintf(setting, sizeof(setting), "%02d", (int)atoi(data)); change_ups_eeprom_item("return threshold percent", _ups->UPS_Cmd[CI_RETPCT], setting); } else { printf( "UPS return threshold configuration not supported by this UPS.\n"); return 0; } break; /* UPS_SELFTEST */ case CI_STESTI: if (_ups->UPS_Cap[CI_STESTI]) { asnprintf(setting, sizeof(setting), "%.3s", data); /* Make sure "ON" is 3 characters */ if (setting[2] == 0) { setting[2] = ' '; setting[3] = 0; } change_ups_eeprom_item("self test interval", _ups->UPS_Cmd[CI_STESTI], setting); } else { printf( "UPS self test interval configuration not supported by this UPS.\n"); return 0; } break; /* OUTPUT_VOLTAGE */ case CI_NOMOUTV: if (_ups->UPS_Cap[CI_NOMOUTV]) { asnprintf(setting, sizeof(setting), "%03d", (int)atoi(data)); change_ups_eeprom_item("output voltage on batteries", _ups->UPS_Cmd[CI_NOMOUTV], setting); } else { printf( "UPS output voltage on batteries configuration not supported by this UPS.\n"); return 0; } break; case -1: /* old style from .conf file */ printf("Attempting to configure UPS ...\n"); change_extended(); /* set new values in UPS */ printf("\nReading updated UPS configuration ...\n\n"); read_volatile_data(); read_static_data(); /* Print report of status */ output_status(_ups, 0, stat_open, stat_print, stat_close); break; default: printf("Ignoring unknown config request command=%d\n", command); return 0; break; } return 1; } /*********************************************************************/ void ApcSmartUpsDriver::change_ups_name(const char *newname) { char *n; char response[32]; char name[10]; char a = _ups->UPS_Cmd[CI_CYCLE_EPROM]; char c = _ups->UPS_Cmd[CI_IDEN]; int i; int j = strlen(newname); name[0] = '\0'; if (j == 0) { fprintf(stderr, "Error, new name of zero length.\n"); return; } else if (j > 8) { j = 8; /* maximum size */ } strncpy(name, newname, 9); /* blank fill to 8 chars */ while (j < 8) { name[j] = ' '; j++; } /* Ask for name */ write(_ups->fd, &c, 1); /* c = 'c' */ getline(response, sizeof(response)); fprintf(stderr, "The old UPS name is: %s\n", response); /* Tell UPS we will change name */ write(_ups->fd, &a, 1); /* a = '-' */ sleep(1); n = name; for (i = 0; i < 8; i++) { write(_ups->fd, n++, 1); sleep(1); } /* Expect OK after successful name change */ *response = 0; getline(response, sizeof(response)); if (strcmp(response, "OK") != 0) { fprintf(stderr, "\nError changing UPS name\n"); } _ups->upsname[0] = '\0'; smart_poll(_ups->UPS_Cmd[CI_IDEN]); strlcpy(_ups->upsname, smart_poll(_ups->UPS_Cmd[CI_IDEN]), sizeof(_ups->upsname)); fprintf(stderr, "The new UPS name is: %s\n", _ups->upsname); } /* * Update date battery replaced */ void ApcSmartUpsDriver::change_ups_battery_date(const char *newdate) { char *n; char response[32]; char battdat[9]; char a = _ups->UPS_Cmd[CI_CYCLE_EPROM]; char c = _ups->UPS_Cmd[CI_BATTDAT]; int i; int j = strlen(newdate); battdat[0] = '\0'; if (j != 8) { fprintf(stderr, "Error, new battery date must be 8 characters long.\n"); return; } strlcpy(battdat, newdate, sizeof(battdat)); /* Ask for battdat */ write(_ups->fd, &c, 1); /* c = 'x' */ getline(response, sizeof(response)); fprintf(stderr, "The old UPS battery date is: %s\n", response); /* Tell UPS we will change battdat */ write(_ups->fd, &a, 1); /* a = '-' */ sleep(1); n = battdat; for (i = 0; i < 8; i++) { write(_ups->fd, n++, 1); sleep(1); } /* Expect OK after successful battdat change */ *response = 0; getline(response, sizeof(response)); if (strcmp(response, "OK") != 0) { fprintf(stderr, "\nError changing UPS battery date\n"); } _ups->battdat[0] = '\0'; smart_poll(_ups->UPS_Cmd[CI_BATTDAT]); strlcpy(_ups->battdat, smart_poll(_ups->UPS_Cmd[CI_BATTDAT]), sizeof(_ups->battdat)); fprintf(stderr, "The new UPS battery date is: %s\n", _ups->battdat); } /*********************************************************************/ int ApcSmartUpsDriver::change_ups_eeprom_item(const char *title, const char cmd, const char *setting) { char response[32]; char response1[32]; char oldvalue[32]; char lastvalue[32]; char allvalues[256]; char a = _ups->UPS_Cmd[CI_CYCLE_EPROM]; int i; /* Ask for old value */ write(_ups->fd, &cmd, 1); if (getline(oldvalue, sizeof(oldvalue)) == FAILURE) { fprintf(stderr, "Could not get old value of %s.\n", title); return FAILURE; } if (strcmp(oldvalue, setting) == 0) { fprintf(stderr, "The UPS %s remains unchanged as: %s\n", title, oldvalue); return SUCCESS; } fprintf(stderr, "The old UPS %s is: %s\n", title, oldvalue); strlcpy(allvalues, oldvalue, sizeof(allvalues)); strlcat(allvalues, " ", sizeof(allvalues)); strlcpy(lastvalue, oldvalue, sizeof(lastvalue)); /* Try a second time to ensure that it is a stable value */ write(_ups->fd, &cmd, 1); *response = 0; getline(response, sizeof(response)); if (strcmp(oldvalue, response) != 0) { fprintf(stderr, "\nEEPROM value of %s is not stable\n", title); return FAILURE; } /* * Just before entering this loop, the last command sent * to the UPS MUST be to query the old value. */ for (i = 0; i < 10; i++) { write(_ups->fd, &cmd, 1); getline(response1, sizeof(response1)); /* Tell UPS to cycle to next value */ write(_ups->fd, &a, 1); /* a = '-' */ /* Expect OK after successful change */ *response = 0; getline(response, sizeof(response)); if (strcmp(response, "OK") != 0) { fprintf(stderr, "\nError changing UPS %s\n", title); fprintf(stderr, "Got %s instead of OK\n\n", response); sleep(10); return FAILURE; } /* get cycled value */ write(_ups->fd, &cmd, 1); getline(response1, sizeof(response1)); /* get cycled value again */ write(_ups->fd, &cmd, 1); if (getline(response, sizeof(response)) == FAILURE || strcmp(response1, response) != 0) { fprintf(stderr, "Error cycling values.\n"); getline(response, sizeof(response)); /* eat any garbage */ return FAILURE; } if (strcmp(setting, response) == 0) { fprintf(stderr, "The new UPS %s is: %s\n", title, response); sleep(10); /* allow things to settle down */ return SUCCESS; } /* * Check if we cycled back to the same value, but permit * a duplicate because the L for sensitivy appears * twice in a row, i.e. H M L L. */ if (strcmp(oldvalue, response) == 0 && i > 0) break; if (strcmp(lastvalue, response) != 0) { strlcat(allvalues, response, sizeof(allvalues)); strlcat(allvalues, " ", sizeof(allvalues)); strlcpy(lastvalue, response, sizeof(lastvalue)); } sleep(5); /* don't cycle too fast */ } fprintf(stderr, "Unable to change %s to: %s\n", title, setting); fprintf(stderr, "Permitted values are: %s\n", allvalues); getline(response, sizeof(response)); /* eat any garbage */ return FAILURE; } /* * Set new values in EEPROM memmory. Change the UPS EEPROM. */ void ApcSmartUpsDriver::change_extended() { char setting[20]; get_capabilities(); /* * Note, a value of -1 in the variable at the beginning * means that the user did not put a configuration directive * in /etc/apcupsd/apcupsd.conf. Consequently, if no value * was given, we won't attept to change it. */ /* SENSITIVITY */ if (_ups->UPS_Cap[CI_SENS] && strcmp(_ups->sensitivity, "-1") != 0) { asnprintf(setting, sizeof(setting), "%.1s", _ups->sensitivity); change_ups_eeprom_item("sensitivity", _ups->UPS_Cmd[CI_SENS], setting); } /* WAKEUP_DELAY */ if (_ups->UPS_Cap[CI_DWAKE] && _ups->dwake != -1) { asnprintf(setting, sizeof(setting), "%03d", (int)_ups->dwake); change_ups_eeprom_item("wakeup delay", _ups->UPS_Cmd[CI_DWAKE], setting); } /* SLEEP_DELAY */ if (_ups->UPS_Cap[CI_DSHUTD] && _ups->dshutd != -1) { asnprintf(setting, sizeof(setting), "%03d", (int)_ups->dshutd); change_ups_eeprom_item("shutdown delay", _ups->UPS_Cmd[CI_DSHUTD], setting); } /* LOW_TRANSFER_LEVEL */ if (_ups->UPS_Cap[CI_LTRANS] && _ups->lotrans != -1) { asnprintf(setting, sizeof(setting), "%03d", (int)_ups->lotrans); change_ups_eeprom_item("lower transfer voltage", _ups->UPS_Cmd[CI_LTRANS], setting); } /* HIGH_TRANSFER_LEVEL */ if (_ups->UPS_Cap[CI_HTRANS] && _ups->hitrans != -1) { asnprintf(setting, sizeof(setting), "%03d", (int)_ups->hitrans); change_ups_eeprom_item("upper transfer voltage", _ups->UPS_Cmd[CI_HTRANS], setting); } /* UPS_BATT_CAP_RETURN */ if (_ups->UPS_Cap[CI_RETPCT] && _ups->rtnpct != -1) { asnprintf(setting, sizeof(setting), "%02d", (int)_ups->rtnpct); change_ups_eeprom_item("return threshold percent", _ups->UPS_Cmd[CI_RETPCT], setting); } /* ALARM_STATUS */ if (_ups->UPS_Cap[CI_DALARM] && strcmp(_ups->beepstate, "-1") != 0) { asnprintf(setting, sizeof(setting), "%.1s", _ups->beepstate); change_ups_eeprom_item("alarm delay", _ups->UPS_Cmd[CI_DALARM], setting); } /* LOWBATT_SHUTDOWN_LEVEL */ if (_ups->UPS_Cap[CI_DLBATT] && _ups->dlowbatt != -1) { asnprintf(setting, sizeof(setting), "%02d", (int)_ups->dlowbatt); change_ups_eeprom_item("low battery warning delay", _ups->UPS_Cmd[CI_DLBATT], setting); } /* UPS_SELFTEST */ if (_ups->UPS_Cap[CI_STESTI] && strcmp(_ups->selftest, "-1") != 0) { asnprintf(setting, sizeof(setting), "%.3s", _ups->selftest); /* Make sure "ON" is 3 characters */ if (setting[2] == 0) { setting[2] = ' '; setting[3] = 0; } change_ups_eeprom_item( "self test interval", _ups->UPS_Cmd[CI_STESTI], setting); } /* OUTPUT_VOLTAGE */ if (_ups->UPS_Cap[CI_NOMOUTV] && _ups->NomOutputVoltage != -1) { asnprintf(setting, sizeof(setting), "%03d", (int)_ups->NomOutputVoltage); change_ups_eeprom_item("output voltage on batteries", _ups->UPS_Cmd[CI_NOMOUTV], setting); } } apcupsd-3.14.14/src/drivers/apcsmart/smartoper.c000066400000000000000000000100601274230402600215570ustar00rootroot00000000000000/* * smartoper.c * * Functions for SmartUPS operations */ /* * Copyright (C) 2001-2004 Kern Sibbald * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 1999-2001 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "apcsmart.h" bool ApcSmartUpsDriver::kill_power() { char response[32] = {0}; int shutdown_delay = apcsmart_ups_get_shutdown_delay(); // Ask for soft shutdown writechar('S'); // Check whether the UPS has acknowledged the power-off command. // The command only succeeds if UPS was on battery. sleep(5); getline(response, sizeof response); if (strcmp(response, "OK") == 0 || (strcmp(response, "*") == 0)) goto acked; // 'S' command failed, most likely because utility power was restored. // We still need to power cycle the UPS however since the OS has been // shut down already. We will issue the shutdown-and-return command // '@000' which works even if UPS is online. // Experiments show that the UPS needs delays between chars // to accept this command. Old code is written to send 2 zeros // first, check for a response, and then send a third zero if // command needs it. I've never seen an UPS that needs only 2 zeros // but apparently someone did, so code is preserved. writechar('@'); /* Shutdown now, try two 0s first */ sleep(2); writechar('0'); sleep(2); writechar('0'); sleep(2); getline(response, sizeof(response)); if ((strcmp(response, "OK") == 0) || (strcmp(response, "*") == 0)) goto acked; writechar('0'); sleep(2); getline(response, sizeof(response)); if ((strcmp(response, "OK") == 0) || (strcmp(response, "*") == 0)) goto acked; // Both shutdown techniques failed. We have one more we can try, but // UPS will power off and stay off in this case. return apcsmart_ups_shutdown_with_delay(shutdown_delay); acked: // Shutdown command was accepted apcsmart_ups_warn_shutdown(shutdown_delay); return 1; } bool ApcSmartUpsDriver::shutdown() { return apcsmart_ups_shutdown_with_delay(apcsmart_ups_get_shutdown_delay()); } int ApcSmartUpsDriver::apcsmart_ups_shutdown_with_delay(int shutdown_delay) { char response[32]; /* * K K command * * This method should turn the UPS off completely according to this article: * http://nam-en.apc.com/cgi-bin/nam_en.cfg/php/enduser/std_adp.php?p_faqid=604 */ writechar('K'); sleep(2); writechar('K'); getline(response, sizeof response); if (strcmp(response, "*") != 0 && strcmp(response, "OK") != 0) { log_event(_ups, LOG_WARNING, "Failed to issue shutdown command!\n"); return 0; } apcsmart_ups_warn_shutdown(shutdown_delay); return 1; } void ApcSmartUpsDriver::apcsmart_ups_warn_shutdown(int shutdown_delay) { if (shutdown_delay > 0) { log_event(_ups, LOG_WARNING, "UPS will power off after %d seconds ...\n", shutdown_delay); } else { log_event(_ups, LOG_WARNING, "UPS will power off after the configured delay ...\n"); } log_event(_ups, LOG_WARNING, "Please power off your UPS before rebooting your computer ...\n"); } int ApcSmartUpsDriver::apcsmart_ups_get_shutdown_delay() { char response[32]; writechar(_ups->UPS_Cmd[CI_DSHUTD]); getline(response, sizeof(response)); return (int)atof(response); } bool ApcSmartUpsDriver::check_state() { return getline(NULL, 0) == SUCCESS ? 1 : 0; } apcupsd-3.14.14/src/drivers/apcsmart/smartsetup.c000066400000000000000000000110701274230402600217540ustar00rootroot00000000000000/* * smartrsetup.c * * Functions to open/setup/close the device */ /* * Copyright (C) 2001-2004 Kern Sibbald * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 1999-2001 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "apcsmart.h" /* Win32 needs O_BINARY; sane platforms have never heard of it */ #ifndef O_BINARY #define O_BINARY 0 #endif /* * This is the first routine in the driver that is called. */ bool ApcSmartUpsDriver::Open() { int cmd; char *opendev = _ups->device; #ifdef HAVE_MINGW // On Win32 add \\.\ UNC prefix to COMx in order to correctly address // ports >= COM10. char device[MAXSTRING]; if (!strnicmp(_ups->device, "COM", 3)) { snprintf(device, sizeof(device), "\\\\.\\%s", _ups->device); opendev = device; } #endif Dmsg(50, "Opening port %s\n", opendev); if ((_ups->fd = open(opendev, O_RDWR | O_NOCTTY | O_NDELAY | O_BINARY | O_CLOEXEC)) < 0) { Dmsg(50, "Cannot open UPS port %s: %s\n", opendev, strerror(errno)); return false; } /* Cancel the no delay we just set */ cmd = fcntl(_ups->fd, F_GETFL, 0); fcntl(_ups->fd, F_SETFL, cmd & ~O_NDELAY); /* Save old settings */ tcgetattr(_ups->fd, &_oldtio); _newtio.c_cflag = DEFAULT_SPEED | CS8 | CLOCAL | CREAD; _newtio.c_iflag = IGNPAR; /* Ignore errors, raw input */ _newtio.c_oflag = 0; /* Raw output */ _newtio.c_lflag = 0; /* No local echo */ #if defined(HAVE_OPENBSD_OS) || \ defined(HAVE_FREEBSD_OS) || \ defined(HAVE_NETBSD_OS) || \ defined(HAVE_QNX_OS) _newtio.c_ispeed = DEFAULT_SPEED; /* Set input speed */ _newtio.c_ospeed = DEFAULT_SPEED; /* Set output speed */ #endif /* __openbsd__ || __freebsd__ || __netbsd__ */ /* This makes a non.blocking read() with TIMER_READ (10) sec. timeout */ _newtio.c_cc[VMIN] = 0; _newtio.c_cc[VTIME] = TIMER_READ * 10; #if defined(HAVE_OSF1_OS) || \ defined(HAVE_LINUX_OS) || defined(HAVE_DARWIN_OS) (void)cfsetospeed(&_newtio, DEFAULT_SPEED); (void)cfsetispeed(&_newtio, DEFAULT_SPEED); #endif /* do it the POSIX way */ tcflush(_ups->fd, TCIFLUSH); tcsetattr(_ups->fd, TCSANOW, &_newtio); tcflush(_ups->fd, TCIFLUSH); return 1; } /* * This routine is the last one called before apcupsd * terminates. */ bool ApcSmartUpsDriver::Close() { /* Reset serial line to old values */ if (_ups->fd >= 0) { Dmsg(50, "Closing port\n"); tcflush(_ups->fd, TCIFLUSH); tcsetattr(_ups->fd, TCSANOW, &_oldtio); tcflush(_ups->fd, TCIFLUSH); close(_ups->fd); } _ups->fd = -1; return 1; } bool ApcSmartUpsDriver::setup() { int attempts; int rts_bit = TIOCM_RTS; char a = 'Y'; if (_ups->fd == -1) return 1; /* we must be a slave */ /* Have to clear RTS line to access the serial cable mode PnP on BKPro */ /* Shouldn't hurt on other cables, so just do it all the time. */ ioctl(_ups->fd, TIOCMBIC, &rts_bit); write(_ups->fd, &a, 1); /* This one might not work, if UPS is */ sleep(1); /* in an unstable communication state */ tcflush(_ups->fd, TCIOFLUSH); /* Discard UPS's response, if any */ /* * Don't use smart_poll here because it may loop waiting * on the serial port, and here we may be called before * we are a deamon, so we want to error after a reasonable * time. */ for (attempts = 0; attempts < 5; attempts++) { char answer[10]; *answer = 0; write(_ups->fd, &a, 1); /* enter smart mode */ getline(answer, sizeof(answer)); if (strcmp("SM", answer) == 0) goto out; sleep(1); } Error_abort( "PANIC! Cannot communicate with UPS via serial port.\n" "Please make sure the port specified on the DEVICE directive is correct,\n" "and that your cable specification on the UPSCABLE directive is correct.\n"); out: return 1; } apcupsd-3.14.14/src/drivers/apcsmart/smartsetup2.c000066400000000000000000000113321274230402600220370ustar00rootroot00000000000000/* * smartsetup2.c * * UPS capability discovery for SmartUPS models. */ /* * Copyright (C) 1996-99 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "apcsmart.h" /*********************************************************************/ const char *ApcSmartUpsDriver::get_model_from_oldfwrev(const char *s) { switch (s[0]) { case '0': return ("APC Matrix-UPS 3000"); case '2': return ("APC Smart-UPS 250"); case '3': return ("APC Smart-UPS 370ci"); case '4': return ("APC Smart-UPS 400"); case '5': return ("APC Matrix-UPS 5000"); case '6': return ("APC Smart-UPS 600"); case '7': return ("APC Smart-UPS 900"); case '8': return ("APC Smart-UPS 1250"); case '9': return ("APC Smart-UPS 2000"); case 'A': return ("APC Smart-UPS 1400"); case 'B': return ("APC Smart-UPS 1000"); case 'C': return ("APC Smart-UPS 650"); case 'D': return ("APC Smart-UPS 420"); case 'E': return ("APC Smart-UPS 280"); case 'F': return ("APC Smart-UPS 450"); case 'G': return ("APC Smart-UPS 700"); case 'H': return ("APC Smart-UPS 700 XL"); case 'I': return ("APC Smart-UPS 1000"); case 'J': return ("APC Smart-UPS 1000 XL"); case 'K': return ("APC Smart-UPS 1400"); case 'L': return ("APC Smart-UPS 1400 XL"); case 'M': return ("APC Smart-UPS 2200"); case 'N': return ("APC Smart-UPS 2200 XL"); case 'O': return ("APC Smart-UPS 5000"); case 'P': return ("APC Smart-UPS 3000"); } return "Unknown"; } /* * This subroutine polls the APC Smart UPS to find out * what capabilities it has. */ bool ApcSmartUpsDriver::get_capabilities() { char answer[1000]; /* keep this big to handle big string */ char caps[1000], *cmds, *p; int i; write_lock(_ups); /* Get UPS capabilities string */ strlcpy(caps, smart_poll(_ups->UPS_Cmd[CI_UPS_CAPS]), sizeof(caps)); if (strlen(caps) && (strcmp(caps, "NA") != 0)) { _ups->UPS_Cap[CI_UPS_CAPS] = TRUE; /* skip version */ for (p = caps; *p && *p != '.'; p++) ; /* skip alert characters */ for (; *p && *p != '.'; p++) ; cmds = p; /* point to commands */ if (!*cmds) { /* oops, none */ cmds = NULL; _ups->UPS_Cap[CI_UPS_CAPS] = FALSE; } } else { cmds = NULL; /* No commands string */ } /* * Try all the possible UPS capabilities and mark the ones supported. * If we can get the eprom caps list, use them to jump over the * unsupported caps, if we can't get the cap list try every known * capability. */ for (i = 0; i <= CI_MAX_CAPS; i++) { if (_ups->UPS_Cmd[i] == 0) continue; if (!cmds || strchr(cmds, _ups->UPS_Cmd[i]) != NULL) { strlcpy(answer, smart_poll(_ups->UPS_Cmd[i]), sizeof(answer)); if (*answer && (strcmp(answer, "NA") != 0)) { _ups->UPS_Cap[i] = true; } } } /* * If UPS did not support APC_CMD_UPSMODEL (the default comand for * CI_UPSMODEL), maybe it supports APC_CMD_OLDFWREV which can be used to * construct the model number. */ if (!_ups->UPS_Cap[CI_UPSMODEL] && (!cmds || strchr(cmds, APC_CMD_OLDFWREV) != NULL)) { strlcpy(answer, smart_poll(APC_CMD_OLDFWREV), sizeof(answer)); if (*answer && (strcmp(answer, "NA") != 0)) { _ups->UPS_Cap[CI_UPSMODEL] = true; _ups->UPS_Cmd[CI_UPSMODEL] = APC_CMD_OLDFWREV; } } /* * If UPS does not support APC_CMD_REVNO (the default command for CI_REVNO), * maybe it supports APC_CMD_OLDFWREV instead. */ if (!_ups->UPS_Cap[CI_REVNO] && (!cmds || strchr(cmds, APC_CMD_OLDFWREV) != NULL)) { strlcpy(answer, smart_poll(APC_CMD_OLDFWREV), sizeof(answer)); if (*answer && (strcmp(answer, "NA") != 0)) { _ups->UPS_Cap[CI_REVNO] = true; _ups->UPS_Cmd[CI_REVNO] = APC_CMD_OLDFWREV; } } write_unlock(_ups); return 1; } apcupsd-3.14.14/src/drivers/drivers.c000066400000000000000000000104701274230402600174140ustar00rootroot00000000000000/* * drivers.c * * UPS drivers middle (link) layer. */ /* * Copyright (C) 2001-2006 Kern Sibbald * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 1999-2001 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #ifdef HAVE_DUMB_DRIVER # include "dumb/dumb.h" #endif #ifdef HAVE_APCSMART_DRIVER # include "apcsmart/apcsmart.h" #endif #ifdef HAVE_NET_DRIVER # include "net/net.h" #endif #ifdef HAVE_USB_DRIVER # include "usb/usb.h" #endif #ifdef HAVE_SNMPLITE_DRIVER # include "snmplite/snmplite.h" #endif #ifdef HAVE_TEST_DRIVER # include "test/testdriver.h" #endif #ifdef HAVE_PCNET_DRIVER # include "pcnet/pcnet.h" #endif #ifdef HAVE_MODBUS_DRIVER # include "modbus/modbus.h" #endif static const UPSDRIVER drivers[] = { #ifdef HAVE_DUMB_DRIVER { "dumb", DumbUpsDriver::Factory }, #endif /* HAVE_DUMB_DRIVER */ #ifdef HAVE_APCSMART_DRIVER { "apcsmart", ApcSmartUpsDriver::Factory }, #endif /* HAVE_APCSMART_DRIVER */ #ifdef HAVE_NET_DRIVER { "net", NetUpsDriver::Factory }, #endif /* HAVE_NET_DRIVER */ #ifdef HAVE_USB_DRIVER { "usb", UsbUpsDriver::Factory }, #endif /* HAVE_USB_DRIVER */ #ifdef HAVE_SNMPLITE_DRIVER { "snmplite", SnmpLiteUpsDriver::Factory }, #endif /* HAVE_SNMPLITE_DRIVER */ #ifdef HAVE_TEST_DRIVER { "test", TestUpsDriver::Factory }, #endif /* HAVE_TEST_DRIVER */ #ifdef HAVE_PCNET_DRIVER { "pcnet", PcnetUpsDriver::Factory }, #endif /* HAVE_PCNET_DRIVER */ #ifdef HAVE_MODBUS_DRIVER { "modbus", ModbusUpsDriver::Factory }, #endif /* HAVE_MODBUS_DRIVER */ /* * The NULL driver: closes the drivers list. */ { NULL, NULL } }; /* * This is the glue between UPSDRIVER and UPSINFO. * It returns an UPSDRIVER pointer that may be null if something * went wrong. */ static UpsDriver *helper_attach_driver(UPSINFO *ups, const char *drvname) { int i; write_lock(ups); Dmsg(99, "Looking for driver: %s\n", drvname); ups->driver = NULL; for (i = 0; drivers[i].driver_name; i++) { Dmsg(99, "Driver %s is configured.\n", drivers[i].driver_name); if (strcasecmp(drivers[i].driver_name, drvname) == 0) { ups->driver = drivers[i].factory(ups); Dmsg(20, "Driver %s found and attached.\n", drivers[i].driver_name); break; } } if (!ups->driver) { printf("\nApcupsd driver %s not found.\n" "The available apcupsd drivers are:\n", drvname); for (i = 0; drivers[i].driver_name; i++) printf("%s\n", drivers[i].driver_name); printf("\n"); printf("Most likely, you need to add --enable-%s " "to your ./configure options.\n\n", drvname); } write_unlock(ups); Dmsg(99, "Driver ptr=0x%x\n", ups->driver); Dmsg(10, "Attached to driver: %s\n", drivers[i].driver_name); return ups->driver; } UpsDriver *attach_driver(UPSINFO *ups) { const char *driver_name = NULL; /* Attach the correct driver. */ switch (ups->mode.type) { case DUMB_UPS: driver_name = "dumb"; break; case APCSMART_UPS: driver_name = "apcsmart"; break; case USB_UPS: driver_name = "usb"; break; case SNMPLITE_UPS: driver_name = "snmplite"; break; case TEST_UPS: driver_name = "test"; break; case NETWORK_UPS: driver_name = "net"; break; case PCNET_UPS: driver_name = "pcnet"; break; case MODBUS_UPS: driver_name = "modbus"; break; default: case NO_UPS: Dmsg(000, "Warning: no UPS driver found (ups->mode.type=%d).\n", ups->mode.type); break; } return driver_name ? helper_attach_driver(ups, driver_name) : NULL; } apcupsd-3.14.14/src/drivers/dumb/000077500000000000000000000000001274230402600165175ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/dumb/Makefile000066400000000000000000000002671274230402600201640ustar00rootroot00000000000000topdir:=../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) all-targets: libdumbdrv.a libdumbdrv.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/dumb/dumb.h000066400000000000000000000026731274230402600176270ustar00rootroot00000000000000/* * dumb.h * * Public header file for the simple-signalling (aka "dumb") driver */ /* * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _DUMB_H #define _DUMB_H class DumbUpsDriver: public UpsDriver { public: DumbUpsDriver(UPSINFO *ups); virtual ~DumbUpsDriver() {} static UpsDriver *Factory(UPSINFO *ups) { return new DumbUpsDriver(ups); } virtual bool get_capabilities(); virtual bool read_volatile_data(); virtual bool read_static_data(); virtual bool kill_power(); virtual bool check_state() { return read_volatile_data(); } virtual bool Open(); virtual bool Close(); virtual bool setup(); virtual bool entry_point(int command, void *data); private: int _sp_flags; /* Serial port flags */ struct termios _oldtio; struct termios _newtio; }; #endif /* _DUMB_H */ apcupsd-3.14.14/src/drivers/dumb/dumboper.c000066400000000000000000000144051274230402600205040ustar00rootroot00000000000000/* * dumboper.c * * Functions for simple-signalling (dumb) UPS operations */ /* * Copyright (C) 1999-2001 Riccardo Facchetti * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 1999-2001 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "dumb.h" bool DumbUpsDriver::kill_power() { int serial_bits = 0; switch (_ups->cable.type) { case CUSTOM_SIMPLE: /* killpwr_bit */ case APC_940_0095A: case APC_940_0095B: case APC_940_0095C: /* killpwr_bit */ serial_bits = TIOCM_RTS; (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); sleep(10); /* hold for 10 seconds */ serial_bits = TIOCM_ST; (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); break; case APC_940_0119A: case APC_940_0127A: case APC_940_0128A: case APC_940_0020B: /* killpwr_bit */ case APC_940_0020C: serial_bits = TIOCM_DTR; (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); sleep(10); /* hold for at least 10 seconds */ break; case APC_940_0023A: /* killpwr_bit */ break; case MAM_CABLE: serial_bits = TIOCM_RTS; (void)ioctl(_ups->fd, TIOCMBIC, &serial_bits); serial_bits = TIOCM_DTR; (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); sleep(10); /* hold */ break; } return 1; } /* * Dumb UPSes don't have static UPS data. */ bool DumbUpsDriver::read_static_data() { return 1; } /* * Set capabilities. */ bool DumbUpsDriver::get_capabilities() { /* We create a Status word */ _ups->UPS_Cap[CI_STATUS] = TRUE; return 1; } /* * dumb_ups_check_state is the same as dumb_read_ups_volatile_data * because this is the only info we can get from UPS. * * This routine is polled. We should sleep at least 5 seconds * unless we are in a FastPoll situation, otherwise, we burn * too much CPU. */ bool DumbUpsDriver::read_volatile_data() { int stat = 1; /* * We generally poll a bit faster because we do * not have interrupts like the smarter devices */ if (_ups->wait_time > TIMER_DUMB) _ups->wait_time = TIMER_DUMB; sleep(_ups->wait_time); write_lock(_ups); ioctl(_ups->fd, TIOCMGET, &_sp_flags); switch (_ups->cable.type) { case CUSTOM_SIMPLE: /* * This is the ONBATT signal sent by UPS. */ if (_sp_flags & TIOCM_CD) { _ups->clear_online(); } else { _ups->set_online(); } if (!(_sp_flags & TIOCM_CTS)) { _ups->set_battlow(); } else { _ups->clear_battlow(); } break; case APC_940_0119A: case APC_940_0127A: case APC_940_0128A: case APC_940_0020B: case APC_940_0020C: if (_sp_flags & TIOCM_CTS) { _ups->clear_online(); } else { _ups->set_online(); } if (_sp_flags & TIOCM_CD) { _ups->set_battlow(); } else { _ups->clear_battlow(); } break; case APC_940_0023A: if (_sp_flags & TIOCM_CD) { _ups->clear_online(); } else { _ups->set_online(); } /* * Code block preserved for posterity in case I ever get a real * 940-0023A cable to test. According to schematic in the apcupsd * manual, SR is not connected at all. We used to treat it as a * battlow indicator, but I have no evidence that it works, and * some evidence that it does not. if (_sp_flags & TIOCM_SR) { _ups->set_battlow(); } else { _ups->clear_battlow(); } */ break; case APC_940_0095A: case APC_940_0095C: if (_sp_flags & TIOCM_RNG) { _ups->clear_online(); } else { _ups->set_online(); } if (_sp_flags & TIOCM_CD) { _ups->set_battlow(); } else { _ups->clear_battlow(); } break; case APC_940_0095B: if (_sp_flags & TIOCM_RNG) { _ups->clear_online(); } else { _ups->set_online(); } break; case MAM_CABLE: if (!(_sp_flags & TIOCM_CTS)) { _ups->clear_online(); } else { _ups->set_online(); } if (!(_sp_flags & TIOCM_CD)) { _ups->set_battlow(); } else { _ups->clear_battlow(); } break; } _ups->clear_replacebatt(); write_unlock(_ups); return stat; } bool DumbUpsDriver::entry_point(int command, void *data) { int serial_bits = 0; switch (command) { case DEVICE_CMD_DTR_ENABLE: if (_ups->cable.type == CUSTOM_SIMPLE) { /* * A power failure just happened. * * Now enable the DTR for the CUSTOM_SIMPLE cable * Note: this enables the the CTS bit, which allows * us to detect the UPS_battlow condition!!!! */ serial_bits = TIOCM_DTR; (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); } break; case DEVICE_CMD_DTR_ST_DISABLE: if (_ups->cable.type == CUSTOM_SIMPLE) { /* * Mains power just returned. * * Clearing DTR and TxD (ST bit). */ serial_bits = TIOCM_DTR | TIOCM_ST; /* Leave it set */ /* (void)ioctl(_ups->fd, TIOCMBIC, &serial_bits); */ } break; default: return 0; break; } return 1; } apcupsd-3.14.14/src/drivers/dumb/dumbsetup.c000066400000000000000000000126311274230402600206760ustar00rootroot00000000000000/* * dumbsetup.c * * Functions to open/setup/close the device */ /* * Copyright (C) 1999-2001 Riccardo Facchetti * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 1999-2001 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "dumb.h" DumbUpsDriver::DumbUpsDriver(UPSINFO *ups) : UpsDriver(ups), _sp_flags(0) { memset(&_oldtio, 0, sizeof(_oldtio)); memset(&_newtio, 0, sizeof(_newtio)); } /* * This is the first routine called in the driver, and it is only * called once. */ bool DumbUpsDriver::Open() { char *opendev = _ups->device; #ifdef HAVE_MINGW // On Win32 add \\.\ UNC prefix to COMx in order to correctly address // ports >= COM10. char device[MAXSTRING]; if (!strnicmp(_ups->device, "COM", 3)) { snprintf(device, sizeof(device), "\\\\.\\%s", _ups->device); opendev = device; } #endif if ((_ups->fd = open(opendev, O_RDWR | O_NOCTTY | O_NDELAY | O_CLOEXEC)) < 0) Error_abort("Cannot open UPS port %s: %s\n", opendev, strerror(errno)); /* Cancel the no delay we just set */ int cmd = fcntl(_ups->fd, F_GETFL, 0); fcntl(_ups->fd, F_SETFL, cmd & ~O_NDELAY); /* Save old settings */ tcgetattr(_ups->fd, &_oldtio); _newtio.c_cflag = DEFAULT_SPEED | CS8 | CLOCAL | CREAD; _newtio.c_iflag = IGNPAR; /* Ignore errors, raw input */ _newtio.c_oflag = 0; /* Raw output */ _newtio.c_lflag = 0; /* No local echo */ #if defined(HAVE_OPENBSD_OS) || \ defined(HAVE_FREEBSD_OS) || \ defined(HAVE_NETBSD_OS) _newtio.c_ispeed = DEFAULT_SPEED; /* Set input speed */ _newtio.c_ospeed = DEFAULT_SPEED; /* Set output speed */ #endif /* __openbsd__ || __freebsd__ || __netbsd__ */ /* This makes a non.blocking read() with TIMER_READ (10) sec. timeout */ _newtio.c_cc[VMIN] = 0; _newtio.c_cc[VTIME] = TIMER_READ * 10; #if defined(HAVE_OSF1_OS) || defined(HAVE_LINUX_OS) (void)cfsetospeed(&_newtio, DEFAULT_SPEED); (void)cfsetispeed(&_newtio, DEFAULT_SPEED); #endif /* do it the POSIX way */ tcflush(_ups->fd, TCIFLUSH); tcsetattr(_ups->fd, TCSANOW, &_newtio); tcflush(_ups->fd, TCIFLUSH); _ups->clear_slave(); return 1; } /* * This is the last routine called in the driver */ bool DumbUpsDriver::Close() { int rts_bit = TIOCM_RTS; int st_bit = TIOCM_ST; int dtr_bit = TIOCM_DTR; /* * Do NOT reset the old values here as it causes the kill * power to trigger on some systems. * * On the other hand do clear any kill_power bit previously * set so that it doesn't remain set in the serial port and * trigger a problem later. * * Note, we assume that the previous code has done a * sleep() for at least 5 seconds. */ switch (_ups->cable.type) { case CUSTOM_SIMPLE: case APC_940_0095A: case APC_940_0095B: case APC_940_0095C: /* clear killpwr_bit */ (void)ioctl(_ups->fd, TIOCMBIC, &rts_bit); (void)ioctl(_ups->fd, TIOCMBIC, &rts_bit); (void)ioctl(_ups->fd, TIOCMBIC, &st_bit); break; case APC_940_0119A: case APC_940_0127A: case APC_940_0128A: case APC_940_0020B: /* clear killpwr_bit */ case APC_940_0020C: (void)ioctl(_ups->fd, TIOCMBIC, &dtr_bit); (void)ioctl(_ups->fd, TIOCMBIC, &dtr_bit); (void)ioctl(_ups->fd, TIOCMBIC, &dtr_bit); break; default: break; } close(_ups->fd); _ups->fd = -1; return 1; } bool DumbUpsDriver::setup() { int serial_bits = 0; switch (_ups->cable.type) { case CUSTOM_SIMPLE: /* Clear killpwr bits */ serial_bits = TIOCM_RTS; (void)ioctl(_ups->fd, TIOCMBIC, &serial_bits); /* Set bit for detecting Low Battery */ serial_bits = TIOCM_DTR; (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); break; case APC_940_0119A: case APC_940_0127A: case APC_940_0128A: case APC_940_0020B: case APC_940_0020C: case MAM_CABLE: /* DTR=>enable CD & CTS RTS=>killpower */ /* Clear DTR bit (shutdown) and set RTS bit (tell we are ready) */ serial_bits = TIOCM_DTR; (void)ioctl(_ups->fd, TIOCMBIC, &serial_bits); serial_bits = TIOCM_RTS; (void)ioctl(_ups->fd, TIOCMBIS, &serial_bits); break; case APC_940_0095A: case APC_940_0095B: case APC_940_0095C: /* Have to clear RTS line to access the serial cable mode PnP */ serial_bits = TIOCM_RTS; (void)ioctl(_ups->fd, TIOCMBIC, &serial_bits); /* Clear killpwr, lowbatt and again killpwr bits. */ serial_bits = TIOCM_RTS | TIOCM_CD; (void)ioctl(_ups->fd, TIOCMBIC, &serial_bits); serial_bits = TIOCM_RTS; (void)ioctl(_ups->fd, TIOCMBIC, &serial_bits); break; default: break; } return 1; } apcupsd-3.14.14/src/drivers/modbus/000077500000000000000000000000001274230402600170615ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/modbus/MPAO-98KJ7F_R1_EN.pdf000066400000000000000000013431341274230402600221250ustar00rootroot00000000000000%PDF-1.5 % 3897 0 obj <> endobj 3915 0 obj <>/Filter/FlateDecode/ID[<1B6FAFFCDD900B4B818557326B05C277><213E18AA97CAA843B657983D9A54C4AE>]/Index[3897 45]/Info 3896 0 R/Length 92/Prev 377671/Root 3898 0 R/Size 3942/Type/XRef/W[1 2 1]>>stream hbbd``b` $ M@-$HZ@Y VjZ r^  $b;+8O_ْX endstream endobj startxref 0 %%EOF 3941 0 obj <>stream hb```f``Z xAb@qF.F؀`p ~K3kBYx p 0 (*,RV^bRll @LS¤V8gNi2kL: ĺûd[PҺLXs b %`. a.{Gqt0xX  , 5:$"B@K#(' ,upc`T?  i {}"Hetxqq%oہ r4@7' wH1aEV' z H33@Nt5 endstream endobj 3898 0 obj <>/Metadata 136 0 R/Outlines 409 0 R/PageLayout/OneColumn/Pages 3890 0 R/StructTreeRoot 574 0 R/Type/Catalog>> endobj 3899 0 obj <>/ExtGState<>/Font<>/XObject<>>>/Rotate 0/StructParents 0/Tabs/S/Type/Page>> endobj 3900 0 obj <>stream hXmo6+~HoPpf дA|Pe5jK EҴcǝWA#y|x{X\FD Q yJND HQD3JJP$3I***p&p\zI*rt2a3(8ITjBJ f{ж7#Jr) \KFm:%w l)+)*oɈZd )][VfUG?v|7w^UpDT:1.Y!֒ؾӡ{(ˢp:}%_y/臶[sz:!~t=//V& UtzQ_ahS8> LbhYyr7ƨ/m1i|Ww1\ӟH͋Hpr>ilI=+۫IWX@8}qm j(~i\Ȏż.'ݼ" \-~#Y6n"^mGwxn0~8$)YOu3i:NXw:4& I*Ѯ!Jg}c#&"PV2($ 3(S\ bې&`N|AXyn\\}fPX#t9NV@7nWj\ֿY$pSpKQy9500vsO٩i0%q)eDX >/̚MhP]C :l$I}Fl 58\fJ[,8+6u uZNZ5z+}VyVNl/ʅ>\2leX}iZZYbcPwbBݚ >l%X;֗~D̾ D,8>m0&XF|zFM%L/ }e3b̾ʶ e&"Xӈ`VwY#zQCHEDTk{/eًt+eN=s?sd?)kRUZN>U aa|y"z$ ys/5wXuqA?gCj QqÞ:711SB>stream HTMO1Rek[BHMԔ \8TiP&@~3͛b0dt< yWtWm1p5PVtߴ0 I_.g% 8C+!TzGb뵔^ڄݴ6zh?,w@%τ?Z.PFH nQ`L%U"`mkJhFdge9$SuU.Ƒ* ¦P}dS^" æyifǼ/#Lf0nuwJwH_xct @Q 'Զ@6%GbDL|A 163qAƻ~MdH%y/-hDSdVvmF&Llq遺 8q&}ˑ= RВ>Pa2[pC[ **1;%݇qeVFce:Ґ  ZgyrbA!m97K>esrci\20pHv&eayf F ȧ?m~\ L6uO SBO&x2p5QAVAX7V6YJ"mpb7:<.` endstream endobj 3902 0 obj <>stream HU[o6~ׯ801H݀@dÂKf{Y,n|0%^w9ǂd]|F/KG^]g]Q7WX.f M%*RZk`lxE'-,[NfXtNm:L@ SUox=h&#p5$)<3DMOɟ\ N iYƜ˟P Q΢\ AM5Z"|>l}[ɽ‰( c_2;&chgEG xh3s&lA%^.J(m##'t*jxA=5^P̸ob QGy'kx.K0R=׼_cf:o@J}񮵁T5O<(4kB¦B9v+pwSCuYC4q>jI]8 c0L}( 5x6JRɇ fy-nCC@1]@o?Bl嘃6GݡCfz^v EbfN]Agb+?|~*:s~\j1jv%@ qx0L endstream endobj 3903 0 obj <>stream H|UMO0W> !-Z©C mHQ!=vvOpf7o&Y ;Xa2 xX«$iZAy%ߕ\VB6Dv1'}t*TA,ٖ{:x2mZҊ-LfդY_ \'(}z-A 9c(C54yths$%flC^"?M 9r{XDl\*I>KSkP{pأj^=?;ܷ9{Ťm$A(}@}%r= b'bosAݤ)iK+4kGZt0&XqyHCMr*hR R>r$$*G%'?#KG`^ͷ&Lkn& \|#U؇ h@ZbY:iwB9v77+74: ZDubD EE6\8A܆5xq(Eo%6Qʛ6A},[T<)O`IAv:GrD1.ԃ&.QDJٱ7zzѳš!iֻ{glԶ~`:BPC]P66TEvyBn4`-[SVcQaxu5;lqm.+,a /n6)PZR'+w/O(ujg`m3(Hauþ^uv"^?ץ 22aJ]`1 s;uZc0BIY,O(M endstream endobj 3904 0 obj <>stream HUMo8W̑<?D@QI@w7A6m#'n}P4iыDѼ7ofV,Ux{ O/ֲ46jō|Xʓ jɶ*lbS\\Sq,WH/^,.߼&˗gqT):\!k;*+頕wMP$&^틕 ;JU\UƕD`Vlw-ˈkHn&bi+A#mv2/:('bmE8!:(P;U7!<ۙ0WF0NO˥&MMF c Hc5 t{נ{MXL?=(@^>܁!Gܵ?GGЫUdƨDf?,dSN?$,N|*"J݈Ꮍ]gjK=dN24o2yw6AN^JG:c% HA\J571kbtX9*dWgsɀK0U~eXpmMG I1i:lr3gW}w{@n-1 גc;i%&~TIaj療BAm>BC,]2a jfFz'# aeΘ2M?S+G ϊW}É}0SAx3 ƌr$iF!<7oL6v9~Ta*-)1ճԵLi idѧ9ɢ>?c'_ endstream endobj 3905 0 obj <>stream HUn0+HMZ ==8p$7v_!lNQpQ  %(S Y.saT ^HR)RP Nq tdOUqT }z4Ξ!URXW̐#7"g͌W#<4 mtU&,[p-c  uNQ7|ӓwW)8;͔l}N{۟T`C0sr>s63ˊWd|kkiƚ+ :y0CPiŬYlIrsKhJkOUW=-89X\u&ry1N6X'}FTv!cpU~^ dEJEVeYKW t@sug`6DI ";n[F~ ,T~?j:cjoq T{v;/b|sG@u؄KՀ-R銚h4CuM!|40[: O{G Wmo$ZTk?ūī Qzɐ+IL6i࣪55T#2PTHjTE'_ANmIIQUGLV%}4,j1.z㟉΂U[0|{MB؍B$zn]JEbO3:ı 澡߅)y&  LSx K|6naY.! Js-m}ƛsk%`G1e˻ endstream endobj 3906 0 obj <>stream HUr0+(ԊeJU C]6P^E1#C =[k.6Ȃݧ5.P%V0b #(ujL[\f6:K-E[cy A/ҕuK>stream HUMo0 W6i@T[v( tiP@Su6Hr.v"||^}L#EV[cmZU[K82N5NԫZP]-LLCfun2*sm 6֚e0M$W]կzl#H{:^`ϩ7ƙtGy&S< w ` 1|W0G.Uʵ8=FUP rFř*N-#KRHbƦ-%^B߇[ݩOSx־Cz<dIisԵm{†>/Filter/FlateDecode/Height 101/Length 10567/Name/X/Subtype/Image/Type/XObject/Width 211>>stream HW{teh6-Me.4ͣm AA^bA@Բ+ u^*ˮ{\yEPZ|3y'ͣyL~ U\fi= 4}{o4*ʘzz^kjұZe#ԉ sRE[lm[ )eV}s׍~Ȳޛ7i9_ ejE[, ,-MM,'|@~#ua|Ō$5p$.yz`Õ#f4hOACtF ^3/|Z4~Y w"k髦᎓["C€rtpH,Xώ'UL?~GVWGvL[<}ZGO}m?sD/3!π~obi˳ J;H@Z zn?{3S//_m T368 t) DvX/PGHӖ3px=C,M M(# y00uB`1?`8/k~|'Ja#dW?Pccw9gDʊ?8F[{.6\ܻgwl.g? 9%`WRb)P%xbcBa˨i$!uw~M/ledye<2v3Bt"45?tH@~hRU7G,E#Ȕ;o%{NWYji͏VFn}M2L;]6>,q\`qŒC')Ijް "S|Yp̬'$9`eK08E=D׳Իıx6"& CDFTbX.7\'a-"JH8 !*ATn O/ޕhԻm{_P. dDoq.V Wk62kkro 88v77Ai! PB;(p.]򊡾αn#׳#I-ܑpDbӠHYAmkf9nJZo._<~ye$,r=[B s mLڱ([ .z2* ݡs H"aSA 'DRbp,X)pRя<۪? 2Txm"?oԹE }fm|epz qox9LG9dZBRhVۺzK笷-9^`|ZsDBRt1I]"eEHS >*pBpy N #92;}GDܵ7I2nOG|lYl9>ecNۜ{,#fH(/"` ESBW߰PS3,!C6PE Kmv[l[>)̄H%Vz6؜k;/8f&0d'w! 8DD wNȌB^Zt=s$V E7=h<ۤ@iɪp \ 5WY4"zU7ms/=p)E( +_KCgKzud>Mhn?Rig؎=s*|ot /Qyi}bgq?45KpbRKy| ݵ|]8Zb/&By͞M(O\$=h"ΥkBvg$}X5۲1Q[mEGP}WurDt #6g?mh$@o|r x1\6>ÎdDm5p '=t8ʢ+yJ/D ;$09+V!V! R*$ۏ?M+SXVwM" )a3BDẀ3ft՛?5h5JWT1@K5(SĎH⭈ꂰ.N.v[LyQo=Sud^cRi^$] n,8>ҽjXy޺z)v׋UZ3,%QQR5ip2qmj9íٗ~R_`)I4NE#CNwLFJ1} 5  _5X&L25t 20kpӁU3u编SK&KRFw>iǣLu"z%#Mt$+Dw";"WlSʪhT:KZWOez} 2}c1ƞVAS tn4y@redi_6'жgQJVHe*5؀~H7U Ǘe6H \v_6Ɂxn@$:z^B~ZBg\" f#DYQ|UM Mjq8nxŢ+R>".{\/mv"\swؾ;(_iB\YDI5%5:Ywˠ i"XG9ffw< Sg FN4oc{t귝6VU;M;9rs$8v׻c4)MOasamcrDuڰ=<աL= rZ8ЃptڈZئjfd) $݀Cxi@Y 3[O}Bc`Y:'''<`i-rm^tx,proŌOi<.ƈod=8b0\ :[W;ox&`2y5jGrPq eIJU5WU{?Cg0ᙎ+[w<5G_,Ei*$-HTVtmT I ɎE+Z~@5ufq)ۇ 21bW8i[ xPаn&RKa rӸ~gyoP?'{W빴yΟ?e5s;xIw63so1>ia⺹ Z2:;p"FN]P0kTz S>XeRY$=qyg΂Be_g%/zY&b} LQ1Te("G#b3 RŞ 7Q~ug(gX<#gs@ @ @ @/ɰ򒒒2B-GsKjuvvYp>x8H0˪ ve%hkDk@ @ @ v6&"'\1&V7xχ2+H:H i"QksS C8FJUw7iϋ*ox~ vuvqrtܿwy G]\>ts޶]-!9ms?d۷g㝟{qf=j0 >SLyt񢩡]bLStdM-*jE {@>?AWSkIp VGOź/?'O5z4/{Et'5%CgmY7|oR޹X7L  :$7|2cyBhh~=kxl +.{j\.wՊAee_rŐJ376ad g^|y 9='$;+zpPO?|~k32Yf³y1in/,NVcg QY5%,Nvm{w6 }Wvv6koomߞ؃ndfvğ{̙3gx[{z>x VUXq=ud!Y?*,<}s.$o6UVVOH8oֽ{>i.dni֨(EF^ `p#)[ .MBa +?^NC7AWCKO[guXX]m-nJ{fH` ~F$ _; |˜dfzrh@%?maj_7z ͛LO/0 E>~*2 Wf߶*#`_^^jk332E'F]^@J]_j};RZ0)՟tcMWBqiJI_" ׳wMS!Y 3cyyR7rp'ft2[.8l[26I@pF> =B~~X,Y 2300` !AxX  +Tc<`͌mZTΜX.7{[#}޿xɔwslֲ~Z Qx@ (***).*8lj^#0)r$t眗/^% @2EBFEmGJ񝓳!3n&xk\ jhNy#]Z§q?ֈ] ,Wnp86jdӀBx‚GEIIU*t\xO#ʠg&rd\xm.M 5+&z:(j%wݽ#e 4[;p1"!e1wO\~yyy`ڼi߁3dvx",6v|Fu{x-$;gLsOXI;ɮy+d\W[J @>0ȡŰ {^$gĂU%G$Yq'SK(GFV-KIIx4~"2l OԴgW،  HKtéq2W;(P߿t``ƤǏ}0$8}q_o~E(!4:Im޴ BwWOV-ڍ' dҖ?L5/a8Dgq8gW2'm/o:2#$]D TԧPX9򝳃c/h.Fπ<}]K%Jw"_VWryrR0 ϕX6Jk f82,zq!SR[ 2322 yW~ZĐ!1v !4UsuqDB~~bmmcn:;:i/wsv3MDNZu{߈͇9Ѵ5!yJ L;-$9(y>#n΅GYi9|70d|Miki}A/\ÏpLƐ*Ο O6ܺ+qHZWoT`7 E !s D/a#ۑtJKK],- ڬ){CbCEswAx-]XHfՇa#Μ%[`{g6qUCq97( ?fdX@ߏb)Ɔg?iq55q780jW ph9),]Q\޹zNv[Pz-EwE^noRGB&Wc.BbFD\謮<7Ӕ,_W'xh~~ȃJ=m-wqrr7[HYR}WEAju7ߐJf(]U|9ڣܰ^eĪŅùxx^^@;IcA1{g0^գ7Í ǎlT:4¶ZĀ&OpoN,_Ӝ;N `oX3AyiyOš@<1(v{TQA}(7MeycG)hPfk3A('b'%9ӋX x5EeU%܋k!]~mo@ݝ4ĵΪ+,7o nWXJ*bS595?({SUT᧡mV;ؔ48Q&ru\^_QA $UEej˒/b/1!a ʷ,N(+(׋XM]wL#h68(HEQqbU+>Ǝ\-'/9ߐsEIo-=P2>Fuq5f}oWƾsɅs)9#Sgܜ蟢vPNB2_עa~Ay9RrJ25A@ vP 04~J@084D܄B~r2~(NUUV%%&F@|썤@馤"?99hiiHrj`Z8E Kejkj* L%!,*B~㤕 7oHQ8VGD@vuu MyG022r5?1uCoTp٣#j掑lrN.x8mᥒIr$ڛ}=9ɒ2&]ƫ:Mk:~d}q9uT3JfHK~?N.ݱp۫md&NYhlf>)8J f|bNGfx.D>$*; (3HQPL[n`.7 endstream endobj 3909 0 obj <>stream HUn0+H1ERB iASD=9(r}Eыm z B3gv&h5$f 'xLGq,Ď.z<K mOE226TpnqO`'ߩ. q{Tfۧ덹 0:?Эen$pa߽iJbv";!ji_8 MAaՄno/-ȶ Gu4W\|2.O2©Uπ\7!8lچ:lPc>+}1?bl2q?NͿvV6R/8Ǒ"nߚˀ +aT0Mse,r[ƾv3 BkF]NKh,Jb\+momc.Ʉ~ն^oƤCDzr4Ӻ ^|ʛ7ɗ7X%˲L".":sfR@]o7J Ͻ@u~\wNPߡ)n] ϻ7x@X $ m% kCZĮa犒,=:9ޥ 8˵IexŔ<2瞹g}4DLYdeyQ[ޭ9aWGG>e\`=XTsĹ KrԣsJI7V&Io6f}9K\rʴNa7N/xPy$dO@d]4?< /[黾k56(u-1"p7 h7ۥdᴪI^ U>stream Hb``$WR~  |@T # 2 S/`M.(*(%8H8c- fԉd9@6_IjH9(3=DR1%?)U!$5X3/9 ($5j%V*'&*r"(,!!0b;CҢ2(ɘ I8/ endstream endobj 3911 0 obj <>stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 3912 0 obj <>stream HyTSwoɞc [5, BHBK!aPVX=u:XKèZ\;v^N߽~w.MhaUZ>31[_& (DԬlK/jq'VOV?:OsRUzdWRab5? Ζ&VϳS7Trc3MQ]Ymc:B :Ŀ9ᝩ*UUZ<"2V[4ZLOMa?\⎽"?.KH6|zӷJ.Hǟy~Nϳ}Vdfc n~Y&+`;A4I d|(@zPZ@;=`=v0v <\$ x ^AD W P$@P>T !-dZP C; t @A/a<v}a1'X Mp'G}a|OY 48"BDH4)EH+ҍ "~rL"(*DQ)*E]a4zBgE#jB=0HIpp0MxJ$D1(%ˉ^Vq%],D"y"Hi$9@"m!#}FL&='dr%w{ȟ/_QXWJ%4R(cci+**FPvu? 6 Fs2hriStݓ.ҍu_џ0 7F4a`cfb|xn51)F]6{̤0]1̥& "rcIXrV+kuu5E4v}}Cq9JN')].uJ  wG x2^9{oƜchk`>b$eJ~ :Eb~,m,-Uݖ,Y¬*6X[ݱF=3뭷Y~dó Qti zf6~`{v.Ng#{}}c1X%6fmFN9NN8SΥ'g\\R]Z\t]\7u}&ps[6v_`) {Q5W=b _zžAe#``/VKPo !]#N}R|:|}n=/ȯo#JuW_ `$ 6+P-AܠԠUA' %8佐b8]+<q苰0C +_ XZ0nSPEUJ#JK#ʢi$aͷ**>2@ꨖОnu&kj6;k%G PApѳqM㽦5͊---SbhZKZO9uM/O\^W8i׹ĕ{̺]7Vھ]Y=&`͖5_ Ыbhו ۶^ Mw7n<< t|hӹ훩' ZL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km  endstream endobj 3913 0 obj <>/Filter/FlateDecode/Height 430/Length 1572/Name/X/Subtype/Image/Type/XObject/Width 576>>stream H߫uo6eLC&Jbbw /Fл1D`""좋Ay!R u1o"ryΩ8es>x'e]7ONo}ݮng5<}\2z#OްKbz~i`uF'?, \sx(NwFOb&\>^=yg900_c0㷞ۯŒ^9~=9Q>_9[l fuz?Yn- ^ޱcvu˽70={70 /l{iuC70ÇwVWwy9Μ~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(C PB?~(Yy~_707 kee 'GFo`^/wn}#ձݻύ^^ܲeY^-kv7zs:sWw0G>g |Ïq8OSs?g?0kO=<|փ0~_L=k9'1co=5e/훾XϚf0fmϚ[?>z3?z]wFdz۶.WV^G/ey?Wswv^IW]~X) endstream endobj 3914 0 obj <>stream Adobed     '$''''$25552;;;;;;;;;;   ####''',,,   ####''',,,$@"   gq!15At"Qa#2%3BRUbr$4CScds &'()*6789:DEFGHIJTVWXYZefghijuvwxyz!1AQ "#$%&'()*23456789:BCDEFGHIJRSTUVWXYZabcdefghijqrstuvwxyz ?6A7EΔa\g4Á|;_QV{@}6VDxA!.Z3c΁~u9(w$Y1i]ez:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;n觔t#2q xODh PqpCIv-ȌlHd9 !d:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:LtGt;nЂ:Lt\FT:~Ϊra8nRQ&>z86,%q- 孅:IfqG6y=#T6j4Ǚ U5m׌3YY'dT  kkێ㛄jš(-*uY#21;3E-V=ZFA WGTz5?d,Gg=`2BBBBBc)~{LƗ]ӝ.KB18Kf'%Jꘜ%t!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@!@(@zʌ6G4)%H2kۚb]q.GJ`|i uvݹ_1ΰ$V9\$TL kx˾8Ak%Zk[P笍ĺ; *+pnjIUi@9Y{ "++k#j^vӀZ3n 1"iʜpTP Oۉ>q{'Ijf4BBBBB Cc&c)~A՝.KBձ8K'%Jꘜ%XBBBBBBBBBBBBB ] [,驷^n ILAX^{NE\Wֻa][(w$sAօ Kl!eX8z!!!!!!i ģThCĝ#@#:nv-@4q`Y6u09ƷNOA`8׶:}*m]%η*knY aDŽ|w>4а3[cJMA`3è@bJ9N&yM `bq{3eBr⵸aPk Kʑ^C.cjp 1 ,PZt6 &%f]ds;)s.l9W^ĆFVƺnĄ9"S\1DB  _=v;LR!ܐ֝.KBձ8K'%J؜%XBBBBBBBBBBBBi%3 cd;uSP$>fa+$܏u᭐x\>AۻQoe{awRg.qcjߩ#Fw9/9iDfC;_ ]ۡ F^ I ,湧T)d*o>p ~<8g 讼kƚrf^޶9o8i^pSvb3q8!-o9~hxkB!%"]˨ MLI]{jn/ ̷ |O t՝fԕ7LU~Hv{4Yރo wv!2\jE335 JvP|Po^ m5$}ԾV+ 鬛LnAⷣmm|ⰺŗXؗe >R2u\YnP<$Q(q\q_8s\+im!'>\H>; ;!Be!\UB uS*O#@klۙwAcYc2vbq6 x{&!lGlXabY!mqb`Iv mJUi禦Z0Մ<Wi0 _ex'q{3;n*$ƶ +^f,dЬ~Wr"<Ы` vX悓4(nB!!0v2]CmHם.KBձ8K'P%JꘜeXBBBBBBBBBBBj' Y%{11V & 8R^=I+ wPewk[%x\?Z2sۜA !,<dY^V/o^E8h|9Ȇ Vk1As0lH|q)HRSF;*{/vqQP<&e^Dq*8aDatC(bI&}.)eI7)znjy[Yo 5NsrNnrqL'x(@«nٴ,AYB KSc(瞙{YB<%-͎bxԍ~MUj&;$0J̬BBͫiDllyDy ~CQn<HB!!R!$e/or@М.KB18f'P%Jꘜet!@!@!@!@$CI.7x!C-8!KWI7]\%^>M \٘c_X^ײt9NņƢ:95i" lFX]́{ /v] B mI Z/C@9l.t\V*;%Fs͌z|hk\C?1vіw}cƖ%@1{5˃GvHXfY13iGxZ-^^GچV[dH]w3 Wڸ»ng^?q $*JM"&K]Q0DC Bns% Hސ75u6$q xS zyN$(2ZXVxH*vlfݩx_aDE5:ExG ARtKάtӬhWg=׽N5%$Mlog.9x#\pFcq{Z c2^W'pÈ"4ai\7Bm$Z '55:}Ko5:AfXb4XU\2޲j VgyÜkk~E[a Ż.2^ޚu~؈)( GDgߓ^J dފio&c`o6:bmQ%<7|Z|^QpxJoQ=HVQ@!TWo8)k+²++ڐbЈ͡6uދ}w`Z-5]6j Є*!!0v2]&c)zҝ.KBձ8K}rZ_BBBB;ۙ2\*»;v-.8WmUCoq s *$ݰ#]KV:qnm. Lc+ 0$ XĊ8wB-ԙ/ps]UVQ) '#IH7H1$̿sKKokwp-Q\)qA1/ooMw,vfK85aыp]P7°+JMRuK)(3$:%Mś᝕*qYeFRmً `5X0ᮥև3lDV6Ond'p.,\COrs\T ']R .n S xci!H8S/5FsG HЫp A$PGWB/̮l]PѮ%ؑuQ@ݐV&={zkVD[›2{vIY5oB+}k %P˱+`P[ML1#{-pLښt/`k W9VD&(bW" +¤687kRW_@%gsmJH@na6kn3;Ʒ43v%^3Ez1putL;U󶹫э𝾗 pg9| ; cFNć|pN¬maj:'s<~ua಍exFVXx^&bА&j89CWv^9B  _=t;LR!܂ӝ.KB18K$)]S1b!!!!"3nHatx3 - 3eSV-uVؘpo8-G[_w l wL=r! [LhqemiYālx `5Z ^4muAxq v'F_]Gb(8{Qi5ԅsה.wPZB;K􇮛ܓHz ՝.KBձ7c$)][1b!!!!iy$הNåyE"_6վ}K%hwEDTb)²?3N]b5tb|ޒcMŗtˡ@p 5;u0VN@L70]ك {6cþ .`*QƏ:ZZ^bRf>F1腱 nVjs9 oYXLskFt$bnԐlmUj`D Kٻ42fg{G~YMg>T1.m󂌌vM;|ST:JR kҥnCIEq]l7\ߍNӁuiF1Y7d( ЂB!ĵaXWX^;8ͣ2ƽ'ibŅA>%nzejK~;P{\CQ»"?v 7T<%8umƲTV wɶ2w+MT-6` #?dًR#iᔊ|K RԚF)1TCLO;G{pLJrc 2:kd+<>8Y=p4!bmJFw bEmpZV Q#rcٸ}֍` 9cEo5 (61A;RUbY (dgư Plv|&WeuҖ>&g=!P!@!ACC`v4Hzw$֜.KBձ8Kc$)]S1b!!(v c`#{? xB{IW[ão{N_\A璕Wuמf]~ 1Dm<4 8jcjwf-ÞeтֹhŲ(GòhB8S %M8Rk%σXbKΫHPVP+8]x5,N K#!+$VG꽬,q!7ěT5]E@=NQcTCn|E6V9 2ϗdb \e-MEŮ:LA۟0eG9,݉3.kY.wwb f.KB܇9!B6bœb.H6Bś^:&#>&}bu^xR&)sNΎ{: 8T"9/w+׽]tsRS\K cnrWAOg> Y> `^Jƚ#[ w>go4-^Jtuw+HRB cnTq 3v9^us-يO$̙e|p3BynQմE';lH]B]NܒBpuG>]#*H]Aߔ<Ē-fx䮈4b8a]ʎbR9a78I OxqG1.IDŽ `Pܐ,йbs9m H|+d!#y$'ќ Dcjn;u{@},-& OE5U}VIr 4*&*_Uƭ'H׹W|s`I'm^g ד8pdNfov=$yG49.$ȗ$s1BXgϺKԇv}!}I %ԡ1 G榙;7t"Fʀ{jDi<އ~>mڻf A"ˉ9m.QvDPرgo~I]92mG%g5]RTrZnIb3Gkp6ۙR%pׅOj %+*pm9`8iFD]P"ޜALoH13?\v7n skoyEo!iwQ-.dAhIe/uf .ELH\qRqwPNе 'jDt*q? 1T7_,*kUUj81u$g&fC f8S;KrLR!ܐѝ.KBձ8K}rZ[5: Lԣ6T5e-wGϊT*n$+7a,kݏI o'uz Ǥ$*y(<&]u(~Ugpb\ҊoW,U{A069%{[<69UX#uA,^ڼaBPd{ͫ&xmOcb^e[<6G~o#^W@5r*AlvAmG^պ71T0 A鬃يr;wWaf>noUwރy _g7 OE6+͋WmkݍU E7IeNzKXLjݯzݪ*6ݴn`oIz#v`a^`V1^g9{_sY< ڼf"ijEBiX6fm6XWՇu1ylȯk6XlhګT.cp@G0&nѐc oPϜɪ k .uяs A5°AIfa3#JfgI8CcMUur8-fë߇߆-k^NϾvlc[Z*n!ѓ0Io3uʑ35:Dq:9;vc~"0^W@N`kj` 4&M= ZDD K4n)2Swni$ï4wa0WZEevB3a%|Y#es vb]|] Uk u58H=ܖ3Om"f!>f%XIs*:na"]s\nr]9[Ѱ EXBX!pyrxF9XFF&q)Ed9F ڀ5))˥r˥iyhЫZiTn5޴xP.On&Vb\3,Z#<\ĺqt`^f0уh$%p`h:{|y%Ey\|fd IEg\l5 *7|V[/'*v& sw+' Ojeچ;:cPfxC/yCok¨*wVBqU;kW?kAi`ֽ[V>j/]cY^WrpY 5ݛ>F9^ u@^p[_;76 UWֶg xn1 Y^q0ma5b^޶$U5c Csn.Y6[¯5cO'myG /j#>ڈۙSL:8bo2alٵ"A,JrCHǙ|pVC76&ʔw)g d0 +ŽX&7wE"rwW%YhLZ>k< ff dH+6^.ڭդNcK͘ c}%\?yT^+^ ({' m@d3b\b^q¦ÈEu$bDc$3P(LeL\#Ipp,D;C)/>'mxwm+zbm j5=1jTx±f$32ơ6>vp,7/B97Y+Tn.J V湧=GC-O|Ÿ"Z Avœ;jǂ6zH.E,74ÈbB? xI˛u^npM;R㝵-r!Ǟd E{s@69 P!@!ACc&cKԃr@ӝ.KBձ7f'%Jꘜ%XB V(t6zH[&xEs.&`%v)Fi"`1j> 55ň3ہ<ٱ-쟝cqps*qC\Tͨm_r Ћ>5՟kvضMCV!ᶴN:5hŇc coHŏʪY6U+nmXHhxv۴;Xf`ĺD{!ӵd%Mb 5σ{^0V-]6Q[^} 1a@`Zpy5ֽMG 7ÒZ۞1mY 'md!r1908Vؑ`voI*Y{}(k GV*A&斑k*&K9?U*f/EDβrB$8Dr4Qf$NT|Љ,uokDkEd#8Ll6p  ,+V~1 Le]"jdwV*5tsi&!U|OA71l`Tb.-C8ۉ2])YK9/ 7 !BfFL߸zj=p+rFQd0a48\Yv0TTmd"mU\h';p(ɎO)h8VK9rv^ Brn'Dx X[ENY5ze[)cGVfҠ E~Yen\KJE}As3t n^qsH+PK5lZ3"i{Ƞv[2b]j@ָq^3">s}Ν,VWVJ<asVvHNM5 1ᰍ؎+y-椂E..Q[W B ! #u]7AX 2A~Ih28[[@"*dy9+!,3M?)nK7is:`><2\FW⛄{*@HB |$MR36 NҢz3ou snD8V0S;/wA e8lq0(%peRĬwAü#v~`FvTo2>/Font<>>>/Rotate 0/StructParents 7/Tabs/S/Type/Page>> endobj 2 0 obj <>stream Hė]o۸+Œ%Rb& phڜE/^8nbgp(Q2-Fڤj8^C.׹!wjcI.anޭW_ߟ9'G)m%<SIDi|-rd'tad~3aL3x $RQN?&2ϧ|*ngHAlo*43D3&9͖]M9JV'3斘QQjfZ1^VENU u'nB 16Rߊïqha <_{!oR"wJ1ee.eE:eC:}Mҩ,9I1QaLѼ\1JZ$ x[>%q0 Vo߀uq*rf-l5շ l3|os!T w &q> H_f`7LB9*c/vb;b][nb`L)K'WxO)L3ORcqԽ{TL_ v Gl x]jX2`Whr3Yjg8#0H6eq|~# OB2QA16(j/*R/\^e|,C9v;sa;YPyN>¾iE&? KlU&r`M& {?q_.l8?9{ ?6!Օ#eyEYwvwnI*gw6nvU?UzS7?\ޔru]T\ ~UaM6K " ԥ";Nc<6oҩuS3A.ڍr<1;;u $U̴w'Bk?-{ ټ=Vi4h83f iw rs'8fM6+LOL=>b -{OC"ڝnkE]آ0NۍaHCp }dxNt`Od:,N;Gc2 4Gdq["d<@"|Ddwϣ|ENw~prF^&œKˍ*,Λۦ Ϳ)T9< YVUe\fh߉:JՋgĕ8Xb8401r܅!8P1 "㐳y DG'*oGbLriV,A :?Xpˎ;X }&>=`xN0=dq> VQX_.: Udycg:$ij'mO|~ϊ}ӑk3 T_vrZu>`D&(n90h͑8#o b3 ;,!e YrEHVݪo챽n٪渼*YUyīZ"BZzg5T$) .16!c{=f <nonJ-f[B& #4Ʊ->.$T94q{`/j$P&MUyoId˽ ;jsꥫv Qvawz@*u͇1h9qx3kV-Y`bɐ:\7(3?֕-r^ɲnr|W7/"؆AcɱNW0c/Sumg>{xU0ֲ^5"7tPgV2-E½2cPy׋Cclk;3 T}'N#W m`D$(M1IhD̡`oPX]U 1neu 4y8jCG8s(PBS*UAAϵ>I@HiK.XVmTe z -NkUn,OS1re_AUcmF YU_$c93FW/c a<?\Tz Rnpk<%?@J8{9ewRcI |q-ʻfNUڏOc G,q(+\ . #r(J#,uG)|7}\mt\Y{ dKE̎,B꘡R3s Eeu!=f,Zy0x y};ܕnDn5D &"kL 1}ӕ%+}i]^P=n \w׮oxrycr0Eb*Eڒr3#/$ck~c3- uŶ)ޡN|J6&̶ ƩLrl[ `c2`H^:'Ǽ)9:9Ґڡ!VjI@ֶ1v8Pm;8bU\^X!ހN8B!4EhTaʹ1*8B X71VWNyn֚hޔhemڀ^t ? V -3VK|&Ɗ2rcj,o*\+㖫?Q,ۡ'z68h <].8p9ՁS% dzTtZ&" k_?3g}H)!Z6*8=t^,sDwl` [;DU=CEhRH!$[2l՗_ GonoH2Wٙﴏm v>0Q53_@뺊jSK_nƜ3v*Ϩ,I;#ڃM;aia'*(>sk3y0pmU ig!Aڍl|Y (;Hc>j.V.-, ٧V}`&YNē&ӐYSF(C* 6 [-E ޝ]@siܪ_3(4'x1Kxa]DŜ%<ӥ2Ȇ Zg* %B 7T:_ح;e褆e ! enUfUI|a; z ;č|1<Զ Tvfaֹ˶=7nK돾bnUٟ`a@Yԅ>eNōda!C S#a\ [M]zD3n feY%J>"t0{7**f` Ssx9~F l1}t&Mg5NFCP 3 2Ψ kc-N9K0"ĂjP?uj.KJՑT-[pnx1v/ 1-$xyK:C8aa>)'h) 񎏏0d2*-v#t#$fF/NieY pnYm"^~ۄ 0uv0r ~ @mI#}&t:)hPI#G~ɘE[$?GbЩwxq?R6]≫צN@%\N2JfY Lf3*Ģfc&.Om؉ j7IJ:4 ;Ϲi&4m u? v"rR NIb, ShrmS[KʵG*dp-ܪi6 `N ̅&ϒ$.Z9Y/C|U J7qv0X`;W*8o[@*:;҈܈֍`>{#]XRp2wԍb~?A;L-Z-\MAX?ψ+lJ|W,襭GT9>t(",K^יpG jdFe\M4>sS썻=j\G8\3r5 D0Ru55@ EFLTTk[NiW:Zʧ;K=l!Yg(ŷahFF>i3#ȏ13cs67 4#jyXA+(e*UFje3*Z}Y?g|I"Yn]ZV[1N.QN$,y "d¸e}`IeRkofr-*ޫ8{8ZN4ѧTnJ@uC:`R@L᧥j羞.=9u8%jN{ÿ}>|t@?N g .HS5͘ժT fM#Ra@ew|K$kRrфU};hy2葏6><^m6o+&>X &`!q8{|ZjXKsq~oV˨ FulyXkg=Z2vFBWJQ>1e_Fx]E Q`40h=1}KB6ZY̞2 2E^=o ֊zf| ڦvMek~[-$ŞX*T$TAoWb)<Y=8N/[?\u;3;c [tuc79rע\mU7A:܊e);٥S6<},]ZPYO,fl$Y%0*ac7+a~HYـmAFN*CǷ+|2M]H?OâZŚ?,z؇W'Hp/@&8)^b6ɬ5#Unn; yz|;] MҼ9,ľ P&BCqOfx+q%v?҅/U۶D{T%%  En>Q"eIw~D&3;yKY #vTb25/"tO{֦ GKoTK$[-c5J :vzƿqkn<+Wx_uQ~_;E2~ԏ{gt1KT;XF$Q<~!+5!vJ.^O U2>m[$H蒴G',*g燜4xMI3BUfO#3$GK]as֤<8]4n5ZǠQa:jZte|Q!cIڿ fڿ$2 N!tzK~rQIٿlC5B6PiU}V=Q82Lyy'p8sy-3ibIS)1AsZԯ4#>zf)H$ӤmOm`B%tf4;{bJ5/b~3  r0^̄mڼ)hPSon,.E*k>9>Yfژlk3kVs[xcx0Im1llc WU;(%!]ֱa dZ݄L" Qh1W9$"9洖 BIPb_Щ{| ́ц$03.7U >+*Lz(@5H)>stream h4j0E%vDYu+mB\Vh)URDop!sqGhA9d~,2#7k}*}Ur0< /8ҥإo> e葮Nc2}ӲnUleyu1y%yiy}Ƹ>m&Q݇/sx endstream endobj 4 0 obj <>/Font<>>>/Rotate 0/StructParents 56/Tabs/S/Type/Page>> endobj 5 0 obj <>stream Hԗ[s)v/\boX ɌD˩3Lz< L%={B"V3"n{9{~l \ˇh}(bU.`/.YUf!]qoPl*&) Ω$\SR4JS|/ill0%d@B&Uo0'MqO5\$RQN{ 3r/l*f'4(<*xT\b4Ɉf7#Lr Ζf:'˲ЏKL$Ak\+i"݊ -RR\scn\(QZͺ +r&`xB̍ G0qDޘ}̠[WeOKhWb8/O[Tc >LFqaNaGD C[դ Q%3P ahʯ6q.GϲTT g96hf[sa)@';Vd- ;Ur`v?4#{hrSL7KyS.jRm+›7,D}&=̴vFlS!`a%w12O" H C޼5n@&UL4>nd43nTK\`QB9]gFmOF< `(F0㱰$ =JԴimSynvGd)N,*riKAGHc\GOi* ,Kۨ"kOa,1Ӧ!K5web.rkRxYsy}0.ICTfxY'et-peW<˦EWkƜmCvmMfi^xYʧCVC Z g]!,_i!ʅA%Xwѓ_cASTި \޻m8e{g7Ma{YsޕF3a+Mhrhw~/r54J~u2i~ڐhAY_k-_-q#aKzU^x5jd*v[凙b ̿D8EXbU>מ;sKYnQ6*rC~i!؁2+xkg khp7Kuڒ9⾸r>DU6Q[vUddgug6\ZOۂkfWuOeănO՗˝vP퇹ʮJe͉d[\CdS:+XN?y< (Yj-yutT4ժ}/fyZ.]5dnD䎐{d"*ic.6~= NuJJ ~mA>,0J~*\+wDEڙ- i{L.$5M\JiJ5pMYZZL(x|,]VPqe#6ʩYj֞`Ntq| ٮjI0 0l?g04&nĸ ZsCE F=AQ c|s ~^Eo++O)<Oam)0a-*Xd. @W8M0X6WX2Ng[? >Yv&oGi)NsGM5cOmOdiIgP )}\n ZO\ |Ͽ+.D'Ph|׫ ^rIc|,ngUͫ5qnNȹ sgT'^5Y2P2ܚ3M$,aC;q5pr1 ;;o3YL5s4drXmNKdd?O)c6)!P) K̲L%=LѶۀ&G?F+Cg8H<1Β#],|.햒Gs3ۮ?`cbP`Q`?[|rmIm%_Ihf/gɚSv :nήvfvJ 픬jƶ%sX;ZdE[#IFäꅹh==PVp@: ʩ$UX 26S(˲wI3%;Xn&dNj{w2m?!Kl3K@ɭAXyt WnvA?)HC%@$I&w{M#UoJ2P=# s/D3.t$~afACh:\<|?@'xyL˩"7PZ I2$k k^jm|ΡMJ|,@PlvF2(m!H^%wwfvɞ҆> e/ 4SAAsR삺# ^NXMkNn $A K\3(yzzZdwtLRǻEL?,2lu%s"9*AX܉pY\8XŪ&H\H!e:R=5QZ(N/5 Ba#BvBOCK#d'JϭJ?~|8߯b"lcl_p q[P¡b7:sѹHxw#d#=|@gi}̄ =&XE9ÝM lY%`XCo{;E!]ұWt[m4Kn v"9<"Mi1DApuZr!'X):9xmlH) }?qY0J'hʼJo$t>SA  8J#联)Ӿ [ &j[q =ˆP)3vƔo .RprE ў>[Х "6t2%v?ht/o/T ޫLngsVTK7l9]nvvrw?썻_ixc~RQ&DMmtnŗi1. *;؁VW# X`9CFN2Js F+*^5Sj&/k} $Q_WOZjݥgޝG(O69/h-.VMe!9 s!j ?9^(]W( >stream h4 0@_n2ՊtU\.-)}pT 1\:hŸ!!S6a=XkV4K!'ѿ#g ~^fam>]}x%pY]B[/H#2# schss4m azǵحUe?/O endstream endobj 7 0 obj <>/Font<>>>/Rotate 0/StructParents 77/Tabs/S/Type/Page>> endobj 8 0 obj <>stream HWIoFW40r0 7  VEJdRںb83-YW_UO֛cQ|39?Pw֔E8.sBSge1a,}kk# i6 f : FOf %g3ܤc2!Y|J6E:65: ԻÞOL.%\î?|RJ~-ϳh,Mf 󀕃[ C6Ap!U^ N"fܰtAP8#r]ɵ!Lj8SK^jqA;cW<щ 8Z)ba,ᧆ-ّfuV\cuXTxWɰߕ 2 4f'. w Q{it=EwqRQx\^q+s*u v$: :^F݂p"46O!T/1*jdFU ב5!Ȥ9DVȢt.>K^̢^$ux̲^O9 zk%-;h]~&5Pͱ5uPb:[9vy¬0&V c%+F: t]` 9i"'7GiFrǘd ~W8w^Y=7g/q`c57Dj P!h{u/Rl{(jB]ڻ}4kr}J&iAIKXc~iO㞒7ڎ^|BN婟{ƱdY-kj^lڲ!? VFR(>`U# { Ոb5$mN{"`c>_LmC]D#kh]Pfrb}9>!mVv6Q`(GyKzk_p`lq"tfj8Zf<.[Zb9Rwj ШBVՁ7eߣ{J\ ~Hf4=c@T = Sg#b{9`<N /|j8-i.72d:zJBj@S+fc"*a$.$HOd'3MyS 9W:,|bvoW*Co#"v,au#Ɯ .v =y̿IBZ߭2w|t+|Fs,. Kdj/j2s*-',-:;N50yzbtO;9^;Ͽkoɀ29OგZkdGBT׊+_ګhâ-> /YgH`pm> ߅pOimŵ~h 4bpk'r0@ck+ZGv]h] T[ri/FL_|\m} pHG/'- }r Ny6@%bgv~ [G 뿙 `g}dt'#QAtD臺kz9gKXc{6M@,4v=*S-±Zlffx.$Ve%X96yN@#ig2EЅo(-|{Էqî_χm,$IʶEg '\04I/k@tjeR Eu 3ȜX;LU%KzԶ[􂖌<=8aHlĬfOfeO} Q Թ$sĂ* :kh{4t`y/h`^0Rb*Pxc)N9\f;٤m>vy0EZ(#F^Ҿ#} <#ٗvP{у "K~CbqWXnVOKB.>:CԿGŠO ~Dٮ༇>B[tcWF8=4#2CsrS$\""NY[O#o2_m;n#GWQr,l6o@6@ƻ5] yrfuH%ce3KIif?#SbWԩS$ֆr7&BZ;tpoC|Wq*>T 1N+1m^#Oy +:".=P}ȉB:)=Sj9CDҐ̰T&3hn7TP~U4OХW磥/oZGY9i h )U2gS|bʌyHPw$ ykD` |dA[/N4ކ;gƪUccv&IO4sy,B_=Z S>⮓^W7'rH;v~&]C̜.G}:T8dZ^Wn^o,gX]teũbN0 m7#x14̆SF813:'-D12h e١.5'Z(tar5 O>0bymec"P }']̵?L( Ak)CC1vBgbS0,c^m"m%w ~14FӒ+PJXHzfEg{nw zSpB6$eg؜ ;6fr:Ӂb6!92  08 bH%B~ B8IsC.: :f8'c˙hyb詻B_=̫Ybo^=hry|j4k21w\#$* vC37C2i!(Nsomm8:g[GUmQ>4d nP~#H8"<7l%r5YH{rIОWO#(o{, oږRZv6PjHߺ>o/g{Ew(e!e/ QÒPY .geiqL+zϵ ȤaRJy+2 ew: APA`5`p )UJ度rbxT SLH_Ͷd|\]:@6,~6AKTeIh-B)E,}!ڙI9$W^ɠ^a3h؂>ByZi>DǢt mAa`~8t7t{i& = <qfՌ zCXPuPYmn¡ʹ/OI|\BDZ:"`B6"U;,x<DZzm_i p@yubtg?ow^6: /7At*~mS{ H kj7L{1}eC uئ`Ɓ:d-@+͈RuU]iUsiRNZ /ߵ"X1; WSk}:_$XQzn8&%cBYe": =^tnrLZ6$S]F TS> _ߜzT<(DՀwAF?,H *f}@<kQ.WlV B2A ˻pXyO{Fȭd O4\FJz+aO o6J 9H)ӈ?+0F%E5f3uI:NjI%9v lByc`*[͢p?_PZ P7p'agNK=_N,)Pyn>ckxlXPꘙϟA1.߀%z/)r|IflH鄄ZUVuÈ"f Pu}w_iz J.duwp{+-vb]U}nF{I#8[Ḽ<=MZ?}3CB񥐟x(=אSB~E d4]Z\4mVrVRrzyuifl.iK!X\vjfUg؛=A>eYV7qSMݶ\'gMBG3QPK֌+=䬝i2^P?Ae?PDqb28*M|h>3qH{ p?qNub_gQh n_U' ;AA!(pG(Y`P^ )KT8Ԣhϖi'*JJT |j 1` Eٕ\]V$~,Bu(`$o1ø$(I5շℿ"'?ںD9;(H Ē*I&_,='Mf@݆$%e VmQRtQ<[ WE ]? ֽ# P!yrA.ewdpYب+y[j]r߸a'uYL#aDWn/UV+bT NśW~8iƍ Ẉ$]JRTRM-c* @ݿO_",l^G=}9}IAUPEK:wxpTw/ ?(DY}>ٺ=LE>^(`} JrZ{kmk ) CWg'?!(=k@}a-38ٙBãi0989d{mԺX=z<(Sg@PChFW_Gkq=[.}L[T`'aSfi ]WӔ±& 4󤾈b,o!n8f֭ E厐PRkP`< LEyfKN#.@ְ邙J^]kZHRfzC^E):خpjtź]~hnlfi@-P nANӦ5'>kvupwA73Y1vqqv'Ui X@0 Y=)*/p=O=+椻}{rbe=Eeyr j n+ VOXH j1E_H,v߼'ܵ'nsftq!}sR)-sϯRx2d<-#ww #zaNXF^}-kTh %=ylV4WSw&B; / AtsnV0Swm 9(3gW+_|2Er\t|4]jO 9 u ҋ֭Ľ)uc_@8^4 U-tA7$=}~rf.f:ߓG9}#{rΓUYHzuLcvr'|ha_ ܵd%UG bBl>laguavzY l7nI` dGֵa};Lke&@Y;}iN&4 lFJkdZ/v+uIźޡS=wZnuIDd*zTUe2]18h"h Wo˧Y5|aHb L,`4tq}t#^$ endstream endobj 9 0 obj <>stream h,OMo0 +>p>3UHjҭE J3uKJ"g4 ) C` !HfZEiai>I,@*WDj1UpQrb-gI ˸NQ,sF8OYL;ٵ E.hcܪȮ4w,nU;ѯg k谷7̗FK\ :/!!cK(8[wn@MFi|Q>/Uqbx|15~\gٿ$x endstream endobj 10 0 obj <>/Font<>>>/Rotate 0/StructParents 79/Tabs/S/Type/Page>> endobj 11 0 obj <>stream HWn6} /bZ)Q`veq֋`<ܭi;d[U,R[m{[-"rԩj'޾=:>W*Jzuۊͮ}o~GKzplnfwwݻ1;ّݮYݴkqu췰#YRI) բe?ﻶY;:Yb(R!WhL3uLƒv)mZ~x@cP{`K g)?>O YdI z=@P&AR D:5/kDc88ni՝ynq}G+vL6FL#ip.5-;:Y, a6.`8'b⎠WV_  2_ Op.?2))@GGg,^*ʂɏR/=@:_'Xݣ~e׻6w){Sa b*Y@iII Q*(KbR6d3>_HN2h[R54m""ꨦ7)FEF|jj G8Ưo y`.q(Tc/kke[ ve~Yi;7uYnoZHTRCo,QY_4x.ư!pKNχqx 6L5 轄(. @N;e2r)/OBpQ@_b۷ӝ qP/`mM+&#sF(DZI ^lb&d U(P Yw|ɂCpx&XSD!MFG%L㬢G4Jui7P9X&@`i(iĘd-: KRHd 40 O0%^;&1@ȑ'Ri U7raiHJ]w@dZHz52& qM)GR\ U|[gL,*wڈS *D=P[UÔ7’LĂ{lO &~bk~-q<ןk R;8lqcJV< F$8lIpʭKƒ \ajr=-?D~MYmŴ{VWƄr#ޓ2d"K_31#w(!YAJA}a-}T%=$eQ6**t!3-X~$^AL|a6 ,c搙eҲqg"MvWUG{|H[x?Aͦ+JxfXSI 8!h[Zn bh7{G T._15$<;XeTR]CXk*afɾ:^TbdS朊zцӽW@j55Qεoh<ZZOl1=ʃ0L#|HdxmM)cXgGe^^Ns)ɂ"hĉJwq~v Oz,DbaD-GXl3V#Fmu 7l e8e4Ʒ,Iǩ-}ϓve5!3'!xJv9|9DZxx9v;f[p!==9vkepT ީM&M^H>B#i]љ"`7H-xs{OT[D/  Et1>4a+ɗygjrYo/LڷD\56Vϡ4%GEJ{\f X'8TՑaؙ/g-6GJ eA֧h`E#ŝm " QѰx-}QbAbn-y$(E|MOZ "!e#eB@3r"|^*5ݎ\LơZ܄3"<)hOfsppJ%ByNZ.u(JZ0  Ǭ7HOYA0ᨴz :?DL;L2@5* @#biqpxLmZ2ldQkNaiFư(L:so"lN1#'+ɾt VXۺAk/xI?m<3:s)'@(bQ-ZAtS^)$+1?tΈk4XzS nm!2_=l˲ mpRLAv9$=W"UT=|Z>NͳPAgHjQj  fl5OUŔ˓9ĨnP=W%U A$IⷽAL^mtEBdQ"EX@NDޛ2M _@@G<|~Ooh 2MN :G#leVtj Sm\]qP QJ:I*hM)0ҟ!Ur4ŷ &w.PqRܜ=ճu 2fOtéq{lѠێMkоtZYtF>i?J/;tc4 WU~κyiM-uG#:xiNu81gn9]h&1 yNsȮF VN4M[R<#Py&^ x0!pE̚%9r+i JKv*6Me{u%W<:p\H`5"}UPjf"*ÈFةzaY(EYFṮz $? ܗ 0+E|W٣F2GMLco>)i*@NKK?XF +zi`ٷΎd1(bG6mQ zhۈQ}n=N:0Cܾ`*?[i})W=s)_=ygEYN3jv7*TeNG 8FT7xb+9=ӓV YI|:^{121*+Oty l y #q,9Աfe\̮+כi]7 ϴo.Q,=_="zVVYJ}QP+jH}=tq<=N! Fˎ ڨbO/5 6 `K ~3v0Soa7{0t$=ĬF[?Ǥs 0e ѵ6F 0yMjVQ!]1v4\cGP/ vKb%ZHVMCk &yhm6VVZ uxZ cQ,<:.ï)>ȐHS@|(l@[sR=:=io1Eǔn髶܇m Cn<PS5[Uj00"<BH+s Ro94$//WR NU:cz7e:Lβ$GY=Iw4zqzңs)/"Z6c Pg&2l^"t?mu>8#PZ#"Js -UWCrПJԥb;*\2Y]gL1gYx]1EU36V>gtYDMR- uu'[Էid3?(p%8-qK f*Hv~XZ/A|_$\WH#ӛu,g)Ͳ*`4t{wq&WE endstream endobj 12 0 obj <>stream h, 0ezaFJ=Y*Jؖ)I-2 ,LR$.#8.9WD[X.WQjqNc5Lw?1t)M-ƻ gqkApDJR_fC0fysn괛Gqgrqp4 endstream endobj 13 0 obj <>/Font<>>>/Rotate 0/StructParents 82/Tabs/S/Type/Page>> endobj 14 0 obj <>stream HW]o6}_A`_E)u")[O'%{ĞiRCj>tXIEޏs99 xZ׋G~ +V"DYRLߋnڇ\dQdB<^w<Jo&JipML!OO21URbӧ٬sY`v&g&E^c.]l&J΄2ZB('ʹI5231ҹ%/O_sB]҆0ʜ+  Lf`ZM.D%+<]&RUISdJ,4*9I9y29/NөU" O?`LS0``=g*-s`a|([T= .x1mR D|( N9$)F;ErGA 3i>~mrEk}LaDD >U0wI>6Zz3{KxX5]iFG+}Thgqna >y"W6^JnVB22äLn5ì )5@]s}wrRQZ>..N^CB|3q K l*X?+9贸*,>09j/QCQ4劝!rZqNURQRwTK7T'ۇTY,:G"p{w|bݭݷ FiJdMYxkTB½Kü}(Y Έ.UO.m^,Ȓhy˞ߊs W%Y&&Bի) PDv8D^H)˚҆n?gp_[&'L@fpŠq,2}6$>QHAN6 ºH8 iVkgCR@opn5KS||S -ey;zaSC rÆvWG@8r PhGPEeQV |3(!4N b;ƣ4k\n1Fee. t!dSkY—t^7tĭ[D5cv> |oQAkluOnF\DײCmCUªkjK~}@s AC|?I޾u%hUݳ+3 B4 42Zo 1C3$@;rxwps ͆<=6YaH6r,eEh`.~i`(D1Z MSĂQٴ\ Bie-zcL"i ?tV"\g.:n0f8K (9TF-9b^5OMﴸ:iX qf0.ҴePsqa@_c]PvVJcd1rbddR OI*S$6/Bg/s,J:H$M,t0?SIq{}]EJuѻ[}wa͂)SS|Y\pĭӑ+igyu7_6&ܛpTHs ȽBJ5G/ZqP:/9761Tt]PS24 0SkrR%u fm6B˿ )mW*,йyPJx+`{pFbȐr+[Y˧F۹-.pz#!'\Ut]Ą qE1_dߺܻ3Ks_T́cQޢ卙tpN8u7´uT$BpWԚևj}-78i:"U{RЖ*wh9?qi8Q)'n[Q CM4i]MV:HuZ$#.{ į/d;>B˚,d5ǯw 'Jz(uwFG']h{|ܸȬ,0 *ܸ`=:4P)T;Q}o֏.]C!G`\Xs/hZ}u}ֻ>9O QgakodGZG|~1"ب˻Iܐ[ =p:= 4[eGʖ(_hX j[z޵np5}jyC.;@4 BM;7t#6>~C[͹8^p3|55LvV>Hvu۠ ^q &)%AD_jʟ)*#xmQ8;9jn}7Z-m}Dc{`Vbårzj(52Μ@\@wTK 5\W%3 #/B,QY͗@>;a%, @O,-4”[6YmG=4+mD>$eH xvh?Wr+8 S;o-iJh`KPs(^0̬̗Nѝ+ݩXkZrCV7PkWkҧ̠R:ZPSP3L'rigR+m?并^2\0"(6%Vcm%ocN3~ x:Wӹ0fz#{3\ .Ry{8j| "x!҂p.Nʨ]B9ML9Jԗ B(IPF]-7>4r=/\ܔLIb}7덷=-Fa4cO]s?]Y"5WpLj >@}믕Qr06-~@R0 }^Px -BGW?- )o~}U!@p3\bc~^c$waq}/!klfVԌq@ РvTi2|}5`Ѹ_ 8o{{C_A̚ +\ &)EfZ=@\Wv3ͯ+ a H0nu-IԮ8]Lo!f~cݠ;qT=Q;*fS$EɗQόVτw)dd 2Wȭqa{Lp̠r Rh(CXFo 'dQꔝ_'Kg}y:%2Q0&v%UJr Xh  k.H?qXt0WowUTވR̫DXbqz&E 'U\>&5 AH#P<=.^}9^30>kL-!8}z:VYj3L`=c3G"kFy%.[Li7r a Es1o@X & 5qoX:OvG« FWs2fsa9E9M[3h "wIs7x@^o>$yy+#@u7?\p60('Kl$=f.^jD w b{˭Za#'ר4lWgL+&JKкaEVZ=>GC->cz~;mC!{/h'F@Fq*:5'@\ lz0gK;5gCrIԙ&~_U x/AL99-}87Ԓ8,*W74g$?cpVj'oړkw@z/@Ԏuw#bF옷Za׬Q4B͈P'E}) (}Up Nф pj2НSռۋY&.bg"k /%ÆzQ#vIhKCWxUҡ, _K%ZLfФ}P)b.j=qz&V1_Fٌ=j`&9Lьg‘FiBriF\4Ǟs>uNksA0!8(ʦQmhr3} >1*l _kIf!=w\T `\1UI6-56a@6$V82 H[B>f45V ׮9> $^AfU*SYh|x./ip-( d_$ J~FA eJޫJEϙ|#_=uX$qgs$bƮIM$2ր:*sNyFw!+4x^wB#IzdR! /Bʃ¨mX5*Wv.:yNDY9.Ih=硂oY gV?5txoq.e4@~2%[ҽ 5]N._IGS -`rN=l IW_X?m$錔ײ>/$5SŇDs"4՞NƜu~(6YS+[$LAZA .etb"dP>^Cy 6cڬJ$^hn2*{1`~fp-)pgUٙЩBx? ;sԠRʵQ I2\?QFt}.5='>g>[S|x(E-F>% Kyu+UI:C)2;In_4wE9M?4M<}wCCQᰤAbr6gY]WZLs(7I>pҖ˺zjD㥍ËRrJW]GmJEfݶ3rwtXrVOE)WF(LS5GLA` ݫdj *oWy5(z1pp? r~cmoa7;0Cs=ԥp;&0sEWdG>Sc;Lcm&@:a\6G} cx4IlV98,V`S^]xS8Kb l to`"DgЈvjcc5ꭵ@0c:^ֲ0obЩ~ʁ?Q$0{mGiqsڶohIb Q̉ǔnv}!/, B:PS5[Qj00"BH~?V7?)ro95$n+xD~OLGXMDYiv&K׶nZ,;]mӥg.Jת'ߖ"> hs=pEʰK+kyFV_B5`u"D},|0c^.1N/DֱCBf[Cc73ƙ-A-Tb_/+I^R5i99ztM |kD_Wȕz}[ߝF(\O6s/e%nB05=dbg?L>˰VTDQ>| 'S d/mYNA[ -3Wݑl>}}_tN endstream endobj 15 0 obj <>stream h,K @]f<!JhE q&3Ȅcr9>8|Wh@j*J ̡ʭE.ϱXWX6 F,|g7fӎwx qRbҌgdMLbH$Ӻ`:=YLƬo.u{x˲`߸7't4! endstream endobj 16 0 obj <>/Font<>>>/Rotate 0/StructParents 85/Tabs/S/Type/Page>> endobj 17 0 obj <>stream HWo8_A^bb@.{MCJmcsi%?w[X>zrIQꊙ|eGU{w}fG3Zx\]/r~c6y^&GUs񩝳8ZJYY/׶wqaGǧ9g9cl3f.4exUdn& KgNr6/] _oYQyV) Yg(wDY^يq%2pRYU쮝|` )7&Y3ܚ\Yղ:+4~Fv&'](>7LYY W8L, f _$=:aFoRfByΒ)3KgetZfE&ʌ'T԰GL&3S?ҩ',@u_>aA|7T"˕59 K?#gp-Z9B}0 LG,3|(PF|p $ *8HRXX;^B L%%s9?} s@$7)Yjө&-/h o`쾮S̉%XP`>W.fY.!] n𰛗 \R:eb49M ex\V 43磚 WR]Ŗɍ? tͱħ_>pH 0*dqώceO@4w@5o&\\i ҵwذw ҽg~.'L9Slppye@˽CfZ }'k?))l /^-n2{EW:i,% X S{q5{ G1N\ON0(0( X_Г#V'+~ѵs]a@%<1@T!SdJ:cuPU_VBխ#7+EvηʹZd#aE}Zf1VAݹ@ 2b5ȘA=9Rx>,BEqX*X:)B=8U!#xYg^n5^fRoe+iJ`G|f.b"]EQJvU~gu*v#xrUs7hª"v+i)s:jOTqG`MZ7Y`$`zX w1rhx֜oDn"[ww.кͱX6Fܓc`C0K~Anp6`YGӾ Y0݀y ܧs̬YAzS#M:f&b D C;9!ݓca<l ݳ%C6t/ ?w-!H[O N4"@ĵ 8Q8Q#xw24iE{O]!0u p6hYGq!Ch7G{/Wо?w-R![ON}]LoDn"[ww.кͱq.YM-Se'p1k6T=:K ӱ%/s{8V6P PԘz}(=1I$WGA4-3>^N(2QԳ72gfYހa:E Yi{ҩ ؀DPA#OǵQF|(gΔ2:Mv&wT\&2yH^7n9>Ys{t*ZSJ #(h2[A漑9q0`qy$H'ԚȀG0]J6{67yƲk5z.H*a51hai֕ߝ=RZWΫDc:͚mm0lMژtnCF3%]8ҹs' YC6zVsi-ӷ@e"0R$Ոg1ܘ&/ʪBnn8 U\ơ[*TҐ.11/*p(+tG/dt7a Q;in?k~ZT:5?Lڐ?Y=KTrrl6] >b^ܻu~4ErAԻ I_>.H#>|aoԷ;W_>1ίlsꦄ<-09,w 1mY`tW7jp!JjD LbQdl Vdndb.![SNdG20͌ȀLL;)~4%B_'EII1 }/v&"?Ty׭&oxO֔Ss25Iw _WkW'S71Ӿ3GNǘ.M4@ߚZuhhO3#^&=:Iz? }],H_Wg݁{3n42)ۋ:0k@-vif, $H4"נ@zgoѡN2F]׻]J; G @8!DJ1@rAj܂*aQ scǛ*y݅8d80p? NK&p\W^+%**,Nf¢5SqHDeҧˊV^c8NBY!q.x ;w =6vV%VLI4x W< {bs}%DzQcn2{@#55^X}W^YhA7qp|CyH<;4J^?,,y~a)꼆}85r?IwsCt]d(mi/z2 bm4S?/n l~̢ONQاIX$r\Ycp? =2!|3{e9b Ԟ8,d; F>pX ns0(AgyH^oK,XI#&S]C ' {$%cÐ# oXQp;VWW( Jx!G)$@_̺5"%4|47I(5Ʉ}?K@dG5_m'TQemF2g =7t^΄ar߾)ވj_K(8Fk`N$։,ў_.'}W/8N9X;_h~pyzP=]iQNO(|M6zN&\9ߊ"#ojE5h;f%ʇz)X 天N-R҂ | ΂QF0(ݘ4shsT簡>rxSaÄyg/]\7hmI:8=qF7oBl&0|`x6nȴ#oӲ'4hYZ/ !D2A2J*q Z \T T+;ndHοLb^O3hΠ"agvB)˰?s=~]knw V4\-cLNv~&j1;Bn"ʋ1خz7eyy:ՑV)dʟ1vqP*T^T<)UVQ^司}0'~$s"s"ҙi9&tfhw3>FfuOɉ>i-%X, 8HOni' T-X;ife>k*)+&j^JH+}OcDyTBܶ{r{h]+p.!ת&U;`;1\ڭJ-+E{9YH 춄ے;O4.fi9NhsBGɼd3հ pxrgHFIEb4OOE!ɔzYw 7EFPXG|6 ,EuJ=$}L>6a ,T1nPmsAsv|r.rߓFBR.1ӅnϑO98BB>WY kgI?/<"Ѕ㑊m=s5sid;g7* lH158VǝcI{jmd\C2x7 [GDPh\^ qKY(H֮H}ÀrյfX>ma'_OcjimWӳ]^<`"ޱ Yd# BZ%mc Asnz{ԶKSdB"]\l^w,`)oadF$Yڑ5U3D=/~#8ۭqaHP a黱gIg CෝCB&C6SJ'h\l*a<$ #CI7U[#(a>P[DPE9lnd`IR(x2:!* g )qK3*Dzv`w33C=; *a΃Y-acKp3W:8yҢc)!6#Cٯ2lEE^;83q$G*A!KV#ѿ(l̡.Բ\y/.u$C8mA [axz8àQ82YbPry&nri8jaƛ $Ae|]a KuG8l؉gĩZĊ{ $;{8TyZ;Gc5Õ\r)}C>:Pb5G~QY03F2tF]/L9 endstream endobj 18 0 obj <>stream h, 0EeA^RʂFqQZPĦHM 3p.ùL*5)4]Q` }g m Թ?4Xc3@qb, &\+МH١_c6,1D֚SScv˲ԓ>pW"1 endstream endobj 19 0 obj <>/ExtGState<>/Font<>/XObject<>>>/Rotate 0/StructParents 86/Tabs/S/Type/Page>> endobj 20 0 obj <>stream HWQs6~ׯ#ةhI1ˌ'ĭǖx(sqH5뿿](Zi3}E\.ۣJ<~t݉ċ/O^E&Y5p/L(Y(-^5/EYʈ4,-JxnR2K P6#vFXuII0M<-4 b]j q/W{LSe/s8WFޒ-Lr(!5¨=pFYWc"ah&VY*,4dk&xFr%Lo =F~]IuO2-?hoBQC><^lޟnՎ>B ̎0ˣ3;C ˶7|vU} X2[*K\ On:țu)}zGmys#<3 4rCL:Opܽⷎ>o:t"]eU- j"rgJ ̰Eal3PI5G*tJ ?ڦf*G k%O^b.*yyAW1tVi?uQi"&no4˨Zc  _ T PwJ>Iܸ/I 5QKs>mx:sד0Y m-8vS^*L  i4ΣKjvUaTQ3FZen GjvЮx3&J`<*@45nfv LT(Mfg?bǹm]تq[vc61Is)J=WGFC: 4@8)nVjtt53+bIrV-;I>׃zpPcm_ke'o*\u[t,Exk ֟;tal X,{V:sBDڞJ 4fiupHaDRDfw6qw:@;F5Z:^ҭx,P8(yZQidYsm,ݿe(t"'z ɏѱeؑuM y$3i)TBfP,nI*Ӎť2L& !jf?XⰇvM*#ąvMwd4fюvG1a`4Ba^l)t%)pg(+@xYS7|2S M:ZGI>d6]0F݄R` J.zVgSQHPzGJz9b,"x{3_BY,3R,m{p!\څq`\ԬI㘼|ҸY*8dh8¤d]^tN*)udR)X?lqCAYu=>Rd]X 5K6BwUZfTLʀ59C6'zarC{KGxb:<1B:rӢR$P(YI7i`6f)ju;pB:N ,9KP#̩98aCgwWyxq)8c<@pv6LWά0!EKe>  cNp9c5tTcMHG0W?^s?P9RO$ΓO|I=C GN &mC,QOq ,0F*4  >#Xl4Z̑6ADiY4ӏ**H`yH8-mxJ!RX  icF9}(K2|Ff\;`ԡ;ҫ/$ YP#*[U :rp"QB^"/At+hJHTMcsC[5eO\3ڭT9;n ɅK2 wy)' Yt%J V-zJEsYX?P&%%G}תK&*\IM"Y\wY^t̙H+e@Q̉Ms\7{9ܴ%u;!kR]HE*TbM^*%VyJj!V@S9_L 0 )kQ,(~`nQ=d?hBXoS*Sx֊J5rBt:c9:>hͺ!Dw VN-?K)'wYvk{&y>;L|皪B+NrjTƄ3}ӟhHpP zPD !HsYZ VizR ¯$tʶvr:zc=zΙEZCsJmV4TWeUPrbwL=Ő >F{k`:1M)赕~g=BKХ#8Yה~ %T'I[ QWl-Sf8э$=Hbk[5lZOueE?]SQvof1e]Lo!-@DizRXʓwY 6p{ 6]ܝŪqẀI$|A(DURx\`;] S6W(dTR0J Ym 3F<Mz H'FRfUYQ #ed}֣k"ZjY[k1Fזf-4zcd?<$K.5&%Y{'-~&`A!35$%$Y1/IGd9KwUN]UMYkiJ^#Z䳔r,=S-ڶ_b>WcSuG-erGѯVRMhW')|.U~u Y+/89)NfZeT)5.y,Jr{eS6W(( endstream endobj 21 0 obj <>stream }}}zzzuuuqqqhhheeeddd___ZZZXXXSSSPPPOOOMMMJJJGGG===999666555000...,,,&&& endstream endobj 22 0 obj <>/Filter/FlateDecode/Height 157/Length 132/Name/X/Subtype/Image/Type/XObject/Width 692>>stream H ULW endstream endobj 23 0 obj <>stream HiADL D2D8x%K?^ء"~8_jE!             X:;H95bB'8oΞ+87vm׌ "X(9"OU2I2Yo<ڲTp,O*vy.ٕՑA2);~TY8\R g Ϝ]@T&IVϲ8bμrm.qqiSl6bu.h1Y=率kYoT+{YNGٙ'3g\W2IΦ>,@iMg_'n8`،JVxSpV%DeUٵl(eے3aEV~Nfm ԝ+u}V*Wz Q$ugYa`[sVYj;lyUwb3λ[\wVٝIJۜ&e9 F:|=O_^sA5D 2 V _m[#Yuz;0\3l3JP!gcGq`5ts^x0`oE `rg7PU=nMC2dwv y@44(h[{0|gVβ=iTzz2حTp9Kb!,A|۱GB݉jQDwXg{Y͸WU /P;:tVב:4 W.aAKvnǥs..:Pae(Æ^b]ܰ8S &6h[gi><|dX_tDXʡC3[[y: Gh<xrr6,vZY #v9tpcawUgl1gXkǨ~/r=k&0^,la-Y,vZ@>Z@9{uپ"gfgMqpG0Yqp59Jg;bXl+l9R' gG}rv' gӷbeZXiмi)ؾZi)b%ECm4[GIz 9[VFtXcU(OH(Z3\g:42B-TZi15X64oڞ$~ks~tOGNj;4 #sY<)w}gkC= ⓝixlY15 x9+4g%g{4LY jwKsqkK 7"eg˳~g_{y_+ K8'1󊽖tҠ[0 Q<[?/0@e{1=pt^j}?QazٶaumGŊ2D]uXja>^&({a::KC>k,9K̏1\G}|:Zbhәlڌlin]a6,\ }9l!gm@Nrzf~EײG.U L/1!tL b$g<#] ;KZY-Yx=;&9rv= g'9rv= g'gG:Ųt13G{_iC `m`Io.!_lx .ZE+DrQ:Mđ&v)Zª9=g oW,+0cp=7"XX؊{0!,rK'ˊgO *(9+8+-;["`%: {T[rŸipCWh:˔p("aڲ3qq{OamWrq([g#'nRWsg]bҷ,Y2;g;z$/Sa%L|ɽ6AhP)LF[뽅AR*UB4ܛtrY722[w8a R=duCb`83!LF̦e]Uls\#P[[5k6u$V~s~gd&H M&Z`}[&ֱK|3U٪Zcd:p? zUwv0kI^ K[&djb2:TuX:r"M̡ٔb2:knGYcfgS{@^ WJgdJ?dzu@l$w&V'g/Fi,60̛9~Jl @xT|!; *uyg2קAAAAAAAq+§ endstream endobj 24 0 obj <>stream h24T0P60RA f : 6G endstream endobj 25 0 obj <>/Font<>>>/Rotate 0/StructParents 89/Tabs/S/Type/Page>> endobj 26 0 obj <>stream HWms_q3d I3ctL]OZ\H")DXܾ>ѫz;x Ekf>οGWO~Y~_v4Ϸvd?p|z&gq<&^׳,t4ZU+lXUVUh|0n`׏`z99N f x ш*s_'xK6=|2/Kpk%Y)YRTDyQٚq%rHRy]5a1yϖǓ+nB,Svr e#Vy)tf{>+j3i%O `zdY7(oRB>$R"L3*)ͪL^yrfw$e2w/d^ʛ{ރ8$W#R̒LP:eJ͝s\E a y+Ǽ+$v&e}/Uah$z]T#Ż /5 =RQB/U2u(Zm(O6s>7C,@ H!EԸFQ3YY}Hqut5k+l wN&˪+TO4;y3&lz[YnC6a?x ."h[ohl1Fw_4g:heځri"cŌ"\޸TB'0+v!掎X9S8HC VIG2J7#H{Sy5, ;XVň ƢgM&YC0N&yVi%~@Ӈ{8F4.mD\`ĞfM2}FUoQ~*Y-C#͡a[4ۏXQW(++(+϶YcQId{&sʋCx}V+̽ndŲerYZ @k!O¢>T;.blQg2zz`%0=Pt׍|f§""EU0yl{ Eji0t7ZeϗQ1Hr ަ:J8 v Ac̼٨DE,Uۍy_lP*YG YM$H֖zBhG{)GGYE-vZRI\>,H|^r/Fу)6p zBg={Q˹Kn*x=j"i,+ #5ݿ9Uɜ>gD5$JY>XWy*Fw&BW3_`?d"=[\.McMzrfX88ۢqs zjSL xo;=<ZkN;n6Bԝubm,#{5ܰ|', ػO<_a:زr(q`nZyzR}ۂjT;adKw~ FFVt< , ,N JFg鴟goPLM]]i@-A4XⓊTGU~?V^EhGScIM0pm(>Luxƴ38iu :m89]Q$ Ɛֲ~XãD\7шPw Vz/p(pWWhݨ@zG%Zw,c.A=]]K6w|kÞnfu?*2u [!mtEzQ=5g-t Т5N#;tN)4Y ;H;u H;;/57gJVopYSș^009CGsByO oKj>tb\D"<oG;S a:Ĥ[W@ .8rګiOTc=cX]0L]"ɵQ6K1v_l TEnAbﻻ;vNx\BUS$.2[]~SL:G=\Ou[A] c.\^x֥)]8wru}=7_"5,>gF4ZfSrn:`:JBȜQS Ⴑi=OP4R4ʑdPDSLfjy@)F!,AWY=zQ":bB(yVh6tUeK*=RzKXRdi/ r"v,b*vm agHkCoѮsொ{5 m4=o_@vaHkOŏ*Xk!Haaqfˡ?0{hLfRo?#Phß F& P [~%Vʃ-J.|7UN6I$ ;$He'_ސUKj(DQRC/P!+k-H8m BjE_h*àSPUCzCzFpqErM.y 5K"_4t #Y$*I̹FPUuvr֬lL4@? >Ĵ"Ux2q͗ Jλ{=@- qآ_}lӝY]L>ӹ%r]"z:b?{49t<#02A^#kEaUFKLbǢbiO&bx4G3BLGnaDa~n< د "83yQ+b. hXe~^/`\n܅wkKLea3#5[ȒG,oި_ ˮ}ktWρuyfR~rHv`/E>bBk:~/@˃fe*̐ě I Y#烑68 eFrѶC3_-ˍWt?_K*1!dvx\vULJ$@R5Hi}@fE6 6sOQ*N5;l_q; t"nhѿDL1hZ|oeMF}]3ghP}/ BZ=eb|7Âxw O⾏5rewNЩ"X#*⋑NH ÖߋyBev`V ;nkFP +|8#KRJl8* 7pf9 l-^h 4[4&Y=!*ɛ{55,;}pEfۦFYR.[ 5( #Z%<ۍ%phT\ffC*)Ӥ[k=0PQBkK,t01sjwK Ryv$!#%*) A\jq2 q%gy@y3[㐜q}Q}~PPaU^.`Z*`ܨfiP]YSs>צ{u=b>pű[@M>Y%wgqP3GATÐ]'NqبHh=X?g54DwtAšVvC Uf 7#æz i->hWzfi;e8${rPZx?1>Ok/5.f, UvkTY5*U7IY$p}cs(SHȩOtnU% {puYb+زojxyğ7r78۾s{YZt\ŽKn->ћfY 6łV `Wp3Yբ n *X/C\.hh}~il0uˁ7^R\QTYdhUx`yxw/LÖt{ gis+)(Wz9#bU6ͬÙ-<6s/R@"դMӧ{+-uAJ/腠pp_ PFn>@KL` 6!)"iF:FءNt=.֥~ `H{vpэ$XJZ@YW8 yx^-W_ӌ? ̳PŖ5/ESV?JYD [hʅ2`&c$? :aVǃ!{,"o}kqLj ~x mgDP%xܕ6,#IΧD/PǙ2]1'; (/łd8ͮwuý`RZo<IY̮+1i4 IcgZ.O#Ҁ\ZluD%lo*$~h-"z,vG9܈`ɈpR(Fu̵.3DSX0P,Ͼ_Eqn}41[01[(8 7o|jh w;5\z^iCJߘhOF-G}_3۰kB|yV#Q}S(p endstream endobj 27 0 obj <>stream h, 0Ee&H@WҖ.EMRI}p^(P`A<80 Ned)"y`Xl)/X6^<`9-a+Pcavx VM8I RN.4Yf.u~pn> Jn%vzޘK7% endstream endobj 28 0 obj <>/Font<>>>/Rotate 0/StructParents 94/Tabs/S/Type/Page>> endobj 29 0 obj <>stream HWnH}W4/`D/d`_I); -&[o~&E9N&NUn6˳~q ~LJtu]Mus,f p˦x &/b2 Um6˳OJ$\Xe+sKa3„^UUu[`[ q{VOfE*XO>,Qbq=DkLd&l~8N Nh^3x͔ۿLTB@I [j)s\L &v{w%k԰/y {.LlJsaL4ե_H4MR`q&-L N ĝD{,S)6ɢxSU--`O٭ $}OMRFUm>bkXx@cPKbe+D[Ra|><A0dRmRx j@0eR D|4$BdM#ڎKrP$&jb7N;Aq$*%]Ӯ+9L^ `2FL4&e>U7P BGUo6"fNb+=9Tt'Xi+ ĥɆ3g),NT^i'lďjEfD ( vW]8W{չN!B\٬6/l H!EbCGM $Gz33džo.g>+ 'X9쌄ABf,ps^_?\r*~qGa6Angח/o[~XW\ (\}Bo~fDžx_@ n* pA:G/y=Q\Qj 8hdR;[{&)]ySMaI`9LRqlK~#M$YY(㭗<#-Vՙr|lEuP4uN(w᥎ f;+rBQ%nXv#)CKR7>N["U$?qs>{Ż'0@4+ptU Im,FXw kŬZ*'&Ch~q7Ҥ_4B>U{R:WlgY. 2ŔL`<_BˮC,W)iM2n̸ӫd{]=n*8^ .S#8]y F5d []銠Ǎ2}ChG+2aPl=KʊGB|3# vlƕﬤ4}O[~tى=Wmϣ<ԱGjkVP=F}(n׼E!A49ÓO ;pL?v,_fviMfܒI2nv9OA Cmp~q 4Rivw?:$y)qN[vn{H\"!}|_a>]ut֪g1 FYEVkXTGÛ麱RNy{U#H[ȻH^aюR[z\T1j1?>2$ '\K*@78cVti($W&Oq( S-FFgGڞ[,S.)KY 2K hr"I LTJT1BC$-bxq !*SSWs;q(nJb`daa]~vQʶ[ǖʌ#7(P(W%hePgr>);lLqPzQgnoxRE0ZbxP2 -vf|a`]miS2bKؠl|k_ m}}J yrqVq$|s(Қ-V H.#=Mـ;'+ 24U˞^CV)X@{@ĈpY\bK).˩[ r pr?#~gGL5/pw\ѶC-==8`ѣm-ilۧh1 E G-Hw1բ=l'x]`z'xG(vHnW$ŭ@!h*v# D(CѰ2R"h!XBQLOEZ+ddˊJ\RAPʽ6EuKBe %'pive IDzBjw[oo!w.f#AՋgvvR.ݎ;B6UT>^U&ـOY$@1G,1`"*f<^/ 뒎u l@4(/W9V:-z]JyAt@Hzg8s23Nr鞑?6D,Pb](AΔ Sznx_-j=1e%ݜ|p=||峣+oQ~ͧYTgR'?$! _qyyP7Mк mB9ysM>(07ɚښu }Q9_̀F2%qwȔŷ^}!"9 a$j0Qg*6DKZ!Ӹ,2;Ql K-6GfQ 7XNՑsRN'n9Ag½Q0bhOB,,ZB>!_cSG!ި؋),,9cR -X]IƙՎQv;k.DX} /c7,1fY.MاͱXǷr(p`8q sA 7 йqxfRzpovʣ\Z&D5f,K:1#zJ{ڵ\e$ N@67y@_= }‡/M7q  FʎSMQvi>b$(A9vƅPQƂە rd8G & }zIV@LԦa`4~M(Sw;%6ްU,[6c>3S(g(1yLl6ꏕ̅I;pK[Gw$d_&en\e$dAqX1qd;KMj6ޭ4[U޿ƟC$ǐRL;:4Mh8'&\4$ߧ\KPY&C/<^>[d\vV)K]u}rHSdh'e5I]٘.uBLcK 8DnXmԗrJ/aQ'P}IIG{j#O. %[UYwܓt]A$nT[XAjրΧt|1/Ilz0`3/Q1#FQp@S[M&,] Øʷ;H՞jHުJԫ&m0BJp˾:O"HkLk X2v._4wiS/p1HRnXAV5FZi& (UTh)3B Gk*Ϟ4УQM).?#\Y}5TS9?j(j\'7LEV>VO^ثzȤ [APhx4P p'9]C@nb*L3h+x4$2P dp¡eC٭K^0'r*|At[yj}OơYOA nAVH膼Etͷ Y@w~Q 'MD܍)fjlip̋gHS:8%nJ}Ey>a|Q6¦C' 9I1)Z"Ǹ9geJc 'e˴4#x:⊝>-\ʷ/ЅԧFߛxvR4siĝtO6Y1zh R HPK&t&-Mw ] vXqR6w|ȯ=Z1,\Bz摧7Mw'F5W+,:x<$aGBq[{>m3 +1Xtq,"\qki}U+O/ÊA>VփoCw,3G=%"O+#;Y^{L3 +7Z|wSx,suNr峨C|Y§PU-2T\}̭t,bEFMƚC*o7p ]c)Nʣ6~B%0tsڤ<+R5HQ3Ps * Ge*$SSI[ 8:+ ^|hnXU/ݨ뫗~Qv6Sn@PNfа];Ԫ׻ݾk=Wz =QreB`"' )trKl%_1r͑{5fEO4{_ d W73GЇ it 69' ']qG"?\ Q٤U]hR7w [ffg:Z뇙e։!mTKJB Z{V#j+cγIv9zP?K_|køWVN!+N|ȟs}3>>qFӏ?G" ,$zaR#u̝3$SHasc=5U ў_K@8dJ~Ў0qai^ugz;㿫llZ7';Z]{G+l\4TfDMmtnچc]~Gn/wO.Q^c:Jj^ L}wZQ:S]VRy3=?;dn1k\c]KmEpeG[m/ˊo ^5grsu`C "Q_WO\ȽT;PO6MJi+kqiS&:CĐl K!f>ѮA\.v+>stream h, 0Ee&FS$ ]%-]H -*"&V(0OBMt RHWX X٠6;X TMzk4}! $' DI8IStzf9 z}s1ut@\ܦtZ46 endstream endobj 31 0 obj <>/Font<>>>/Rotate 0/StructParents 97/Tabs/S/Type/Page>> endobj 32 0 obj <>stream HW]sۺ}ׯ/d N&3Lr'u'ӡ-:L*/K;Il vϞ={l*/7ɓ:OχbsѻrSo'u4M]nnZ=}zDM^¿ofS^^W u~4oVش9mUR(iޫ\T뇍buyb.|+Wm4aE#i5*>TG:S2@g~3$28vi ^3?OLŹrJ&giB;UOfGx'4r4S1=։2K?{'x M9ߍ%6) Oa0N0TWUD)I";LpN\p&( ^$I85ItsSt4,5Q(/ԟaL0._ma &JE8[g`F6 \2LOB牶0ZJ @'YAݞX{>Q4!l, .yKB0׈܆h֒pj4cc0ڷ1Ќ0ᧀOeM,MNC↠gI? JAn{lg"<~7:}`d祤x\N~L}U:_V$"-^ZN2r2`8=y ۣll(Lg!"#V&heb٘s5cd9P+J->}7zm1̀Oڥ+ۍC [ۗ/߇wZ4r +A! 4Gʸ qO8j}܇2.1@Y.J]U3MP^рCE;|լ5!%tMSG&q$:IvՃ9CH>&ˢX)bKBf;6$4KVg]1֌ٛsoh-.i+? AK<]X^1rtq} D h'!''8J!YQ~Cn+i1F.ZԖRa- hfوgΒV[f`=P<7˃[)>Ѷ -jwÆtyf4<.G{hz{wQSJӭ>;aW#k <" @xkP4M\@$?SHfqOdp-eiLN0}ߞV1uaYGd>IRAS.1 uֵGjVHoxX!2E4ԨHEEZB`fRfWLV!~?: $;kS; ! rCQ5@o0@OemnʼnZ3CABJmPhB7S77IX75vR[BEږ٭$/@cg[hq tm}ɻSnh8Y4yV3dտPzr!Q?DE*/ؼBdH P!.iUW_#I`-%dU5(7QΘcXq϶ O{ȸ?D!y!%p]=7^Q:.ASZN4JDWr:Uxy}ل{֡8-@zˊHqo(m3lrl8ߐesa-9 3srH#Çq%kڊ>JڎtpjFZ o;{qm2EjZ.O E'i4fXas{aN 1$ڢ )8%,M,ǣZ; Z`:ʱtL)-E?}T3xw8PhN?`;pT"\dgʬ>|aw<>5A'P5x@9ChAnCM~݉(f+%dWfIVbE;8BzkU]>Rx ^" s/q̥uUQO>GBoN QK}\>K¦O_q!Ҹ*}mc^>aш;krJh)R֎/OcZbw/H͖^J/ʖqϵU'1DWrм,EJ w03lP m!1bRYur Ô.<`za7/|{]*NjE$^r%.|}&r- C%98zwq*COӵ(u ޯa8BI>NKmͩpp~o:|leДpsUHq۔O/,)||,b[V'p{u5y|I.JO&ն۸DHecZ5/ 3 ^xcXJ,#6K﷮&)vf)/u9uTR(pid#T?Ebb"]&d\9'.hītO;8()axUSz(g5( tك]N9ƈth{|y~雍xbF6@)C3ߢ^6+KyF2P~τU$kgdFMi0_ئ O_XBct^|fz71sF̯ vH3iq%i CHp"Cf;j1Zqx ҋi tʁr9dr=THtzz- {Co5<:֞PgAѸH&?BL~&v#vy1'w2~chGU%W0"8ϒA\^I<>yxL߂/3a)$ͩ'msk YtC&5ʜq_RŞsU|"׌ĕѸqD3Uby-1q⼑1&,X73n>t9X,@eKz{;HyЏ jGj{cKCx{KV&9EGReP*Ƿ6Íd.9kӾG϶%oj[}ΓwvyŜqԣnG^@S7\Cݷɭr%k9I'(+g55JoZ`%pZq^!mC2;A(6~r72"0͊ȍUe㭡%֖JA϶~fil |Kt (bgdi2]ط e0ɷܟjd^`+sK@?;GW@F;g҆.}fr2FV'%R肰I|UMxƴS F)NAXdՠs%: X kVvZhlxVd{q=Mț~~ڷ*Qa iꪞWqQt싓^k{%/Tr!910[Z6\%XG̒\f%R"_Z 6?^"׵ E21<8kDOvVOѬzѴ:Sѡqj(Vy8~i`ZVD4ÁSeVo<Y*Sfʔ}$tE1sHF8qrlm/9D.Q(+V}ݭ=zs7scUk)WeۘO]kkuY޵9oPEA[J%^ o65@L@`N FQ;Fu%w ?=9TZROF( w }^"BreITi381V BvbCE;¼2%C?R^ظ|,''dǃt2* O짲,ٱY?L"iD_DpM %k͜&lU2#vJR^tv͐ 4,?/o9+mTrL9b@ -IȢ7ldt#Ǥ?stZ OSg3{P%Y$ S00L TfʵA2W W;g$ČpOZk؁uRPrlZ#D'dϛs-z\'0N$fP?F80;4&.t;NH4CkH`◻#7ulslj*VRru=wl)|}GO^֬LQE)=.;rөLdujB$ִCz* wmƵx,?.zO#f7W\6QЗ/Z а2.Ѝf`âMfA-@S*X5 OO0ո*=^N}(n5]3 P5ʀ{ $}%*(m`yTLTo955#t# WP~R`x9*nuG E}hN2G W轡8Yخ0+wڰN 2%c}biBnf{l+!Honcq泰G!P M}꿎es2dF38xL:G >Gud}/gi]pH;"5tRwhnhW=z4X]=Osy9'M.:\K2v&j=H* bjDF/;>c)9=nM˵}a,}<:v؆wC7m/CMǻ".3׷h=mٷI -/1%>dLPT[G3 m#>`^ Ajzs)|U^2 "iv#: @Iġd:&@lVy flÑ/v'=C=p=pm[I&.]YI`euVS?a iԣKs. j˦<:9!GP.m.S"6>+cqNq@ɤ ˯ַ+^55Sb&.ׁ*PBe:nɑu;-;P5qWS'8)vkZ>g,HH9J^y~ "wq!}Raf_X:!MEU 2+A H`LCxqn~qB` endstream endobj 33 0 obj <>stream Hw|}3swH`{N4cLUP D1!`C(96 ѻFHpH@p]愢?瓹{;7of;ow@ࠐWD"S#m>^ C:R&| б<zhh_'7ǧqb#cn$HN:R_'!5+7`^mxeZJzt$(H=+52ֱ@+.ةARP[zfVfE}%']}w1 T 56^8)B`q{\4u fv1 [E#/FdG.)u,I &I/leS TjJ-UNAN% *{pa)RۏJ:u]fxuռqZ6Siϴ vK{=Aw->@чz_?l1au-,-]-2oZ8[X?VXY/ZoXk}#|}z(76*{MQ#679z:Ngٲt(ýؠ*T5HRեjuzIS0ErɁ,"Xd^^o.,ʼjut_ neiUT{n;Eo}>Enӳ5zK,!9ŚV$6em,H[Yː,ҪdM`.Zi]weG.C -WoO06Cgr3ӥV*Ƭ=2cTze m9SqZEѦ4Smm,eXޅR;`;w7հV1mcxV $( B,3py KpvC<<=\ $HdHH2H |Ȅِu  a1, @/Cx pG MЌ'$pЈq ` a|BC7tǩ8 ~1[8g,8< pH_*!1q&`"vN@5_aWLd| =MLTLtav'/zYu4{b6`.a>.E}Њ p >A RC{S}F>ӗttVa:tcTAStY:G畑(@]o }GUFTF+cpr\+qaVzެ1? ^ekl { bfo߲߰l{S Wv+{P6 g#H1b6cj.D6MfSX dA,X#(w]ԈZq_<u^<4615}c:f07042615c3L6fl0-lsy "B^ėy1_ʗ+*\*^ 7j._k:>_7?pno;p*Coe| ʷvg^wX1N(&b"HbӕhXxJPR"%Q2P*Q:(S&eʦʥ<ʧSR-QƉ-1Cl*戹x,.<&i'<ȓx2O,bXKa,X+!XU@$Z`=ldHT`3Ԅ-v;a=j>!A8cpN@n'AHpY8g.܍{#D8"\)pY ޠtu]Coz5u-]['P01E܏q7FufV͐a];.E)w=)ndM9q>>cJ8j M ܂[nj`bjZ 5akihw46MLSLI O&ܴ2Mic"M[eڙhε#tLlt6]LWc5Lwkzm˧ s< s[(nܞ;pGqd U%_jOHATjP0PME)¨5{ĝ ?xY<9x/EiY)}N_ʷ'74&S/JhͤO4"ZJ-i9VJD=ZO(R(6RkDi+m>:D 4J,ʦ:Mg).%+t~tn]O1\zJ!}@呋k؍؝mfv؃`x\\Kqi.eًgW*\Ur wԉ:SJ1.u~ρ!ܓG Oy _7e?/O+;vB@;_k0i0f@k5b Yqpk(k81'בּ0fz^W5:ѱĽUjTڨAJV)j?nW=ks9N9@ch;'<3~q.ERhepU`"$\qngؙ)̶lhhgsjc/K c,pb}YU@ejfN>4i6;9oM|=!?NiD ~?:mHTi4]h.f s·BK- FЇRARi0B%S+a9% !QX#SL*=B[pS&\Wzn~=ZOCqҤIer.E~E.bh(ȣ<ZFA;l$DQ;q<@ă&DxXpxa/yA*JE(bSq<ȓ<8'SxOR)tLBS&oLq0 ޗ/ O(lϨ|B@n"Eu2&*zu5闭 Wn*o˛3q]ECGn[=$*9ߦݣ ^㤍Ws%o YC]T6-[4oִIFya ]fHpA|V\b弽ʖ)]d Ŋzq6n ^I^ᱭ%yѪ:³?wgA?Et B JN8A1hEta! Ej*&42,nBB4M)yFDVeUnAE-*B(B&B)pa켝|3{Y;a/]g+I jN2鼈&Zss _4̜Лo)Sݎe'jTyZ2ڌv`Er%:ʕ4xv;bA?9;>͵(o j,S9lv;+SI8JF)4~.y.O}~Dr~;W܊9g2=vZNw3]Nvfݺe&$TY I- p_ȅ-/T3 gwsL"s"o4<ЌVƇ'UV0LA7<>7/FGhIkΕz^p-\|p\ζ.v>E^,mq&kg YㆨωY^54/״W2/$O {9\*.IZ6,N@}> !-/!_Zꃝrcʢ.8\"Cf?~ZݽNd\К,x7z^],20 iɨG7f | zykl>ou5Eۦ'ƚEc2a}g;\֐ &&U/usԱQP nj0 Mmvym^a2g +kW !چ"ᖔ(2㭭C4t}f x޶҆Um:Nsy-dm<^F1 Hs“`Ĭ|?p;E7綮 4HqeqP^`㿛gP&D\֌9Y3j]jX?0=^]o>({㝴Inhu4C Vjfkx,)7rN0%mE")"θ"o&0جNr`*<;1!Br,#]{, e&R=ͦ7;ht:ߧ*MAs Bd]WIoT~m :tE&网Jact"4јo9 1:Ev$-Q/Q~ h,.Ekh3g/C;td7ߡQ~,qF\_i݈zߣb8Jer=DǕۈve\^,vB%%;]ّ3Ԥy?ivD޿QN9n;Ø#HJɁ7@6d҈PQP?C1{&eu i+GL5e=wsܿQ l.=խLk3}Z'hs> 'Ap+32h'C?h@@>K ms핾gpKmdҷ _98I\3IYamȸZP՝Rf0mSWRrZԷ([}.cqd0>qY7qϴ[ݢ=XtgsH[\e?2ГYpuJJ!sr#/@)s6j{з?vF.96Ps~Y\D}_C}C!T@{\MAΛv'}PchPM>43I}Hߦfe:T5U%-'X{){ĞߕC9rKiZc}e~op/T\}j;y>#"eC;MQUz) 5Ѹ|TYW %>&6 < j5.ng1{1k>|$'^#h;+R Q8XO<]OhY0_g9 \c΂LɃ!psyhEC?=x )М] V|ŃVmedӳ\d00}`ƧS͠Zgnq% sRNրvYL-P?GRf؟>ij_1n WE}%o~'!CB@Vnr`P<@h?}g߈4a--O75;mw)oEsN;|+5:ni{N"ח#.wKmCq<կ_pD[Sg1G bp8AoC$niO2gdAˌ>)Cu*oy@'rλ9/!)q: l(7qXjRlǎQ#sRmH)yO!QW,Ugc]|h}"ljLjք='jXi0sæWퟴ9frsV*cw;*=hy45IF4jRGask(NSK,N*@gmS[::|Qq'[o^.78>OoGò˚gn $ݦGjJ sQJ gq$1U7JMWgr^[ߞƽrK\Q7pӋKz7d =c]װuMf-~5dG:eJ2͠ e>]_Z,#W_e>ZE8[>mv66s~:č/o̴]w2J=s_O+Ą/ 8?ǚk9'>F1.n-|~ؒV}*mzYHKX;|Fq\l/ưy2'k4")>KؼBaܳU/bp`mh{w|9w:<:bB >>m{) ǥ2k>ΐӥRk-3˽}[!9rQ6ĵ Y5";)lcMャ瘕Ev)ˌGwy^Ǝ8nh !vxV˗N96ҡ,x)[9wJZ:3Xe_Eݹk?ߦ>A땯)(O@M=U~zNͫc9m=h^yj=bDj 6ݦ:mH}Uƿ`t$$Cyu+ ׾8 ڕvo&;fj_Of" +f$h[1?bG]% O,~<wib}F3>CC~ߣ~` 7]λ'[Q(o"15B|iEEyhy_!YNc-bX` Ql|SM/ &н҂jӢypo$/L\mu@Eu{/ `۷;WHEO4+ǩN[]wH<Ace/2 ս_shZsbֲͩ_UW?^C^I҄EBR )@6Y$Va,#S˒0D`bEk :,s雰4s;=U|hZ]o!oGVzgqOiusj//G:"USTK*(ƊgQ'hE/;ǒE__6n|,orjYTÔ1\YoG 5:tPb !!X#R_{ UwΠ<"}}ډ ڸs~y-JAsa@Oe;e:|Po/@py(s:;h_{XW(34RR}VHw)z牀:z*"v{Qc_4$M}g9Հrn1Vh~mGi/I :(0]].VН^mW ŵ*I#o)mj1g@?V3ˢ m⛳NO<'dJޅ8v4|75c΁ obu\g$}gx,|;JNɝ'O2?ms K CY x,_B0C3+^Ckg lknHs21p}y<9-{nx|뼍`3c {h[)ՙ{_ 9g okMς@g99 _ pJ)SOr9-]g 5 Vj=ک'Rsʨw4:A#('`/u4VVQb?/ is<πg_li6w-FօzʝqnuЈyq4c\w!bAr"nmS +4[ܡch7}y 7⮈1~w3Z9Iй?p_{#=%#ב v= &"h@cX)xP)HA@l?rh4OKPGQRQ4i޿R)V9 ,1@li&9T޸׌Hsb=i2:C~F-{Q2t_HR GlmdFmpleX;"o!ff+"/T'"ψ<-ȓ"(ȷDzGD=+r "׋\'r*DY)rBE2vIkH|HNIb3˞-=b\sbgY1?aay7)2ҘĢO'/]:<{ o5F.\t}x<.9WgcOtܳolS=aC wHT۷Bߑ'U)w \{O_$\.>::Gj7J5۲Ŷ?cjM\-MOWUsM{!e2k!+f9Rk\{ 9'$>X;u?؈s\ll3yR{ݭ+q-UI!'mŷv ף+}yWV.( ` X VUiUUeUJZ87~ۡ77R72Xy He2gx(=''d M.Rxj\Fr?))&(ۍ_l MnHC6M%lL`LsH%w ^ GjU?p<("REO^DzVGE} UD|޼̼oe/+3_OaBUUB2NSܔ7Cԃ]H)=Az z@e oT2[ڭz}~Uq{TٵKe Ye<&|3IbŘERbDN@2wX  (<,I<<\^p3ޘnlUq* ӖMQ2Lmt i[!M8F>stream H\j >wٜ%PrNReby6l*s)do݀@q;@ڂ.]bqi"w8=8YWȁf8}ކ3aK txg^삠+v!a{Bhk 5YliFe̓T?}YV-ަxBm̒N(}H)&,#o0 endstream endobj 35 0 obj <>stream h,P]k@+Pއ%Ab)yMS=T=1Wޝr,3G}P?5@=1P \/-,[Yn0u&r^DH$jUp9Ϝ0"d9Wb̦vwA86WoPFR6W!heVWgTcԲu 0m endstream endobj 36 0 obj <>/Font<>>>/Rotate 0/StructParents 101/Tabs/S/Type/Page>> endobj 37 0 obj <>stream HW[o~ׯX༐ͽpIEAR$S)[EՑ̒KTy%ɓͻjrz%.m!r'T8YfSnӧgb;]NBOvju]ɲGiE$VRY„պvrHHNTH|7JS8ObD,Y*2X>tV:2P;M EK33%i!r o !Jlc"/]=Elg I&I褉\$5lʬM2 pv.goA$!71.7pqI ,Wh$ʤ}:Q&`w=eg:)d8̔ SEğ3iᴕA9$N64E=ٯEb&v}w? 8/0TtKuQϭA~3+8_71Dnl\e`>|@r,7NX1.XܹPZ$̄hXN))s"+o)qN'֌Rs mrlq8{ $ ?BX``/Bnhq;ˤ0w]S pgl@NJ]˖ $$eϢ"WGws#ٯfZRj7NRD]~mT_>bHXGewiPeҢW ya!ѷyMNwv%C=咿Umnb@ء5|.P"4c쪂cG&Zw!n51X$h fzELe #5~+>aclkעbӛQ2HV98|ءҝF [׌~!c]g_Xua"Hv(i/@8ک!Blhךz3UG=hEVǂ`ٱ1.h6>ZH*f}te-CGͮs] x uG,7%GsGlXy˦Mhl6 a^պW|ޖ J @L w61,p$ ^D|RGf<10xvo(252,YίNЖX`uGaw3DHa(R *= 2%_0248TaRJ=UqY^2sh sֱW369Z 0yz=WM)^BB<И108(8[~9Q|W_i`tQ~.rdz8 bTB Ab1q"=gxl 1S\% <0xd;AJxM*\i1}gI۾3g kA M 99{s@) %YY&<2XfR3WXo:ukbS \,fͩs£a7{\-X4)+eD߁Oc-,{g{BH|>.} {ufg`bI}k~c޹bdjɵg1SGjP|} uh"\o{'uF|XW ˔|w&?kՓMy>ťZ2k[nj?m 䞡Exs8OPY{X贩x鯉J{Uc^1{0@z @i ng~a56QSz]w:MndsѼ mkKd^S^z!@Gmm>dbl M%}}P0Uo̸ Mv}&w}&Nui?8t~gD'Ilg+=AjuDp+oۯ,#S#KfJzRݯV?˭zZٙ-:H u$\ i}9Cm\W/,GQ?KBCz94Vx;Yoj@C9wHtu"nD%{ƶ O QpJp͡P [lH{~P5svP4zkQ sQ |j("jFbj a1Z4 'X! f'Z0;Y[(Rfm>΁Z(U3CwE(Z-`0'vT nEX*[5[&C]͠z6wkz_kKVm[X3Mo9,VhڢWY@!Õ[4R}vE= CrxL%L{~T6I=#|%M(9;Z)gfn"}("}CGoX}s.ouyCn^C8g7o3mJ޹YF[P0c.iq<[ 7R'>cvtIgX9t UcCY tn4̇  C2_eƶa?U)9{p! a Q&uMVFaQ=gObgg!_Bm<دb50X'kDRZM1UBSi;9Z:6Z޵6~uҸ .@2; f(O$UTGY[9UUNS0ɵ`Y=dT3{[aRc0j*5@=l "eBs4'L[; <>Z+dVbyb'<jФ u J[ AI5ʧpxF)sYk7|b*dgk#XeS._S {䋈8qE f'X0;Q,Mq "b8#TeƓq']2cPZfGqPÀxn; b I}!d Ϗ*WV AI5gsF)sX@oͰ&(_:^k/-(3FaÂىNV0 .Ù=>¡^ĪuIy>EP%Cbx GQI0s%9] ì{Ȃ]XQ˱| =l!x6)CId ŘS НSCjX;q>VsSi𡌏-eݘ? I(~:,㲃\c_ikijD\JEL\akuur-za9G\ ĥCHqE;I-'8UE:[~&:}Wx5JI}h:"Nf%b]`L!1JUnA@?m7pqk 8%n1>.A)8=Smvap6!qB8%!f'fQa,b 4KEJVdy)*-: 5Z/5I9ɜ 6o3B\qZFhNF®2Rw93F57+XrD"N;nL/lXf "#j\tj~k~*óϩZjԞ#p=؉:Mh xʡTHAQe>!5% -"8Z׊&)=ž/A0{fc&m8dw%S9ΑtT $3d@ B&O:1EI (Jp8"t&OD2'ip7bƣv0 D-r3,Q67EJ705T˽NG47G>QϊprĪ]9ܼ<]_(OfxT`);-' 9d?Eotpe,33@EnTS5BMvkom"ٕgF 26oF2`L"slM_Au-.}(?YOrB?"}1G@?y(1u9[Di9J \8fqD LjX+Er.<vec嚞`-*Qԇl^3]軥lƞ@QE`59D'Cxpj]W C {.a8P0]}}j>9n t U9ܼ2$W<< 8U]4PU?Ѫ*A[5:f}!cm4n{(J:ټթH2owf8¦@uct1ڌ**<VHXquD*j6_׵]hκ`YQxOHt?_w71> m=?8'׭Ei{ίR\f~pȐeuP3_<󫐝8 4Q_(ίZ׷Z<}É5,fW4vWx*^J Voe+Gefu~1^!f5Eq[3.?CE~O_8I()' ,Wΰk^p{\)xɃ/ERB{Hqƾ$ֽvJ>CͦL<Be,^?X@Gl27"UJe6C dp}F9{|{-fn n1_qBz&H$.p[' ~d&h ?]%}'!}t}T]aA:rCт.*M]?֫em$sd!) {H,P"ekn~{EIH\~TU\iR2T-Ehcj?b#A/|L{wk[iVZ,-mrU+w.ju?A:.c[CH:~&_PPnty?x&MS N9G959Aaǯ27Z@<b'n?7w]'gT3L9uXCg2H;~).lJծcK6<T5Zf?>AY 4@kZxZo gܧĻML*p2(=Z_=4#K"p})}9q cU7^dQ2B+Pu(^ k1r!GQ:(aS<&q(B痈OG͊}ې!PUUч?Gtʵ审zGoA#;GN=$AOهxPШ%:KÕL58r&:YZ>&b)r ?4ڋg;=b58y\i1zBϡLSa[br$6o'ezr{?ƪ8~F;sѹHzՖz>>Йw;!ͫVsS/x kxT] Og0v%tɣ^{h3v0Td@43xDA _R /ۚrZKx~yMk a 6$pS?pTah~GLU@$un +B [F[%lT\]D%1XHS+K!䷥3ϐlaz k@b<}UMwK bvt3%v?hjYko\kvUw_g4 <6ۮ66{ ;з[>zr>iJGgL4'mjs P7$13"|;rՕ:JQV:adzTE׊ŜBw%gr/q7?;Yd1O%/gAKb ^~7F9(WԼhjHS{/C lzȨ,?WO\ȃzLs[ޝG(R7|ek?oM 3CrG;,zSg -}0r2SG{Jܱ~ݩ~m\UK^v&2ϛ i endstream endobj 38 0 obj <>stream h, 0Dez&)m)dSx(=h (bJ$&Uxsx L090.`HAM&$4ﰛ[ T? DGc0$AI- 'e9y_C6liJoNC;#xK­R_0 endstream endobj 39 0 obj <>/Font<>>>/Rotate 0/StructParents 102/Tabs/S/Type/Page>> endobj 40 0 obj <>stream Hoܸ_A( ,$WozXۊ휭uݤ_r(Q}] yr槣WOOᇣ؅E^2?||<:__?VŪzzX<^56{gGW궺fG#H:sV"-xΤa.RQPߛjq]=M+;:93{gGy8q '*Q:l0X< f%+8-W"`+aOwV8sbjNrXJ3EۯtS[/oنP\SiJ#࿂u$K3`~do̤&woRB]DbnR i'Eq"Sĉ0FTFsXcZٯ 8Q}cR5 e(8p?'4 "9M B46נK!>`\F ڽ@zw@aBWVėiIB 8i$\#'~9(S-c8.ytiG-րbk{J+VL<+_w1Үmip> 쑵!GFO1ʖʟW&@7 oBTRJLJB߆7Pxf✝_TE"]ˮuOBG;l;9G{?[7Vwpg 4vS6~f3%|p;Eopx;y{ !82+#+tpP?.U0-C nqƜ5podRЅ;Cnwqtuo)hOM*cMTĉ 7 nrz^HX^ rCHMf ~睓^\hJL!̃sVB),2i&g`7mUUwn)4Ն' b7b2괉ޞ4$S{ 1/*`\|mSnC)uxLpp|R.(yo@Xc(|t N7p"1("͠m>/ wq)Р XMH:eEM\(q-q=QB; 8_J8"Bё+yp8]M<ͫu4PMoCښ,!Y bR6]!vͶx* AU]!텿vUdK@xKkI*i0Y9bS !">+zXv 6Bd|= aҽ9!>Y+yX@OjжFn&žQnw[1֏l feX Qμ?22wTFxY( ułP6w`*,c}֞၎)F݄UN=UAyfgk \|95pOI4 URu=~&R/ExVqy<܃ Ŏ"0~ ñNO?m굏%bQ_1L9N!`"Ѳl]a/{UE,-[O| kLO9<9wɽG#.ђ-0D{"Z"2w-ij79C m}ry5>I/9NI=kR|S\F)h嚜fuEƊ##oe\ ]uuxӻ^/H6k&0vZ(QERaPpLxDL_=V#9vjjN;eCrFCج{ecouFIАK*18BhaԘĬa`?qb&PM뜏0iuwtgjz{3:xډơ'8 '8 '9j|/qNs怢qGG8 96Ih\Sb2+Ұ.S&5f4B֥/|.yҲ=*gU6XF rhfM-UkN3я!NF]KWLh1Z$g)O:~ڤ:%2?2umV P~o=@h-=$^SA4,3 Lْq Q#ZϦ)wa5Ĩ\fjC7C&7]OiL892`<ĴF !TB ;CkiWC*he#Tp~#)TPZ; }}&<74{O,"n5i sB-$FkP޾K4/-Ȃ,#26Dd\lL=2?˥m| ,e٪ĶAv]JU2$M$}97q|٣+êϘ[a|ɠHCl_Cl߻#7aqD&$~i=1P]c8.>;IR$=L~B;4]hx6"wgo<LtwvͧtufONQr"݄ f=dRu_MiS4}#TUQe5_zTUI4@qDhUh2Sj{fNiV_qjk¨u`mG0iMܨmX#4B$Eo ItND1>n+haQ=F%HQ%Un*?WVR8 !bR84..}! Y:`6/ G_C m) ֝?V!}+$31x͵LVGwӾz I)n:Mjд֒UZmuJUZmy_nrAkɪi-YbWX4ִ \g6N/Yh l7(lFPXpO]t 7pC:#O+h+~Vޗ\n|?$O{xn ofy4 SSAs$ nkQV\΂5~M*yzF~U}3Kz~/= _gUoz` Gjl>{I<2 }c#ouS`:2' U$n>\ʎI<.Q7DzGHb6y@?SӋMmd|۾>=l+'9(#d r\DcA9Lȋyiu5qk#eϰ1J6l)m>p;ڞ|M}ꙃ"''qa>Υ!$1LFd~ȂU`JM]EFER0 y \-bW~hGm .3q郞zA^eIHOx#t'f[('-YɚdvCS/ǣkP&r #4&@D8#[+"2Y"&a9$^KEhe*kYel2P8Η$UŁ\DFԕW˞ɤ@A8x |w8g Q@ʝߘ/GZk׀E)6W^#;[o,!iâ ѬG K[8g3],XzԤqFV SNPhlTe dԸBYK *W(_j+S X{tjSRb氢9-g\Qo|s#\HuNK\aw+4=OiCl3eY9%^و32=נnCD'5Yݵ0yt ?a_.ǓlԪ9%eV$(Tkw,E)&CtxBiv\˜u2w)EeXvGf&ʂvi01t$uZlk ͚n]n,4:d|?YҕC_Q(d1쉾 k}fOOX[5{xdڨYPgR\sGq![jJev7U&7IwZLJ'h^ѳJ5'՞Fm|sќn7L|${Q_5nAm()V"QDeA劽׮8ږ{,ܮLbK :diwj}!C^{Njxmc-mMFR{c-x_ bJ$LT4*FUPtѨ Vk FEP֪*fZ1sXѬ+U&_Ajum:|V#u]Ot\5ceY_zW9 ]zYaC8˿(ߣ6 t,K_Ȳ-,LԳJLiwFG?mƭRIY߮'@J^A>@q ]U]i7;?}/e_;yw7rG\΍G$=]C?Wk0رJ70xH4u;ҡE$L3ҐDLKҌe.o&f,;ӅR4cA"ir]"y~XZRPژfp5;G9j)GPGϖd2ĝjS PK 1d<ɫO9#3JůB$6Z?`]~u碌W,8vͩ ]N7%U4.IH-EA>tQtM ^-7ԕ%u|w['O;rϿ9h4w?`_S!]7i?+?}@!˯."?..$:?8Aȏ.:9HE *PeP+O'o7xê~ 7G? Ia>|Q~\-*5hrƪO #`yEvń]:ʚM}YN,zAp<815PF|=r&/WK . m)hLa%Ԛ_#=@Mۻu= jMkGĉևl5aH@ mҏ<_v^%mA#T(bseJ$",O#Ur@ ׯE1}DĽ-l&x|U215'N0K5mq1<e[RQZIgcXF)d `HXIN'_dUg%g5ʅjt`nG^凷UBcDv5}Ez>&PL/g LdFuv\ҷ ȺgtE#$+SJAgnd#AhV^_ ٘9ƴ)`MO1&mTCϭ6Aм_#!'MZLkM\8e G=-:KY@--fF7[˻hyXٽN*8^vJ.B쒭])=hʑlpqw1,UNF3L! <.)saB5N*(Í@KϋhOpMUn[PTVћny<##c8N*-c60sjۨ_xL_aSp$!#ON>U6 C{T )$f3$Z8Dzr7`~TBCЇZLvzyqmn*ZOvmgt&>U({g{4zX :yEjQ)BZc+s?mo;d"J]RTlt,` )OgmFj@UKk)% ?䴦ϵ jca,}G{l$md)T|eQ6ϓI msbJ62$Q:^H %0  UtRu2jG ōJHK*$+$ޢ)lBo84u_QNM8cv %{RM΃Y9+*@pag(J'-_" >hC=pE|'ezեo,Ӷ#=Gq 8a th5 B{ٕGRrcJ5M2b;(\a2 g4L#yxwt:yUS7%gk|&tYx멂$ 'T; d%BfwUM\>Q&qX̖8S3QXw5cAG2̕WjO| WOp˥Y5|~HB Bȑ `4t|wʼG/ endstream endobj 41 0 obj <>stream h, 0EeaFJ]Yp*.B6-%R{* p.S(0)X_XiMg[71p4Qv!:!4 2NrM5\2PHyq1,~Ƭ5g[/8y&10pkW1 endstream endobj 42 0 obj <>/Font<>>>/Rotate 0/StructParents 103/Tabs/S/Type/Page>> endobj 43 0 obj <>stream Hėo8W+(ҴuaҢ&NNgfȡDI-ٽDF|rǓb~ɓ\ S.Nݬ/?di^}ެv 'O d9; UvKv~bFɆm QPO6lQ;V2vw,%ly5Kx WTt!,cY-ki6 Yh fE$Ӳn0e&tQpf\TQݮgق;BCtʂ]NTIK˪ЕufB Wsa,V6+xϮ0/,X^0!+kr_RB˝g9o &{|n =Y> #y!%tW |&ct H=xw[?C=h(8lkeQ]"ϻ=Wh(2%p* "xO[Md`聦H,z6\dԅʶ9,]*rPX"sxƾ=ZJ`[|c3is}cckLpi@dXlPn =2ͱwT7^Ý$ RcRkEkY8t-Sܯtw@{?lqf4j ~.ͰT)jvfgK~-`q;EN?xq)c wT*lի/4֩\ `Z?X󺵅{[l'.[h0{WAW~HMA{jDڮ= ; nvsj};轐.>hQH垐6+\b;~OwNZ "KQJLCG Д"MQn۪U)jýƉ(b؏HF3\];қ֙yZ\`-znm۹ okP{|qj94&HNyJnJ f07m |Yc(9yt WN7EXcTX(>{/۸hP6^$FY18j'%ב"KYzo#"$wMpÛc T3[FLړ,1. f I 6CeU_HhQt7ό@6Yo(XPz%IquyMV5Hȵ=_T'sGibمZ0m? x< Rb@<4M 'E[jNh[?>žQn[wbx o]} ,âN0rܨPֱuł\))uI`2x|?L@x#è S=T?/ +'ل~ 1ZγܩxYf.8.oqxlʉ/ȏgno7;'U7 {>DŽ,Kb(_f<ZNk~?k*[c%F»@Y٧ ~gͳ{z(Nqw8:J[y}yѥd>*=FdCfD&?Hd;s7<iim-dzc@d]9B8Rئ ƭDd7 >(įf5~cCW Uo>yץ tfe:&sej.N>h {ށˁ`ãh'gW66\bR^[af>:#Be昐09SkWKm);iKv/Xcؘli~5$@M7yP4ݢ]^(Dhj e5\ z (x«Z)q 'a8a >S8 ^J٦'&dDµx8ںhW}Оph:GAO#~1h?STcF&vJ;DzfL#8a"sk~4"6}XV=*݀JQ€Ѧ_Je O oH\a,DsɆ(8zm=@C¾0miڥB ҳ0x*1 Mʵ'ưKW FIAgQpZ! NMI\= v$ǿ% v4?nAb/wG( )HQpTFFed((Xa`6MQ"(%SN๸A4O1iڐd7yD̾ _z؆>f.ˣY#ft+ħR̻};:[mrmw$^0'F<[IڏC}D$'! j0#s1!o> >ydTv! &]c6pp:P*Am4 mPj gp O nf#1 s/EpxT7#:}"voa _JpeTMJj UAHe6oPç;aKCu9p Nu0/:!&{7cľWAhOhЬN80oƐ0 퉏3ch'a) Nm֥Nɬ@J=FTRKY(I֋/y>v%;@%p#+ĈM)1A8w@z#弴tXB2mffwYD M:~THp@qC[ޣN8{{|\+Ǫ7U6D:R1# (웼hqL@$$*F6)3+3kP\d[DU徼ߦ^0Cd(`ͅ]!Wn+Rslsݍ`z%g:!) i:SFNʸ7AC2ٯR ؊A]Oa{`/%3Maz\2lF`>h΢c [6Ffuy vh`X}A߆W'S ҥFʫ ?cp?şZd*<RyHQOCo?[}O q$™`;#k)q@!"5 'Oba<2g>F9< c\1bQN7vܬkd̯ $Dw<;~w^>O gI= >OF ^BBc1'7{UYwKgJD>0A N l$NCn ~r"?q3h?5wd=@ œNxNC c#UNNS͎eypBjIBϡN" ]fs~+wv!#p +yz?(mF$7j]@jܺl&R9@CHpz?= C&ܬ?E6^B f{)~uUBTHSJ5Z\^$ٮ؞hߪr޲)p[4RΜ$N(ӗ,7:ͫfS{$0" &g~>ih>[Pgm|U`. \!A& k4%PćQyq@|A1!C4byO)2Ȧć8MgrXh '۳IHr$"ؗkqpzrx6uR/>\|5T;P J[U.n_7'uqe~kf{wzqu(m$bرrAez,U?Lǽ9HdZlVP# V `R!D邖L -qDޝ/`¡ 9CHVci5[,/ 2+-tad:H,!*)b7P[k,7YDv9%` j#$Ip#*Y,YxpH.~5菶[ݒYd %3ȡR\gw ݔJ=h|nO`3gW-ldN %̬ZHX~"_?qJ*lQ:BKrY-d<_NaYKdԇVw*/*9'@9iS 瀏jPnGs @wal1ZO+RQB65Aݹ.H6[bvߔI S; _R!%x`/b WVSҺ[6Gkp5_j6>TS+%ܕǝbcH{#~;v%X3Cj 1HTKNV/ϻu"m#<0QBO9<^'+Mv,ht=jm@f_<4Rўzݫi]ԥ42 ̃ 5sM C`TxELZ*$a%Vv=JT 5-]2xkee-+sLO\-7b<ƵGnx]ӓ]<:цu*">Ҷ}YS;aPl^e>;Vxb=ԟ䶷e\v2etqƺVVmܖj';@2TmHƒs`֒("g_{.0lP (V'ކvxBwƺ,2Jg- }V>G%v ;݋ΘUUFnv p^?48# PYoY80k,pre5`7W/޼}^!Z endstream endobj 44 0 obj <>stream h, 0Dez&)m)dSx(=h-(bJ$&UYx0Dҗ>#356[Ц;~[nӂgZ)GcfC_p'RQ9IYhאlי61H.~${V)01 endstream endobj 45 0 obj <>/Font<>>>/Rotate 0/StructParents 104/Tabs/S/Type/Page>> endobj 46 0 obj <>stream HW[o~ׯ/dҜ, $N͢lb`[GR32e)ZDg/9yr\owߝ<}Τ0ewy?~~Y?¾xp^n6kOWt1; E%m$I=I#ڌs bP*٤.2'%H>S*JK@_ڞ;4R̉=9|x@,V2$c\#sqkSWt챂RaP25@Q"0*wvSTcI>]< ,N稯-~Ag7gVW7]a;+v ffKx^N8<^|!8 +#+t0H( yy_W*!/{l2o]EA9YF pQo05..|TP.=NVLCAMV  Tqi]ر%Y稥{X'BEbd n;Zy k )8E ݴU5V_S(Tպ{~Q$M]nzϹ:ow51Yb.GX[@r} wi4w}(q=q8/G G+OѢ[0}~}^1.+W@xX+Y|t N7P%E1H,Ёx=.8QG (HlLS}(rhj\Mq=Q;8M,(sp!"D<:q){pp+8xsc/o[-Z ,>. f  !貪KL. &cbh\{4!-gN*c1&lQ@ '5x3Q>eԽu"0qEqe{^W bS[w_'gn8VvnȬ%ǑEz.^l)+YAk]Z  <sE B Htxw!U5h RXqoWj+ ȳu~Dm) 7;:|.)։A+eܚs(d 0g ƾZeOdup,! ![h( X:Ng ^~/KW [{t e`W +zC/O#ۊP1՚kF*"znlҨdg_TLSQL7A|{[hwPΘVɷ3 [ ]f/klss_d;,dGuuqա2:.q%g%)̀̕*a7Gd2t}A1QƐk(6cKiNrAnYXq|p$fO ż@$)uB L#vE e%k"ֆ]]")\ D_( NlƦ(ԎI!I(:k2eyՂyxX ̭ *=nWE+Lw!S@hܶ0b5Hp[8&[ᏱJhL^5?| Ѓ5]OB/W{!D !+@so պ \ě|44o%QPGTr%?Xߪ'-Sp}p1} `L5{"{"ƀ}6D``\{"{C )Qx)T4p/ݫx(h'?/uDk{@5$Ɂ)CP/q$<܊ -¶v)/wݝcQག$e1@ٮO}==]W4: Ͼ]ҷ>4~h$'ۄ@Xqd[.=C͖B';{Lz8pdwY.3 ʢW=fa VF\}nIWn \ƄRpA=)@s*8zͅm jEÇ"'ICv.woga[&aʨT%PM ;qEy.EVo!|d 1)@6BROqOu0Qlv6QhLI !5L?"\pWHJx^.?ߊ֕~YV1% ֪!݅hRnD"XQ^%ߑ=2܇kyR`<.v]a2>Z'{u_ KL:ݿ^O^nAҩ..HR B%p^Ou=eF/^ʱϗEQ'y^(~O|('\[ Wcz"QTٲ8-eqNdϜe!"{p3";:<ٲ8- |miv]ܞ]Ϣd9FGmHQ'3Vu2Ҏ~=6y}"#'Z[]ZxcmjNѫll V5kv&9px 0=}46ЂOs|zY'FݗI_$Q|)JL_WCoq&*SgtT+2ڪB{}EǎPrmP**~NR"AYhx'|,qeNOb+}XxX*v=62pc%(r⎢J%Ε:rƉ(76Iάh}z&I5Oqm|b=Zõ7J"(>{ph6vkn.CduMq9ЬsPYYY_\o9<@v^^_g.fV5wUoΈU65)3]_[!v0[k^E-Qf|AԲ0n j *D?2hݝף7:H6/Z{*F} 'Dٶ[QAGP[zzΓUHzuLc>vr'C! @YHݰꓗTX|?I>H .MD'4%9MyXϳ=#Gi8E3-Wi4 P/^7|9 u1G\ n[K*kHSYy{摆]6ocˮ5QZe@? _e!lQVx!m'vAB~bQQ߯V bT@T|g=;6Uh@;抒UMݔɷev] "P?WȍK}[ M#T]N6q4ĹNeb-?Ԍ0W^֋"}4>?(\! goVŭ#9K)(3k⯵WBkЂл|_ endstream endobj 47 0 obj <>stream h,A 0E2Kd6@*U\,1 %Iaއy XMAˀq&#m5MݐpHs yM *=138%PԂpQ,-kȦ=ֹ9(֜twscG2/*`&0 endstream endobj 48 0 obj <>/Font<>>>/Rotate 0/StructParents 105/Tabs/S/Type/Page>> endobj 49 0 obj <>stream Hs6W`^ΐ&>H78NM眤nd:8%cKMs DN%$,].v89ܼ]^nߟ1l]"|ߚ1(s}9̽5ۡ:N #I^ ?qKͯsbmfLp|@d\lv6=217&UMj߄(y o(pO?*SPcI>]klmmPAUWO8m݀G È. X*zi_?.log 8UB5IxGD+`K-Mv;]7d%=`V4Uً~]7 -,,7ɯ%K@XxjbIaO6H; l㤌m]hm+XJ!8* 6ED?j^aKhʵOہ|T=ğ]}߮&T.}?YkU7勒."3k?&_ $^f8 [: LAxfro4ֻ/3k H Jz8RZx >'i9Y)b_GERAOZ!a)DnuC'8S& ͑Bb2:$& }o\fCdfUӜ(-A|7ֵ[x1ExC !i~dq'vH/(謧i:vISj.t!4z-!+Eݼ^^luMIQY9 hّA5~| nS.{|Xh*JwcG<7BCTߐѷrܭW!p(FțZ <@-w7aQ2N( !*( ز1ll(lr99Bx@fyr?t: .]>l=) fy9my==+h,hO9q5m}a ڭUݨ6MKp* Xl 8{٫w7W kw{ɺO;_qKWAiҸI߲]4:=.=lYЫ&fwf7lR{,e ` e#BAMnZ axH$pCπr2;(' MZ5d#s}vLD);6ˍ-: c/H>ʔNƫ;qř1'.5?v)eE}s^{͍:fO&WJ ϳ ?%] ~vhuI0Dvފ11 YafI8oezdW+[o96޶tЁ!`cFb~ȟflazP;Lu[#Wzin<ᴽ3nVa9"1;vfEd,6q> S+/ѣݽ,bݗ?gN'gDy#Bݬ?lL'wQ/3 U,xөƆC4WxiJ~kҚTi*bœiΑϽ k 5QRPe27{Z-*ZC%c.PLbņ|5uh+UHMSR3rP:duޓB3[:guc/=R6(2ty UOr$d`E,_}㑨]1(E<s?$pP!n ^še'^⦠BT0qb74.$0sU}*qWE];s3a$'S;5ћOrwDvCsK[% e} X")F/GKdUй3ic|w: xdKY`$F1hOejngsKiT' ô?fs&]`k`M okq GSkWCQ>aH!VW iOPU3[t_"ǡ}UhY3(T2Bo+l}GZ0H3X{k6zriqtJπ!MާA-e7[.h_șVմ TUG{$C0:үC%>SrEEu,LI:.ԗB)6cKwjcG.°4`0\|:ha@_ MQ;Ay`04&Ql3saNQ>"%]ɒG3a"R 22Xr%0@@"2"{㓽%__}EDTlC=`)`7ׇD1  S z@h;@G*w!as^'Pϫ~N=PҠ(\S.)L*Ӻ0&ƀHunЩ c܆C `opP3Z“P{~ЮVLxupP6JX`J`^X'ɪmw|1Lw:mxS!4aӜdJ˜l 2'UzL17mLA PÊY_ !oWÿYҕX;x^z==)IҜ%^OҚd~S1yw/d%|]]/dF<㡿`.\g=/BxLrTeġצ1!}$Xs͐^~翏rw/=szS$cW+\:$\4 SMgv(a QvjpBujo Tm7ޣ^wz}%<@'CuNbȶ^ Cj[E ˺ w%GIH}=29yٍV-pAA0!^Y꠨_܊߾ F6Y& %= ѣЛ& qJ3T\^gN%5ј ͋Q^ؓjgD = -\/I>DaVP^RM5kG>`T/ppczǛ ,ru$v{Hwm~Tv`$g|IYr/M2|*a٠9,MJr)>t!0lI{\fW,\bCGi6seeB$ &-lҜ>u[Cw޽ADQJhQFhTܬc9|/O( *O :$;h+wÍnVC+O~Ň, _v0~++W'4͜JLaÖ3?d*r 6􎚶axJod7qJnC] gY\Y7UDȄGV7HgicVfBW檙A& Ŭ،%S#EVڕdJ.,SY0\%]6e=K\]^>1* yUw-M|+ymөia;glH:{䄹Z5E}PQAT.2pf/Y.A%ZA\`e;sOEs endstream endobj 50 0 obj <>stream h, 0 _%G4mVFa;9)q2|{)!'|`݁ ͂60_X8?4<Xb]h4ĴVT XXs}?kךsU.0yf17pkW1 endstream endobj 51 0 obj <>/Font<>>>/Rotate 0/StructParents 106/Tabs/S/Type/Page>> endobj 52 0 obj <>stream HW[s6~ׯ̾;+LۙNldnLFXvlyspYR>"y>=_]_?~a3%mY1;o&V_jq3/;Wv~􄍞ttxZ/>,.hz{'z%VLJ~Y/ieG']˜+WֹE^ 7Mdu^tS*::nƟe%-llsϲ?Ʋ5JOaM^L߲k?A?guL Xz,7_X4T\/ZY Z]2ϛ C*Zp!UH$%&u ">D oM dqLO@,:'G~9ro38_µ>d3o2kܪOjK'qҭX; 6Oĭ[t5f}A\:lUPtp 3ŕ+oW`ĝLJJJI%gwjW⧶y|{-y8 }rd,8q*_aJ3*?8b74h;9}d>Ru%BptW%xa.NJAhKpw E[4;H%t4et9PS0j4Z*8ck: P?  [ Һp"#iI.{E Y᫔o0֘B[L.9;zhҹh Q؍LF5\7ћƙq|95fj9ys ]?U8L*SGDΓe).(y0*j \l0{6.I ጵ²y !RÀ`5(1۴lĵ(q?-q3YA; 8ɐ>:R@t2é{SP\Ԅ͝ۼjVӣ@CkddiILYC4 є] srfZ/u[8CjշGapɎ/10tAaJqA O}QV!ELrޖ =R4~3/`n%VJaVt,"+z/"CuA\g<(渢7_31}&"١ jm? :osS`U+㒳][HUʇIDe|Z.JRl&T% |kB` L0=b{?!'i )^*8`X+qI8;|P6]If̏$^c &x̏lXi"[ކKǿֆ-̂/ak&A[3~ 'E O&{,zvz7ۙJn(n<3 D]SC62ivMm[Sm|>p&N}gz T//vD5;HI4`b%/e`%IP >Qq8' m($&~)siBi1aq3ڊ?d0?+k&uGiLIZgi̖F 7(%祒祗{o߉Ss@axfD@f.{pO,|b23I.K),K `]̲-lҍ͞"z+4X;cO#Fњ.PW2EE)G(LШiG^|V:uT)wMb"mځa't>-(XTT`AGF;&DAź@ZoVOAn"KU|+C$ &iiRL%Z`d4(l:kBݼTдXjY+3vds]MZ$ N5N!ӫKbp:W]n UM1Cw<1UX{W@~B  hJO{}C9|I}ίsUT(a.X́t"O53|^uUfڌi2}F@omk7  m/+Mb́~Nà)Wl;5'F0~` A`dY-h9|E8V8tIϕ^叇/t OX~.+RJ]:[6/TTIuK`֭K YӺ|CğŽ\;(J>h@]!LRHfhA{rdB𕈱x2d * c 2.6nS%G8eA\pָMzzd`"oO/"P (?+' Dʉ{+ oIQe(h ρXTbR(u%;fiaƝIOE X`G  :()̅ԴI*6Ǣ_/%\R=~::Ry?r(jA(#O]%  e^:UDLB:p\Ej 4W Z;t\8>H|_9 ik) <>){C/n(E׍7]2A k>( V \-ўiL$?icwS6f%I H_tL#`we6"1T;z\h#Bt獈)"]vEuSև.fnk V1ǿ v O=MmJ= ̓j3!<#/p?:x_!KV/M>ʺ ulBW4i WenXYe΁~i=}[_'S| f>+?m :$Tggms'l*s*sz)2\QD p= vn"z`_Vpk9jnNJ6s׭=~8l ;'ZFė+cpIb&JM' ZeYe7fSfE`K E F(rz-e^N/Y-8hL2$iLnyff2l dF!¥Mzf !3bvw*'v/bx~g)JU YZ3QzϪ)ly|k59EnP",uGqsl-28yβ\~k*g*s1Rtg /&;rg#J{f u_!C:жf/3.ULS~a5nfsD֫dm#s*E dٮ+M"!Q `$R>ULO/_怟O@uIĨeM}ȹ?͵$3rfhh=#/|ӡ)Fלˍl:q{ƁFi'9kt G>! ҁ84NIFτeCc-].D$;-F .r =rj_kaG;`z1i}.zrxEY,3 {;@w,JaLe?(Y͕)KD 9&Wym8h^Y!:sPQ'Eлab3=\xs', *S1@P5~;t~_%.=tYgsocШ;pKC~iW;lݮ]m`N^v|;{~\Y5ir%vu٧au~}iovw7࣭r &&z)Ņl@";bCR DO-`./S!b`JG [XasJi d | ʯW8aBϐXO:iC;O; `Mm:yc1R% ̰,5X)N-=uSq,dF|ROh@CdY,0,s_3#9~_Yҷ){.prG 'f& DpvظbfH%_8NJ4G{Lr$WUC?p҃[b>WX6(tw #za.XcxPy4e5pn1朘|pŀvtp5.8NyFYd #e4@bvjKv'w&'ZLq!U-+Hʁ 񣴀?t fh77ENs◗Kt4 UtAjOl)|@?sfMnχ{(?H(ܫdUiVRAӘI mO,Tq~Ipf܋sJx0ݝ\rODAtBiՔǎՋZ<30Q_r|Ex6l7Ѩi=_= # $Dh?>dNX9{摆ƯRot|*.V@X+|1h/}v0yLo zF |ktFbŢ60P*UO`[~PCenmMa}#>y <*/]œ);az0QqGՙlg<ͪEYnvr]g,p3֓?" >hc=pExVʰ K,Ӷ#;Gqd 8a th5/߅DZ=ˮ{ TMݔɯevM lk@[ JrǾ-.'|%MĹ+q榦UX5cAuG2̕WuiO|tk7S u$g1-MC2WV̑>^¼WM endstream endobj 53 0 obj <>stream h, 0EeAhW\҅ւ"6DoRese LK0*`\A5MuMs#~ Z?t:! $'PB+•IQؾ!sV䃵k5y7b\ [k )51 endstream endobj 54 0 obj <>/Font<>>>/Rotate 0/StructParents 107/Tabs/S/Type/Page>> endobj 55 0 obj <>stream HWo7_A^vk b'hҴR7(k%ǖ!A]93ٳj˾|7T5slneg.Ov6 oVvYo=~&/^|rx.%/g.شex 淓?&%k6N V,d5]L~j5^SY"H^l{=Gq8:=a6 YoC>(8/C \4p6 Ky{?=gJ8Buzj@3Rq+X $@螤_tbmFb9G~1 mr`-Ap^b6qKm>,e kc k/`̈́U9;64HJfp+`rdvc.nm|$lRcP6@Q!8*y3ةLQ$?]ʩyAY]P_[>foFOf4v 6-n'KxLf"gxu9\ܩR y% L}O$T`<˵*<n˘=6N7AuQPN.aԻ{WQWHNA{jPE(mQ?cmC>P@Pipf[WU}B@B.\ڔZA+\q9j։P{rQRL}G+a!4%ǰHa(gڪkJZwVx#?ؽ)v+ݫ^r.iM0f ֖Bs}v.iXlqj_O#VEI aNob\֮pFW<85\!xxLu;[<e:s~¸%Cgu˪BLƄsFFSs|j< EugAɃ+!љKy=ss\\;{x:PM m`R:tY k!S}TA1D]Vut~}f|T&cϱJ4=H>N}7+Gشok;_TsK4cх\0u;"Ap< EE'yD%}hOYjh[`(+=Gvu8ooe1,(fޞQ;J#m<-&yl|@${iWVb^2Oˎ&Fxʥ'祻= į'X`OS`ԁUeS` @$t)M0BG:@F QZ'$X`4~̧K1[oݽִ{}f.l݁%}oSfͭ^q0fVZ3[R+~'E_X!_n*1R ̅T n: ѥӏ 06>Dd [7vޯHnݸoKA PG|.N^h ,۵ޘO.̔ޑ-3/-a!=J.R(7Ase/._T[R;4Ij |eڧnN6EG7{+ KD-+ XS$ƺ[}b>lf8nԏ;UX/ q}zUPTTc]k5Xx;ž#>vvR /X?%12’ߟrz96.3%[-FbҺh(f16;UPzvC#ezF @Ԍ8K3BO@:E‰73FѼ6{Z ):3E6 WƱGFlD &59 HʝjǂL_I &P0JSNabzR՟Ja+"9lG2*HQ# PPas7'= pey@>=8 1N72_@8a=OQOu(A?)?>X'IJD,ޱhX+8aH޵ݱc1 Zj ?z6V}:iҩ]\b1N0vԦ961yqfXlTL07XlY_ģv[P.:_0t#Zg-UZߨ/9O/X#~q#`$r 3u6W2 ڦpk)쩣4tH* gj?)x(PC'srǐ)1-J`gGL`gGLb񳄝1GNaؙb/0oRLJȤVDqjVM{]h*xnHCjk_US?JP JzIʪ'@:RB puV=9 xw2 ;KN:fGrru`mAXu#|5kX t-][xӍq ~6x j:X{_]ß%>dq`,[@jr~ ~lg z%!{ۏYQ O5!v(#Cw-.nsc_;EfKbwkku/4 I[R;c#]sv~J6MARk)opr뗤=ޯY<:HLF- I؍u"o)xQ++Ź6jF_R푬 kT]O˱QDܙ/q# Wqj u$5U)kMi&9QeD >Ba kh5(E4uN2d k$_쿖1R#9X4wLzpv8xM'N>htn",zn4Y/J(GF>7'Q> څ@uSY},KX8&IXZRɅ@0 2xX>4uY4ꨪ uWBA91R7,: -Jc!k lخwD iX1rDa:+ gIO3cfʌ6rv7po CQ@;vdwЕ^r"Rŀ\UuǶ}g? ,8gA` 4Qkiw-&ܵ2Sc:r" 3vW ݵ^]WuvIqZb5eڸnğ,q& vEt"}xjxAڀS^^⩫t%ב^7}js!Y:u\kwPj^H5ϛ`~1o\nOMm+#Ӗu9\pktѯtؤG{GwVn>_IcwNqE!W_oӄL@_25>fUVbK;u6Jc;B^H?jC;7,9X98 N={K׃ [(]`wy+N+~U'$R Zy 7.˲PØKP(:!g Lmcݺ#2čd *n/Nv%!,H7L66g7 2kN &kQ7| hiTƨA 3d cиDZ0pƸA칣!fhQi3f4]?ČW%mRj=؍n\lEq fŒP0},!߹ bdCu1@ 3;Pt*VU3%>U[Fe{3OsK.8Kgp]g!{:Il)9uŴ.4s50DUGߏK>S C(vQVIЂ4s4[[% A$GHl#I GRrGL.M4:v{6)9jC@C|P)$? '$?GZ?rIZ”˨<&ao`mw+T<21Fu5ʀ@DvW D[eCXʛTa?LU=@g~,a;0I7-KΞ4t0FdWzn1rE8boG$b@WP@#ZTVN .o|Y{v͝]p{zg>`U_֛ ?)n p2ѮM82DVRsrH- {</NƛWsK3듞aƪF}[Y&EE(*|hsG"#J[>ѓ'E!٢0%)!Qyԏ;wX13/oYYW13μ8s̀Nș2:33_^0'|߽M"+7ol۝s &&WuÌYzEescհc_0]?9ݾlv<)9j ?{?z'p?n0pMN\_yo+>g4οwvog$ZR373RO;jMW׷my`^-) 2.$UTˆIAEBqqڰqIJVœV ˨< &PEk](ME()hF=UF@12yH?j3)I,̇voZhDǝ Мڬf9$IOBS`jjsc.Hf:߻z6q?jഊ۟tLtM6R? *AUcu]R`RhMaP? ".I sJӊac@eXX,U!\5s^4ȑ$&L XC f,יp~9j9fI\Cw 3 #%*VqB{X=D=gLrv"}SS5ƴLmxЎ+z y~a$-DDB%DbPh5'%2?Xx)3AE"D*aNZ sZ1HdS3)ɫcGy,Sy<ּ4)ԻaDwIVβ&!I_c }'9^aYO8 Ir{E-:ҟ7w|[h0Jw?W]f߅4eZ5 m:W0^Ժ_嶢-EՖ M4gES q4h4)㮊4,MUQ׏\#[ Z'-EǽeҽA;FOy8808w}RnF߰-jH=FJU ~/ղԸE|E/5`C*YL3 ٖ1\ >!P,}s૤Utܬaɂϒcvq 2z%b74_FWxiW#rrն[0ãvqu5|7 õ@9X(*pL_?v}\|oWn&e@"74ga6Y3 D7 SB/g5ࢁߡ#ljX9_|nEJ jaKq'j8F; ^aJ 켤æQKYAV`Mnxv.]j'wd+ ^@39݋!#ij+f0 'k4aezFvW\~MG /01(tXDO֤6cbH]K"n1dT)j ⶆ۲;},3GƱ_xsGd^ƻF{ēBMs:n4/Š%|#^+Cu&jw=̱ҫs,T5}p Xh1VTJʓY?RX@4yj;jG ō L#mN uq8[[gfap⼟E <}y_Upڮ^;faz0QqhoNgr;)KnVϪf GK`p陎xs'.e&QwRmP]Z÷滪ȋ`:GFƑ+`Mkk(ṉ.]yt/.ρ0CBl'\U!ӱL&ئ5Ok{ TMݔt91M0$A𺺣@>m&zwⴳoNp%]״:&6}x ٹ#ʫԺ>AOOVԑ9\*Qfeͧksu endstream endobj 56 0 obj <>stream h, 0EeADJ]Yp*.J ؄ Ia`e8)Ҡtq CF XUXil}Oظ6-xjGGcd &AɉTPpY(FאM9yvԵy71H.^5+'1 endstream endobj 57 0 obj <>/Font<>>>/Rotate 0/StructParents 108/Tabs/S/Type/Page>> endobj 58 0 obj <>stream HWnG}W4v_fen@+mȃb,(vIY`{~gzfy3A"9uuΜ=߼;݈;;?_ZUe-fn)~og3|~BL~əf3ug>KQ*d)t#Tm|?.}U.nD.jr6BۉTbcD'Ȕ}$"6Tfba?JgE6Z? Y&ZTBAbexq%)<+ ;y&a Wr& GlѺ̊~mM^fBdUFi̴ݫ 'L,[_}M֔tuwu$MTʬJ^+VYZ\O0d?81hqRH &WpeُHϞaHS@#+W (+LPB{\-} n!0/Z,a1pAp1 .iMW DQp6]:-MM6t 腊R-H%>Z҇M"ܽYQ̛!ͣs6a%redcՄ*[t_GFTpzPgWEA/%M4 pFX~aB ffi9/ 4wq-I8O]$2o*wA &qSqA.Q<r;QP9"1j*aȾ[ү*P6_l fp#+;\Bk%wknVe16,Ѯ~ActpG AD?ГzƎ=mhYwNXl'$Z\-?f02|-$ &1oc p ~*xn#O{/P6?ؕA<{"֎ 6ׄt \JVs6d!6&.Cû,xz%q%eHPIq5k;A UV $Ϟwc4+F:?QmǂQ\ΗĬ i!e =QBFO<{MFlD铑c4J/^m+Ѕ1;ՙ}!TO%N&¤h$"㮝CETsz,I}ϒGzDnHӌx\'3ZIۨHvU#-rxj;TChyg$M&L2al5%k'Ox_ e"s6ʪ-f=(%Kk)aRUcj p+bvI9X.H%-bl;\-j{_QVâwrJq mM\Fs̵`.M#m%đe@V-\4Y($Hw3/;}vVD˩DCN*ɞH#'H҄vwo`eIvwBM$oZvw'zqS5Zhx:sߒՠxl+ ZQfrZ':b#:Sl3mĢmhn# *;֢H7snUs,wn72͗[OLRp 㩽fc/IqWi([ş'!7V ; Xtr5{JV2k#H[Z )ϨFS]yd[1KRF5{V'q顲JE>4=lj-qd`kL{P9Z˥m$ <*صLv$a{AD4)MbIzW}KX sb_ס أ*fA:ġ  :$EjfI[8,8 c⸐&&-6xk gX 5挅p A"!Fء?eC|y ]"SU΃x]y{DEiU GWIUy@JJ^ޭ++iJC2 Wu KN]%,MG( Aٵ?%4uUzc&}TDSr4իwT2tN˓C FUDGBF9JA܈"=ӎFć֞u,YH\JFl'N\\[X/"-P1Mq#ZmvUgg>"Zf"f{`tN"X l[d4cFy>% *b{iIi5N%c z.:+<@7m̆ߛuOdA.SnTAmdI"F/FX$ﳫTLˢ[#)SҌKdj]j@ F-,S SԒ8qAa]tZcjaaZL,vPGqMV S!yMF elqzm#B88A1\F ޖ!޺Je*p-#=S#'5 H#k\ 7t-6sEѓJ.= (rǂlk(ܷ\bXMs3jQ~<[+dق%=ؽИ, 0,7dUL]Yo,#'##lHwt\ 8), _TU53 ⻈%\tFqyA2HRLZ>eM Heb;p+W+ꚓyr,WGd+7BLABCݎV6Á^ N< |3~`4ѢҴOL1ʅsz1L|>Y)ҍ9€&q؋d rEd{b7;'PA}RJB֮[dF|y:l|G4h;0(=E @TxE ;mk÷$JlB+ SOt;PRPm=P%\j/c;v{qYK]&qO\;nL3~{{gB~ ~Ɏre}ڀ26Q*{s4}{P,?)rPbc~ό\a?嚏/9Y!D/Ҟ2ٽK9h{9&?a5gĽt$;~ UY4eBG^>mye[dP;VqgZ'OQ[2cU.!`vg῞0hgiPO;C'-JmYS;aPl^FͺT.5A_/E*#jxӃCV\Fgly۽=![&HfێpkH+k_<.0lP _xN~Ckn0c !C?uYiJW*uJH+/]m1tp0V6kwG=9![@[dTE!u#)HVdT-ey@޳y@Jz\22)"Sp3fzw ;Igvfϳ΃wf]nv 8Z.{/=CWR'mUhS>^ц=D8WEx>wP9 ^v3B.St?U=G!~h)TaY[= s86rLhwcUw6&6+C:mLY`zNeeM!$l#QZ,u8r˱އy+TLn66y"aKbmLly<˨PdGckqW4BE##R|~pg_ϯɥ[`77u\ endstream endobj 59 0 obj <>stream h, 0EeAFJ]Yp*.BZ  Iae8)B?56k!3n jCqp%' D% %HNb} txXkͩn!b\D&­_1 endstream endobj 60 0 obj <>/Font<>>>/Rotate 0/StructParents 109/Tabs/S/Type/Page>> endobj 61 0 obj <>stream HW]S8}_}%ٲ55Ud*L 3$THj a{ǿ{lٖ-KG\]O{oT”v~>ܟmbCYԷ{38/j?@Ldwj?/toZEiDFJy2]T߉Tdo6KTb0,OL"b*k<-f<Ӥ̴uE9&'*OR-Tβ,*q|K)II ]͒4Mk?!yfEbȟ8w{5P"_E)_+tiY6*) &-n&{=9"{o%kV52vy}Rvd85H%.5?s@39ÿ^3>*e0uqiR צX2ZrMs8*mщM\D5;!"u>yIce~83:C\i<ٝY_nj+ KnSE/[nliTh:cߩ@THڳ3GJi@̢/qTb@6݃tRYVbHz(~l~F2H m7h[8[(Ha<,a,dFK'(v't9"-G$$>mQUO(^H?J!4;IJIâ.[c+jJ P3bc~5 NEb-kkƐ75r{~–1@3^^:;LWY_'TמIMIus ^@P6 >^ g/h<\=ܺO6|񪵀Jݎ^{ VE&rS.47jbe5v;[üaN%~Tz2=dgFC cjc$2Y4Ր˞iɬ5=g:g QN_ ֶ^m<._NsUⅹtSn' fJyE\jk%/hu>z<g^0Wn)4l`@p_Hx2ɥ_au2> ih~a ,;p51.Wh{-0xMvwe?].>ZĹA)&1 #g^]er*];3»vrwmo'޼R͕̎s !]S-zG7/;=rE.-|>DVA paMS9 d>dQ4)mǛ2D`lKD Lӌ(S#&ǤkknbesnWua h_fDϽ$Se:2T2Lb;c=vmisZqd_9Yh--W=-ȯk75Xd`mh'`t?-(r=T m{#&2v hΕ]^QC#NCC-tj4 qݠJrZKOVN-I2K\H7lDq-˦t!̍iB^b]8[Z-:nu=6ul>RNx4`WwAa+=tۦ܏ e T)HޡU/ei;ўw3_&i{M ivZTv",܈LM"]UVT,DR(VQ.D>g/vJu2ԪRgMѠ ܥ2^~'^tY%e7#8F%]M| N"'(vS SUcо aVNj 5&ưNiQ {]\yQ/[b-Օ`Ak:h8u ] eW\ǹeS{Y[Ӳ>6F,] 1>ڠX;j+NUĄ%TPCNtks%.l_1%[+ʴ,mvq/钪rbǝ$m5J'K 0U9ΌcET$JY636CV|f+*`EЄܭ#RZ@cwunGMҹ~xҹIL'#w1..V1C&*Kr{*{56T-/Q@jܶ}oK,vԦjڃjKcђlR-;@wH\FD~[T:#o6hFߓxz4~"aE,>Y,aH0|U`˂pd!KH/E\pHPr,UA{.L0]42^f6^P.? KjZ$Vax)G\j].S]S{%Vgt:=OW饁wXyG% hQ"Y$ -52ofgfSofq/k1$bJE ˧%Wz5)MQ7l״ҥ_O;i5\xYEV0/^%pvd SY)ireFz]5pKl\M_ɯ;[?.!8aue9r1-Sr9SOUy] ȈȑUhz%]u7aw]4LFqNj(yaQ]W4-FBsR0޳0͓|SxrsuWbE6>FNk(zc ~_Mt<e 2.~7vAWc,EP. Eu-UָZ*tı4yfzFOv>O!PuŸ<+iڨ$Qa`PMT bWzLEHFP #AE]E's.у=vE\![&% 筰r2;Z&f6@nz[7 ~!B~[n8Gh=rPG7t;P;+FՖGG ='{R텱v}{̤!{j԰wG2lgF%^M#sYG!7gdž2ua$g*ko}&#<14ep0 QMVeC.KC>e[R\X|Llfz럀ȼgWB,B6 &(,Mw:v5[0;SШ=ډF'ZPWBgge nmu!VCErR!(6 )d,R?Z]ieO@VL$ZsH4vk=1X%8#%#AWح֎+q!lmV'j{ ) Ѧ`usdós2?w+b] G'hq?ثp1/[Ę,u׿?i\[P `g0Ws^P$gR5Q(Ɛ: 6J)W""r7mF9@b/=t} /b1ؘ}UiL6DH ߷XUf\:.:n Ov \Dr?|mAC3L)F4CX명?yV?ƅL*4#^T%m[0RmTOtV|~M[wQǥCp9IB&LbfM T**qxPGP,A39GY[gX; 9% ӺiN&k;bمt$x"n#ysHa[\U6)?R7v.~Wc*eAܭv.oJyϼ EANjkkFɨBG:&᳖ ӨdŅjF强u<+FG*!݃xsT_촥"]QÓDEÑ32A00éZ'Y*c~A#5zߍ#q厔dU%SˆGk|+ͩl"L>f2DxY< Ѭ ԑ,[NY-QDiƩ½qh$Ƚ˽mimg\8hxkn'? =.AXqA8q ]7kMFä&Y.[:kc*kf߈h j6fT*|OdIhm^jL@Z)NM8\*7oX׼9#L}t$WUC/FI_ -s=AgG!=08BK",h#r4O6' `FR/ 5 9;t$L<(saB5-~ %r)+I*?|fi*_R|aZo/ ]57\4 _Vz!~ZDFp?ciBa%]9iCm%=>5n'rTQNG?螦rΓUYIuLc{9@&|AYHOVRuPIH MD;4$wk uh3ٕ1ggzr`~uTB>r `!S7q}P¦ lnOIɆu&>}7L3m0頓Wf"3:{!м*9G'Wim,&wWꒊCb {uIDhc=pE|2lp+k촭#{&TVq0@dZkDN"s eWCu@ÃG,QxlIJWitj8Ӡ8eQlu􍞹US7%go|evu ,P9(Ku;Puq:g \$KgnjZ~_3$;7{$\yZ'Gw p?|JUc>Y,4_WY se5h i|;3 endstream endobj 62 0 obj <>stream h,A 0E2Kd6@U\,l (bJ$x{* >;d20$zM#`G>b3/7RhbgLΠऔTBV E<ؿGL9iRk͹kn޻=b\!f~V):1 endstream endobj 63 0 obj <>/Font<>>>/Rotate 0/StructParents 110/Tabs/S/Type/Page>> endobj 64 0 obj <>stream HWYoF~_}Xء/ `(mi5#i#kcyƲ}>Ht7׷FnMjl}]My{Y؅u\ו=1;xv_fy~U΢^D֙LeQ&S %Yr\ie;{'8"b!W"R,.fRy D%&X.b.#>/XfQq-]؟ LT?TŹ$| iT6&ʳBܖq;b%8pڹ+]ņ=,ZQZOe!TE4 cP9+aG1X8NQ0u'4x"RQ82ʂ_y%a8ב ¹*phO߆s',98&a~/4 *ҩUA R~|>^0dB z8@zP"O3jIC2 N4N\;^@uO38܄ήOT ~ʞKX˚_!b'*܇G[Vde50p܆ōsgT cR6dJQDOEõ<N}貅oL?d--KĝUZ`9_D8A,f' v<FMAd>%,LH^:rRpȗNx~pAt[MnwFKZ`+Q[ m !hhցOuHO4)/ H[qh^y÷0;1؍g hYQ7^cb&826}VliWЊNClo~ 2tkg7D :Gg9ŴȽ\&NlSp2e6mC$m$L1xMISQ* m_?!ۙ ZCk$vVCf1na DUV_tQx ['SK>/٬z+`˲F]fWcIa-Q%5 _z˯|T5V5}t)bĦs^<-$N ^ixN=ě`GtǐΜr+Ş. Kd}#< V}5w *))1h0g? B % "2~Z|ok-:m3lRv:{KQl7Y?^7mpz.h#m*V.lz98DNYG~ڸKV\.Yr س?.˪,L:HfC^PZ2{+He MZ PܱZ?Sɺa $|b3(9^ɱ^m)_Ț=@Po,]a:jڽ4"d6aD)[ s,ҪPRr9TFvc3+Ƌ 3%~0TLRN"ᚘe=7wV?%J8mue$;m:Sg8"\tu)X[#WG&JNy:>Vk)2Yk.,W.Yu: 3gk|ݢ굇 dis g咰qQ('7n|4tF,5ghG6ʎ!Ap۝3dv]%'Vx-hj=7 Y)ePJ!48n)Cލu]˛z4DvFXn$u?8v[$ OC`C @z5+rA,M/2v' ~XMF4^+ʋ2'cK#J(g&2Edmġ}V!#KgKX3+-YdMpۆtHi^>:*8s^y'+ ѳ-ČY.NΉ!LdC?j;rW5QhPTPbG?>\Cu =ShuU7g /SRLJS+v0V-xĊt:Y')>&v- 'Rև|}k؏ Sh@tmh;4c]s;f|@[;@}KLm-sO =59r9j 8倣OMDOr4r>ơtCG[[N G !-efGWl`00$] BnB扶n<|[C!6x9R,5gCX臰3{Z{jȵ'f'p>c!sᏇ=z|"-5`=ʾI0 \gO(  P⵽GUHc8jwkh!IzUVI^6ЪH8ۖ2Fa\0LQ̽i ==E3[ѓ.F(LJ_-%Ðc2u'vs˛5;}Ac<蛛g؍wwtO5o/y.,kP%!Hpy~o#<{LdC1O Ÿ55\'sXC3dE3[S,W^5qH_1l$~J-,N.آ%WUb t7hJh4hu`9n1}.5<1yʙ"M9BOb 9̸}_^ULX-"M̢=+ы-xa9];Y~%A<@Ūgrʩ2׸\U^3!a[&o+KaTSu(y"4$&)SDk#Zuj[TCTk`&v~n YdzrA<6O[( ʭ gsoA| OӔPa5oR;X-w;/&aM]WB M :+- ȭӕąt%q-ܼJ`ڤ,*B_py ê\u) l-~E^. &w?;$pn(׮}`˷ky&z^6;dk[[01}G+%^+!W4`K ϼR0 5`r?1+{p \ܽʶ !n=}arTO͝'"p(Z:U<u_t5p5U_Rw&]qmg>cLc=}ҺW賁$/{9ZTy5f) V"94Рhؗ~&Sac~<-C0q|hܡl,=?ǣF'p-N?È]0(H1S=#FF4{t^ʱ hZ5|S*+:$gXCG-cZĪ-U+ܔG鍟-V>A,9y!?䀼!lyC3n%P5JX>"2 Dn˒h;(,\_:na߿QjGp:>Svh ^Z_{}_Jy7)N)͕eeG*{v{`|ԝ'2Ps -ss>{AAdž+cEɱaO{(M$EKJȱhIT. M"؇EM ncul-i._};bޜ#1K5(\B'U{PTڅɵ\)CZUnP wSIF\1I7sYDV3SGD^lȴDs9f?c밯Q[dGf%54"] 5t$Yd\,2>*SFjP5ĠZ@ՇAM7w؟g$;}hQvLBvpӍer̮vr<ቩn ։@Ois4)9ˋثV#}irYws+rD/kKB.$JC=4?w|IǯaW܉2t=A~\؏yO_k_+>gahbZd`?n:od\ً_׃n.KiRT8 &AT}iWQ=<3~_ )N ݅m&&z^f|}h2F=A񂖄VSdz1ݴknGmb/ MLCLoLM7>cvj+=r/ E}uR$5_5*WB% KUQX_^"jot' -`ǦUBeH5R2tĝLT pQrF"-5bah҈>Utc7Nˁ8s0i_0'ǨI\5HJBm .tH,ߙ#y,- pp|EXWKzxCgI hAk&^iL#) J`SJSҀPU9, MJӇF%7Xi|..!iHrVqfNU>~Bn"-7VXnv!Q7ޖ=-4zJht<14zhSDKDDyOj4,>͗$resw˂re$d7X|.GzS'a69I3VX3F+BE`ޓ "Ŷ +Y칻AAV'@cd>cv\;Xx#@:Nfm&᨝]cmް10h[Q/U"D?UܶD9BIL3XsCRX7:DU$eue;H0om>?։aꢏq dX@rc7`G/_:W K7jq|%;%\ۧw O'n|x$;\ړ(B AHդɑ⋑~lQm7kOfsnR<,{'p@0;uVOMA7g=\<.9'G5mX;zKd-g#[ր&zrIVp'{!k3CV)?2 Hq'c.ÿ1bb[Im8x radn;Y[Fu:m:q,,g/֑fΫإ{mv*80\T8#0wTPGd-4@~*C'sr5G -sٻsH?rYfm kJ9 _%tgk0@m[1_@q8M#\zoߏ/Ofeŀ{.G2R*`7o.Mw{7tqPRdȒHn99Vj9s(纂tUEV^`CpqMjw w! gҢpM]8܁j2WF TrV@V^"mvOpǴO,-kH*@ GEy > qEnĽ)3ue_@87 l{DžUmƵtAxjw(|H=QAG?p{FrΓUYKFuLc> r&M! )zD*$wmx>I MD;4$坵VS:,ɞ Hzͫi@4U48Ӝ_`B~#tUm9GSbUKR0kO<ҰԸ*FOSHŊaغkj]T^O/Wca[T9\Gȣf~ۊ]3ÇFgTT+*4*ĨR\6|>wKtUHENhj zopjSV81'Yx4~nc 3f‘ā<:^MmBX"8(C)tb탐f0\ Cq6ӓ󛰨G1kcń>maodwazYlw~OId&WQY߾L3m0験WfUNÃMl^AMfȀ+s;"J]RaTlt/<6@RT#2|۱ԀRJT8~Ӛk#LX<: } ~2$ }qY0Jh>OJh+@OE-qf#S[]BG I$Cr%ݢTmT(Q >P2͐La}#> <\_pڭɔy`80LdLngwitElr{ + XOzT?/# >hS=pEVʰKk,Ӷ:{"\p y0Y:6J"Js eWK3#c@*QylI*_itz8Ӡ8eQl5w1;抒UMݔTevM ljH̯; d%Rw.N'D+i _b秦U5cAG2̕WkO| WO+Q5|qHR ZJd.׀,~:W_D  endstream endobj 65 0 obj <>stream h, 0Dezɦ)m)dSx=h (bJ&Ux2S рH8Ʃm[ W U,~@NGk.KAX5#ʆkTՄ}p_g眏R3qc ;eY%b R~21 endstream endobj 66 0 obj <>/Font<>>>/Rotate 0/StructParents 111/Tabs/S/Type/Page>> endobj 67 0 obj <>stream HW[o~ p^fċ( ( l{g۸>x'&iv8RD`K"7̜yZ_ɏ? {?N._|x<L~9_߯䧟Nߞѻw:*ެ LW T"!UYQ^K_ϋ) Ϥ z9:N ӈq2.`Z,)'ϣ?G3J2}kﶳ Z`vAk)H)XcɫIۚ0)8[JZW yZ>%#WB[+Z(Z*s9t4^fBJЍToE_{F¸X0&FF0s'7䬡<nj*O>hcAYvyFE6wn7cX&# 캗ߑ{ R*|T_Xm(T(oZ. J}?g0%hB 8p OGLjI@*Hr)^Hd/!5*q ܿg\cgs>pi<5qxkUtkLKȥL.="{5*k &~&dCAۻ02(U2ls' eRkR?qry+*R O,M4誢GCkrY|Lat M91,SP$Ӕ HQ#ۀV>s%ӯo8nIn'R]TɊIƙKm$4ASHQup&ht&ח ?|=9unqA@MFMcj_,Rn tY!)~#PjNh ~Ps(E.odkBMh}NbCAJhAŇѧMeoi>w^Ȫ?D+Fy[!a:OǼPh= \#i,ܛ_kGMč't?Eb̦8-ȕ:e8ϾLeD;Vw[ tZjEtvѣDI*TɓlT-~rW}^`=b]zlb:`gZ`Ӑb& hZ4Ӄ#BX<#F 2 ahILV,`м$'vL'z9Drǀb`Dz+>yg@oed~"?0X埜1n?R&0iKqh9N尛C,M,E` L.t!K$/E[mmZ>\tb_\E3^W}Πu7`ֽm ĘJ{8!BGa1":qthKCpWf+F!}X Xm"ws4\@6Z|68],nysb|fNŎqDdqZO4r̷z1AEK޴$myy\Xd T6G_ٗc,=$ O-Rw7SOY۲gc[2={+S="R{P֪Yv흃-4n ˢ<և8x~0qN\]7؁dnk3/="n^vG.ĩ$&]SLzb,[əM= :Lڝ 3xo%6;% .#ꏖUl ,rPSgQe͌jU,w3?!|F~T‹.ㅝ:o(iQϐ$z47F%֞$.T%=j`޷β#{#O'\'VbyS*ht=.*l+6.:R25G9;)B7rPpA8Iw*䠽X$9p?VͲqX`ٴ'&  ]4A?T do/a0Wpw:J,:%)q?Zvn%0pѤK(1"9Ip|i&Jp$D8X p;\E.`'8kFpz-Š(vaEbOKe 0y &\4 ZhzToa0`ճ߶0Tm_XP}w䑙Ӫ? aEbTTwRTڋH;cƵ&2 mCϵ[_+U揱z/ Zkp+lhK ՌpiΩm"W0[Fkhpx LyZmi]21%5z{BӏJ;YOO}v)fЂ-V[GYjϙx+AIIͤ\@s ^ss]RHuξtKfb/=Ie#vSPd9?p$5GOe4^ &*g9NdOyAp=aeb' rզ`eZWy+|>cn*Ԃ ɥ5zK6'YG:٩,xXVi޺̲ `iKWh۳mיY`wA! ꝴ"{]= W~Id5|-g 60<{f(7g ,v<&H ȪE$49r&Ts7ǵ0{Fe~+EUXn@7>CY8o?lPn֔dZ VxcfN^Օ{1d' ;SmQe+(t i8*^&/'@ڼ/TWX􌦅i X[ND:Ƹ^ 459 HL85=;y1CLel*DD*+'RSo9YFw:7ъP\m ! lO$]tc#)e%fP/߸Ns|̕fۉ2~pRQw},FdُxfF|^^l3rc+5;G>9şSbbi(e0ji^~]r1e "Cq'#9CGJ fPA*:z\rUcCҾ -e9SP>*-〳sinRp>.p.?. T1dr(N}lI}4`-Zy~PIL`֠YueQӈti] =&dka cЀ}]| X%I]QnCNUM{| %͠h/j(4]@ }n~yw|Gd0M> ~=zP5N5 {2wnʸ {g:?|xE*!rʐ`@px?&$0!8'4R.6+`U#Qu=+ʐζdJS*B hYf9ZMCS4g wǖ3FXZBP^lcDIYq8 - kÉl ̗Ɯ]\IȒ'|[smՔlr=Ew:1?je#AA|q ' ҳ S6ӫǜWю .ȳ.\~F5^?3l ;6c yHӨH6G=v Ǹh)-U?Xwj5 ĉSĂU-2j姂*Zr%B\7r]$vA, θH4{3[=wӏ O+گ8L.P9lbL幒%N#t-Dδ%i2ˑ"z ]=YMQE1 ;nI5J*4Yt]))yiY9tTE9}9}B9t?PuF4א.xlC5=8' 8KEHw~y+e 2{˹U[LEX{jo996/zA}@Cf p [k9+b({ǰCdfVD7]ZeA*B Xj doy&-lmrG܂T>_]ץA1H]3I s{Mu^UMLrYgSi Ytn`.+)(VDQbz4^N-k (ښԨӳ8J]SDe}+F9O'=2 wQg}yjĞx64%M@(nS„aDb :$FG,/]h :gh'@*3>γR|g6P^z=RUw~u3oRHlx7xfZ6MֶL.^eZjYnȢ{E׬1 &v, UDZ}v7^Dy6t߾sνQ?8/3ޛ@ӽ1?%x\';q{2d/t2ߗ.ÜYO,,/ WܧN”~a\w_G-V4x7UIմY^4ީY(c| H02ssORz/zZE:PU$3;-鸖lN*PRWb '9IeqI)cCNN7(EJT)N,J,/*Q >+N z^D[co0BUQƎ8vuȻ)RSǕ9;_l7e8b nsD Օ3Hp)YfQM ܈0vlGwsW o+*|s0)nAKTD~ IbK_\@Rƿ%9;]w\Fћt >6ش*kHCK'_aqU.ɧb0`lpٵ:X 躗Z᫊A&p4|ۊݶQ>1oVT9JۙU=;IL^37Av7^JD<ԅZ+c?QmQ WqtHqApeQ%i;x TMݔxYjeM0puuGl$з_u0|/l(AH*ѯ"Gk30O>Ѽ(% endstream endobj 68 0 obj <>stream h,A @3! zJEPPD"ҿobxw)!a }Dv(K5].F6x}4р{lT N gQ(RRAȲGa?ge^ߜ&fseg^+S0 endstream endobj 69 0 obj <>/Font<>>>/Rotate 0/StructParents 112/Tabs/S/Type/Page>> endobj 70 0 obj <>stream HWYs7~@e_fs+*[VrDWd?PXRb0ߧ`."Go>,/O?=|ZY!sztvy8Z؅Mij_W|1;U<_^^W+q~h tf"WyLRi"R-WݴX\~.b )fRy m$ivp,sT,^Ђn6+)GEEK3J Iy)q<>b8pݕn yl%::~n\. *BPS* %]Sq ݙ94k{_Z~݄&{5U–Y[,,8PpB@BST~'$eN ;PeF8g$dwײk4(t{G3cm~<_D!^?W@iaeT[㴸R,rŐǫѧ) {R*T2~o/;ɗ,?樽趚2KV[[QMh`=1]>AԽBz^TFdK8^{؂t lPfVқ$a܃mOXhp*զ![Z4 (Eh((~C(ڦ澋^n`s@M&ATfvPD@@1- o,KMM~p{^f|2SD3yn2ID,Tmu- ܴkOiNdYNnȉj K1Yj/-+ -[ASBP`[ m !YL!0p@31*0wVdp䱡lOIQ[P]VQ;lg ;e^+fḫ|$<||{IͧQ ߆R`W& ؠ!|<=͇t-IU#)p۰3:΃Uj- NF F Jk#3oeu?0vƂ,χ]us+`K2k +´Gio$e8ؾTC߃ԥ# e^OF9?v0fjG_o B1ℴV/0(Uvfn]Nzz[U/1I qM[S5q3l ّBUf!}ҔX+C iOׁ} /Ce9g47"9HţӕǵJ&9.r=ds'u>~LΣ̷e4F= e͓ɡ;A#Bxl8$4@}p ]^bOdiREf;8UIr~eI%fᕕ`.պ:VtuSSϠ=baNXxp\ঔDkPz]~[Q^(T.DUK?EER0t6utkbᴘĐf2Ʀv`/4,`!KX6晶9@^m+vRN=GQ\SfPn. 42gl$"=f96)ح1w ם;)#LJ!SFr8e˨; uZA|7yA[RzͳPY'Z3/!_>KG]@D#'o8܇]<&]@SWB,1J9H/2 tƽݘDz4f#%49ܑ#.A3pIH xdYl?Z0-7cp$4ߴ#7!BvBH`d쁗CX*ZkU(WMLRz]l` Ɵ7pk!e2?át9ISf܊mW80M_b/p-p}qTk$݇!tjkg12do8,Lz8~ϧQЎH-, ScMw#yR8Z(R$mv.&X˯Q.}1!6Uh%1Xh15[2ş-rT-Od86[*#T0[ηq|8VRElax<&fՋ~ WW===}"-M%:^NQ0:^wTu٘NRp~5\&$OmJfjH`l3·=!3"[\h9|,$6}6[y/溌6VBnLSi1T^*`js=Pw5U鐧B:FU-wSgZXSu绐duAsg[ ήm^Bȁ@PD!:k3g~|⿆UU`8%N:0@Аr^c,ixxkH*Xk2Y1GS`"GWRd/_xVT|7(f]۲qbǣ!xTKYZ9ܜclY^EZ}U"l'(9[Ib`߄փLɷT_# ѕenr1KDjUwIViQsX o@j.^]fg ٗNrtzÛ+Xj g!ןԫq" 5yp Rbˁx佽݂OF)sMڹeӚs$tz*1 /n循 y$DI%] z@BiE;M"Ү2?BUϧC2V횊uڔJhN]A@eʖ?yۦ)!c9P'e]񀈒0uCS7f]]r3Ign|5뽧rc61;hFY)tm:sS<[rl ֿ%.'{SU\a;]CIz!=ݥsxUhs/4,t(@:'V ȍcuƖ&TmAx=&}& PZzX0Loo $3a&dd.xMȧlDYGsgJ̲+mE1zeXh",neM$q`jW{i0"U2kT,9>5sī){]D2z; m2F\7/_7#섏v(ԭ 壨|:Q*Ihm | 7Z5еWxA#dQszwУL4&;-U .ѧ/qz.ߟ}o\oߢ9 ǖCy`:s}DKs|`^u"˖۶VnKxkd]dgg .:( I@dQLp38S=Qp_߫ Hc%?rH+\0SdLq;.j[ٯeq*jrYt(I㈶pf$9bCo|Mc'N3iz}&!7X 6ǒu e-r3a\ؽ p3ݔ>wr_[72>"p Kdg^“wq)]M6vF X| Я|Q wJ]|0kӘh<4**ذpe_J;W; ږ4 : z&hRZn XE"댔Cr$_\I,2q؊Iާn}-xt} Q9o,wh1%ځv *݅'3IڑN\9vS' n️4h,H\8PK7 Etm\ad}irB/|s#\p%Zd=/{9E6Us, 0h% ZL> &FtTNf`ؓEA6o q|`|~a1Zq7ݝ-.F]8'+M!6t`ባ YR„~EN!V%`qTUXIxE&{|qkկ,<3m Py LXi)b䋕<ʜT1 ۴^Vf+=O Zz}&a7X 6ǒuzJ$EиAWйʅtyVKݤ"]'u2_ңI79G'uS&6%g!&4 _p D}9ȬqϓbzbeB_LUZf|9 kWD-^Ӎ!{OF5 4륉7, _ KzAIftrޘ9VQ\ms] t ?j ?:6G T׬KdJ\Uh&|t@m@dtV M  )*;yzPȓJ+Q^g.ʜ (h\._EĐ?@Q$fp;=?!BXsOdf{eG|9}4"t'kWu%LtJWOX^CqYq,l`/N! 咑LKeSFDo"ϟUx~@s_?.Q ^/ mxdya_ݔL{аvAָGݫ$xTc+U?ݎQbIr,\ݐ?-,uX:\YM+|{ `0cX^oxlvg6㱿5~k6A8 ` ÉϧCk3M)^F)8H WQ22˩ȐHs@ITdpwL̻gYZYm+ԫ*ỸFrF5:Szd/[^2$׏ ¥1Il/gV%Px{'6Rpp$jw| rʦJdz "Q[nhBýIjYWKv($Pq:I?U,05*qZ VIΚflUj ;9CꈘlNײp tZb~ɺ1u0p%֤8E6H/rLj>g8lBhOɤ{77Cu%j?.gn$Bv!,Q`\]VՎ>CBÓWҡ(+]xVQJlZ&(Ar8-y\\<'鲘^V2~^<x"@wOc>&zHFj!~bhԱ '+V!R[No q ~{9kw_Ȣʏ~${E'Ldj|D'K! P =KZ\ʏ+);@ylҵ7q偰ľeՐ WyfC7fX4ꮌ{SkT4`4P/^YdO,Z;k/cUJ¡%VaT.SņaغkjMVw/WbYNPJ.Dȣbzۋ\gQ=1(W연T:JrI̥h=М,P*Հ?w7=Ǚ6lLjyrɘmHF2Wa'9$$vdĊ[-2j%$ 5NBnfa\Sq6QJ]X#P y@?ńئ^p19:fV3^<&łWu":| [ʙzZ0iWF2ԝ"5چ;!X*ѣj9^HRd=:[msI{0T4e:#2|ٱ꫑RJTݚk! Xyt;l!.!Lw". Zir5mQاZϙ#ВzĔ ,dL<2>kPBB%n?Ȑ\-vjQcFe(ntT` iTdnmaЅh{/Ƈ\RUy(vؙ~1 oJ"L39vjUָm`-`foaҰbGB#C4'ppEx|ZҰKgx{zWiY-#S?j# ,mZ;#{# ˦3![@pD\DG+}V.qNq@ئi;抂eM͔xYh*pz G6nhJnj⸳$N rW5Bz3a t$fC J͚k-U\Y0Gczw݇7 fT endstream endobj 71 0 obj <>stream h, @_eug[ YSB'-:4\ [-~g@5 Mb0VaNM~ )Q,;_KiGH c,jz~1̆ykךsY,{?yױ{گ 0 endstream endobj 72 0 obj <>/Font<>>>/Rotate 0/StructParents 113/Tabs/S/Type/Page>> endobj 73 0 obj <>stream HW[o8~ /bDI`&Lgij)N\fMv琢$ʱ>$Hy,7NNO\B O;?N.W뚝ԏ?,/nW}b?xM}ɉfl~2k t*V")bbE^$|}Ų~Wvrv'2tf)lv3MSX_$fų?&)lY$4)3rY^sQbȓd%H YEolexv4!:ik.'w$cHJre?ge!UR(_1欬;#a&)X0fA7V%BaIDdy&U"xyRD?"ɣT&<:o$Od4ov_/4K/,Wk?~g2R૊?~zjCHyjeAyO; W2 SDD淂/`i'i Ģ"k+KGAdQh UteS #A׀b߮WqL^+|½Ǻ&XO[Fhfq Ł=2zu-nL~'M_+)Nʔ(gWlY,Tkٷέ4(t{GKmiJe˳_ nEξ}OLÁf?di0ɹϓKnXd^dzoaOS@49TH}^wPϭO(w_Dդd`Uiܶ6QMhaB莂 ^!/TF(aK`z}a _`NOwY`;ݮ m.&Ue/,K5J}f%4KT/6 ْUC/T'ocMoDkB&5.&{9澁 J&b =;]" ĘV&Y?8 9/Sګ68aQ`*VBhjԙIpmzهK=4!kۂ~OCߞƚPٛ$?6ى6ZwQt#;]/=J) ^y/jO*"m| b*5/uY֮~caM8{Pe:1'ax8@PeqHa1tp^+uWpHՅ7:gAbzCqT.{3ZrK2*=yp̣7KKkW䟩h%xu}Sr3{q/4G{By^tS'e>{-ylh}Ցit DdW53Ւ#li^A\x1W1~g5Bk9٢ 0 Wn?e5֧*uI|Q~\gɹ&J0 z؆֊Y7cR-0+Z@fP<}1R0:pgB7Uo8\ZGS+uCaפ[5uo>L( Gydɩ?IY5au.ݛ.5J8I"e``E`Q&€?uP3`Q*4qwFfm9:dymJѰ 6ƀxGp>JFH `-{^Q.Em*((Y0GJFmOiȗI kYwm MdPk9iI_QYKQܴKO>pTD/|5+祋`ڲS61UieykmNԹS掵܃+ D7Ώ &"̲:rsDmį%ݐ|%ytN!R鷡KbAǯ(R Y#'kf{KOwXYv]f7` pnhg@sr@seF e@sy(brG@ku\ 9NA{΂$ G6dP%Wࡀٸ ܫؓ5{Q,$ @(/Q(ŵBj/Ƨ"#oS@ 6VϩߍLVԼoUaQ<2]u`cI.bᆰؚ^q~n89%Ǥcw(pBu:8=Djf)֜<hQHH!Rg]<*x$r+^I9gCL:Z Rd.v.i:ṣ>}C(z(L,3ڰME:> H!<;haӽ1&H/xVmiQDнnV*Udi΂ͮ'㊵$+xYE֟Rvhqy(4-w&ETЬ?zG-8 l+/:`fnqPb7ʖ}'$C6G5G8k'Bv箨rj:/`V WQؒ> m 2NGF>Aszljv 32QJAP^z ڃTR,!hU2F{" 󂵛GqX[6Q%8Dmh˗ХM3ںm QůS26H dWP<+"ej@W5nñ/I4W'!y4gr/>39utCpu#գ[ʍjG!Ռ_z |Ϛʤ*!PeL@{W}N5P$e? ($׻!ԫm{!t=қaf^ډ&J3+8>S(A{ 11YY dh.K{ȍwE?xE=z1"Y㙶=3m)J[duKߪźsHz7(1gnXѩP['q ou%$=<ݘ]h[籃p] +tIZ ,_Cm<\b:!ArwGݮ܁>WG0E_vwͨ6W66fA#PRS'R4Hm*5ݐnX16(FjZ#X;`33m (_"Ȳ݇L:b3--SuzaU>JMjl=h煀,y! #'è4Ԟpv'ݦJIA쇕w1q-H_؟i<1{@ _#ߞ F%Q [A30Ѕ*"Z;Xa|YO?7cwVf o B??ֶ#8pޚ<0*8$ K]d%-2 }M3. t̥L̥ܥMTKR6\=_Q(Zw)*ϩ.X~Ap©p~6.Hx[2?4ؘS9n|1nU1 C2 Ʀ T` jHA6^X &z` 渽r~O?Ȧ4,@k;`/!im&U~D |[>1QXְlkNe >.Zg`7u`z ȘrFj€ - ȁ 3Y2[d*d@{aAf2 C,DdB2&nFј(Κ!T7jMNp68"/,l3rl^(pƕ67#fha Q \Q}+TΉ{ <~rɶ[^z+Zo:H'|ßdٻ׾qIF]\頄=d#KvdLj:[Z`wOJjV_̟^lPYՓLD{W%4z}wݽԮ~s]5'szW'ڵtރ `^úŏ)[D:ZPא/dle=_9 h`2ZZhahF(mB^CT)MfifhN7ueкBֳsD(+1qshLZ.M^Vv/ǘ]WCfV`l.U0{hٵHMNev,fϊ% ):q -qogan9LfWha6MqZ&b SZ/9??8I/*. 56Ӌcz^0` R2zA^ {T/t]4^,woo?]JeAJ8 ,#7ޝ|]>O/;OsAՁ2\H> +dvOFV]mlيfnd*+|ò `Я1 ]r`N8ݽA3Ȯh Ư,/'Cs' <*ᓟz4i/7oR<6ګ {cguCG/KRv_atR*Qa1dV) Qa/ Y_Li\b~ͥiR4QYpxRrWo(a䤑s Z× ǑhT^^ѫ@ujUx *fSM堁#4kjCcUPҒA/|9b0 /jZIݚvA K E?1W&jq^i!}>]o4I)iQY?D{ EvHl2¯G:6?SinjWv8p{]N#{Tq~t9 ٪lX#CAd)>py~Mr~ڋ\T$6 Cᑰx KX"cͬ/~i|˛[MC34ƻ/M<VO{r0/.`Ukr~$.HRӪ2N1k`k'eGjmR c;\Ņk*J{m1A7^z==>'$7QIطW>Fʥrj G.(Gs xs~ЅN;jN=ۙ1lJ=e6&pN2fʑā=:u>#pV P:Z{Vr3]j 3bGSNfoʢ s(GcŔN}ow 'azIYWLlaOIbWɤlh{#v6&LtUN DɬspXCm<v)A]Za dWZ3ؓT"@3hDA[h;pZD9W5/G#L4"Xt3l>(CMe=FQZN@[mR#: hs=pE^˰Ok"yA{ء.Q"X!" CCDߝFZWK>!5?1d.~RE4d>v;aiLePlKc;FJT nji|.KT-r-YkܷydSx8/qJԴX3$0{4RyPmEA >1\8\WL 4u4g9͊k\`E&4Ow_ endstream endobj 74 0 obj <>stream h, 0 _%G4YUFa;9):ؕQ)ݔ)& *-H`jM#`Fl?nzog Qؠߥ@΢P -`de=_L}z9f{C !0pW0 endstream endobj 75 0 obj <>/Font<>>>/Rotate 0/StructParents 114/Tabs/S/Type/Page>> endobj 76 0 obj <>stream H[o+8/dqDs$@huӇ 8`l%qO,ܤ<ؒ8ܹ~3{nwܱ?9=~eo(Le߷kv{[wg'+xw gl;]-N&v{{ނFiX!ɊD~ZW;E.YfqZ匳ՇlcF[,Xl39>p>泐vJ2-+SO-C|s!tశd\ TV[/~gdz C3 3op9\a+&ŹZMt4fҭ syKfHª2^&e&TGYʫL$HIERf<9Kw$dwV8,5]J~ _-iwuLn_5R4J6`KtnO~Ff%J5A_!T&T.% *qR$ZZ͝bJ)KI޻} 2 û:]'Yo;x&ͯ2uolc‡ DNYfi pxܥŝC| ;ISEYq cuv77SQ1ȧ[y{;4qvq+ ++P Sq`w?vWY.olfϋ PvOvxu9lّܻ j )l[T2 oσ~n Um-J"3yhmHA)O)(: ix #:Kl3]6ٍ톳2+RM + y2FBPfP֚jI^vKS;Bugr6GAXD@AsZ}̻B_שT=z/G`J$cp^f-;՘ @r͐kl%55¥M}CDŽdS$*ڟtK%qˍP8Vv{l{AUn^\ڪ;KRw[7De¸֘9M?! zk[}j?M9oÍތ ߡߩO).pQd$-]`!ďz}(}Di9J΃@=|6gma"z|qB0, &C!뫬1B5;0W7{8CZJsH/u:|C* v}:źcn 3TЊ} i 6MB}z׾^7s~~jC0„8og 77)J'x7-,Jar 2+;|:eKKC*Krh#+,_(dALU9&XauY:|| Cm ϻNL$_,' * z!04v C#d4’%$^>L1³u#naA[= `x&“Za1ųu#ōnb[=`x&œvS8F'M1O@X|$ƞnO6@;glRHOuUdI`/z]ʢ\qbӍR.X,\h1Z@u&O< RlJŲMk>`_=C: -T<$ Gɪ_\'0[.ڪ. 2Dەpd} !< ^qf@7+r-1R*CyR/0Eyڊ/@ Chro4$U0¦PVhFC$NSd("UiIxIPwzɗE 9l0[3`T;pi'7\l6&KPk(ۮVU2ju:y]Lzz5awu<9xRK0K©hB-B!Ȣ?]|ؚ"Pǘ?p[z9y[JJ̫_&׌Bz__QS yM'`~(yϓG̐0s[$h=(B,Q k.Anb2\q9* ;Tc=RnX%)V&(d.RXb\x1s0} C;9/ූIJRq z?v#e.V;N3zK&/+mXr)r4KQ-±$Êku=4G|12WB{sԿP!P12͹G/1O n=~ P;e$FzC'V5 /kִ8iXEJo"P&L݃q?e3󴛙tc,tF]ڪ%w5&˥ *[o=;VUhnJLU-qcaKl5!bK_uM_70U, "*G6mrBY =oc(rDmQh#RWY5Ҟ5X XvuX (&5-)YEJ BYYIM(jmp8DdEsכEH <.3y;#-ؕax0{iw'Α2͋}!}(a %u{1Y3[2bPVgUsUcuԩ$|}*R>gi:Œ5oVL5vY.#nZis"m71}.UǙ|Ô9^(( "1̞*B,e",S&~%J>8;[ GYd^xG-s葧 TWLmւA;(3kޘ D8De/푁લY)_=pqm:mQvQ5Ѽ=G+?jQwuG@SJ7ɝ-7ہK2Ԝǘh9k;Ow1؝9h0w[m=SCL3rzA b_[bX \qsCd-xhQP_hQRIk>m8v7;F)Eӄm*V rl_vY}1C! ~(Tx݇eZyY7kVxĚ#=U5{D|a_l%-&~q#Gf~޳7=Sý:5]HAEcNƭݛ/ۧV֛vuح/7qr ,̥n /a}_mT'(7RQf eFeh4NF6e-I˺BVh鑭n"U|Jjṭp S'R"1a/ȱ+lSpcQ*7| &^p]HxFoƣ 6\+F)7Id*5{g,YMY7pGYJ+-/@500 )mQ ߕd.7d`=I#lqgH]nduk"I%TI[5̈́ XR+?p 2)& }eiv2솙`:`u\J O/9ƕ|㸬1r l* M*]$-{޽`=wo&ǟWMoLW1];q  !nNS=3엓H|>3e#n-o5L|~"^h]So"ty { o */Z $vx?BݸSVNO/`C8rȿ_s=<#~_B<<"x4;mֈ4Oi2\m_u(x?nQ@E&Civ}9_r$嫵%k |34t6)iLs0;-˺G"GDמuQDV|6)7N#qEFo?F)V` KZt饰|^ mq^ 3=&c21jEI|o0^q_״R (-߯ʇvxzQ|>/僼5?7ޒ =89" ~y{b~cG~kHS`3 YQ@[V P_I\ )G7:tnZOB [E2@m)"\ +$zfnm/;C6MCd\s.qɔQ;|y|4x/ngz;Wiϣviњ:~[럿҈c'd@ߕ, ]pE{9tEy v<܅<V<adahuw9ׅJ(O!rf8W;1enġh&tL )f Tkb ^>F+)^55ӿ^ւd+|Ouȉj>stream h, 0Dez&4RɂDzZPĶHM,f$8RrmYbv]g[?1)[cR3+tbrPIJEtx _g5 c0f9&isa!..SǺ[c 0 endstream endobj 78 0 obj <>/Font<>>>/Rotate 0/StructParents 115/Tabs/S/Type/Page>> endobj 79 0 obj <>stream HW[o~ׯX༐ͽb;ESmr"nP}ibɱ&gvf\Kٲ[$ww.|3{~}s9X<8<\}gZy)ts~Wu};$ff9_߬⧟ ;M|ugHd(T2EV$4_Wvpt pfbv9JLS V%fHij'DfbvOY$4)5Le$-E!l)Q mLR'q<:bdNHܕIR#y9BU%EK#gu࿁}(a&)X0AWQ%UNIDOY*UwTʤ޽EEoNdtOU{Lt4=U;I8[<5I ͯ`l^Wk5TD>/\@4[fK|܂O Rp!TOO^ ( `O S/̈/FP8YOSN@d/'21*q9>oC #怊nc {pgTW`ovwᛂsV4o7͉Xbe>T"Y%$ A}lsqRlWB4WPJ)? +PV?pޝ+~"M(ɟyA[;NX9GnE&RW`iav[?iq;ɤϓS]`m'GoaߦIH2ܳ f6#I}_!7n38@Քv%]ʒ4KW2Df(llEAՁOH4TFʥ[k}q ÷=]FwgD.P'U/^cRMh n qej:VhiWql[2M,~S(fd/6/o G~ ;;(" $L[H"[?8 9/R^dv>$+X`4 ~Ez/%EjSҭ-lΈ=L(J֨4N<' im/oAhmH~#!F m FX\0G`  <]ׂ>eP8;z[<}U / sՅw4AӼCl ׯBN١\#1V관Koٜ1YY ˅[Btp4HYr狕0wJƸ p'igԞkg]kѐ $ dC|rNq(5] ER,ѵ2c &Hh̔L3v$ݧh[3AZ1ߐR"jo5@fVHښHcx\"ε 3? f-+2cԶqnSxMQ>H}r?gI҂JxN1o#`ADyqDo[44) uf;qO+\06)I%m幊W.b.{VhRBΛTtM"\^ͩPXWJTl[N1gz׻Kncxq÷2rea\Btz1Rŀ[jz_[odJ轤i,:8ex}pif Kޙ&92t\@:HC@+e^éżA!=҃ !'A.Yeop[ eB+0' {RE9(roN_iWn<Wuo5:B;FYrv圇r9qZE'aLqq8؁X -]ePA{<-I7еv)ݟ{~L0?#-2i/ Z2-jB&.D,bä҉[Pa^0|񴄙xt0A<#f,jSb' 4TF/g-2 ЃYAe0~VL*K DcS 8V!!>LR>7 دiw 1ȶm,(>. ;ǚ^Ve^f}To͸HNAai|PJF(!f(m7>TD院y^jE LJ&R5XvY_yi!Aw+M{"3'N؆iJ6Sa͊CSiglGn܈!'MiALb;{âg[3)(R$\r[-Vz~Uѡ[iRV;T董a9xG5C&OEG'9Fm^Y ܹ^ M&/cIՅ| Ec~.d9*<]X{4ptT _(κ`rӅgkQf>1ޕDLT**nFgHFO!i4Y!n@# X5(0YwF&_6K-R+|JPN[Ԧ;%G:^yt`I{;_CH%L>#Z4IĨݳD@ RqN:HN "z 2y^ֱ\7F-KԷEICDy&>2[SҳR* iPF݊%LN<)ہ-byǬ U V?0BOf ւR\RJ[(\=۲=#^߽PRD-դwOEzi|; {vKgRҿ)@>4A66>KYi[@y:5O>g;#˒1'-&Rw-&AwHA'-Q[T<ҕ@ 9^ ޷BZi&Y"X@HII## ;HXHwKCh+*跔do;FGd}dECp*=zإN[ܾ9r-R.JGaYoIf ^aڤܷIӝd|g4ĜSYl, %|1K0bIzfId`jv[ʛz 8蘜81ӔgӄxYh%~ң'$/ejr]w 0qYnqf[w `>l`VbW*8U/GPa5,+5(ZceVj/`BD{a"K5JL[#ů\JRGuz1 aΛSvD]V^v]rNY*q!I@Z[Qg6d{dIDJ GfШgSy߄eXbo+sŬ=oҳ2`r@.zg/j} d QS/ls)L{zc{y-ZjnR0u &FD%#^k;~oRw{}\kks$ʯ"/ L+(9~Eb \uP=Qo|'lzxtN-L0EVe IUHAXYL Ju*9Q嶾mB4 PΤ0?&YyK$ h3x AYwY`.0u@HB5IOC#WEG~%OZ-C\)cOjizƒ>#iJ%J?HМs݇ aϘ?9s!I3}?j?a-l5Ajf93 `~jqX))6E"3(^E1b#5CȀ`]dCϿ) ^9lv^ll`kbc)Z'w}i?|&+#E& w\ rFq;đ}y/ Ko>B ;5pu^ ?47z5NłKPGWiH4O^ E$+jF$vLU>+T[J@rXVxP :U:B!R&>%}-tF'6i=JFة)&JX+,u([æ^ l%G}9)87yV,z!+%.%{Ud$QΗzҠy,3Wc8e=PM @;c Q͟J6Aui ^ߕEvVH_#8R4F,ZFt.$`B{ٕRrLJ>d*fTUe218h"h,A۸d;:}{\A򂪩3y+#\FC-uuK,%зa&.R&ę+qꦦUX5cAuG2̕WuiO|t WO˧I5|aHΆ9\ȑ `4tp|W hk endstream endobj 80 0 obj <>stream h, 0 _%G4mUFa;9)qR|{)!'|? $$xw HA s,4M&3 X6xnZxoԌ25L1R)(bIab:>YƬ5Zvs~#u̺n 0 0 endstream endobj 81 0 obj <>/Font<>>>/Rotate 0/StructParents 116/Tabs/S/Type/Page>> endobj 82 0 obj <>stream HWnG}W4/3h,)8X9vD#*eU]U==7`$}{S}~s{]_mwR)RyJZoV?.onzsngx1;Ul꫏8Z@"UaйJ*UdEd^AJ=\5"VZ-gڨy J,2jyp,VsL-Nyn6$20;4QYRٟLLť*4-NMNӨ,*uǓsM.Qщ# ]Q+N(˭2**r_1Jݤ2?sVShis3{ {bkװV_!ڞhle>|TeE6V:K(Г!Ɩʡw RbRm؁&G~VS=[L(ONJ|w-ֹHBG;,𝜣)sp\Ju 3:>29,r)li HBB*XA`E*dx!o|-SG(w_DՔ'N=zRhB*; |{L# ȍ[za _/`NOwYbnWgBH$QfUeo,i#nK}*uFt'^[m d+1/zTwb"%S ů|%t16 Qdm%Ŵ*\&Nl*8FLWmrsltFyt, 9 P  !7l$ctSEKw}.ҝxѮ/ޞ<1zŷܘN )1Gy@mD Q-вi@;Qtkw%o* fng^6.i4TJ@Ķ=\=tyQ6.Ot-n [^I]|չU>Z~+U: y+VJF +u`rw4C65E\sxƂ-:dd2scS.d31tY*`#! 6p==gfjEO+R*9ۮxbr f;c$I2*NGbWŴ. v@gAhCkV4r4|8Odk[@Q_Zjz 0b.B Tθ2;+*[$8ucS(:2L5m4r5В:tK XSKʄu~ ^GMʕzO8[liBrO\LLфIGrP+ܶL-۹]@XDo_#^&+ʨ~~DFQ!0D@7uׁ_ 3q^(Yш$[@!MH!P*\ܒ(7_,*vH~yQ<;r"NUpi׀/uKA8_|OHEe3d h{9 \t rz`Ye^ZryO@ 2}Rs-)IOMDw זR%j/.5?6Gl7LS%kV ZPѨm/j%fշ2?Iaن$$ % "̾L_g 1$};wd_>-c$2LF t@goO~9$}T́ڪ|;;o_/֛ajT,tb=du $Ç鸺y|5 os%G~)?[Sb{Eb8&n>08-1v_>âPePB?5!Tr5bMX-y˧KS31u/|z8l֣W+CJ܆ryLz-*dt SU%it+k{;3y4&i'E7F">KIDKiY w-qw2yKU?pѫZYvvuHf~k=Q2e 2q̂Sx? w) ?T(҅siz#Oz؝{֚ӘgnH$q,\q5p-.}#CޔI5E {K+zә7u:f:ZO0W ,G$Q>{KabHw<%SG;R{ʄJ(ZOeޢ̧Pg ǡX^ބB ~XT^O/x#!$*92j\7WMܸ+:vq[D}n z=Nkd"H}%Jj=WU||JLGR*DЍ@qը@JLI;tڿ]Y r)2,88lC3'Rո y\!G)@@SSԑUt4gRBp*_,BZ%CB+aEF0%02)<3)Ky={@Lq d&=k&2`&Oe0;OK? &=[V& I; F5F$sK;Sf#U2ط) 7Ҿ FspM%&*-Σsq<g#>kzYH㪌|נcFZaU squtLEi}]tau *'UAXWDvU1$Ũ.I2".T܈Ai"Hyv2}#.5 ϑhGd}0oX} C 2 cu9Hjm0Asʵfru* oH"p^#nwOƞl[h+vX+ҍ^ ptU: Ӂ Jl3=$WH~E9LlKCly$p U7"MWPDLzȂ+YbVgzuLvtNB|vծ\F$48fXf s*;9^(aPG07S)4awj0tl3ua*NmϹOu=nwTP_풔MrR5(Ւ4a^ Y.Wuz_̀ȥ(d4=M钍)эH!=OIMZK+U)Z{ 99A Qot%]e/1"ޣ.IEJ}V' 1qi[#F`MQ2A VFd4%3 lD ƠZHRmek-_Tg8e*79̺FṆP7[l(]!}X.e-zف&1e{p+<>tbH-ɍ!Ori9 gFu5n/˘ [u?.k ||7eȣΧotv}~h$`l{N%MgTN8Ύ} ߠ^ә>VR/x9it΀BѡÞo%U#Ox#šj>WŸUf)s^A7*sly@D{V66UjcGg6`b: rEB#WW\KrIaߊV w* ͋՘am6-1qYj00 .2h b'{x-ڂN 37dðB Ra mL JA0`&c軯{};;\"q4 (v~rZBT[L52FfBPp/yq+4K;t6m.Kh:Lƨ$[jtE}z+"4U OL2BDʗҥ)AX!!ETw0- Y)5T{TO1IԈ_#zFb*Y &` s{]"N‘;r5OMϑ[yhn*Gn{1F= KAͫg6\JaL9>:MQ? ϸ3e0K2oLAt$>cDH֣$ d.$[JdL9f'cutPވ!<*V [aX2,0d|62lU(11p ðZ ê茡CM 1#°eX` $ sldتPb cZ(U;c32:j((E?j(d1"$+F5 Ɋ6 %F2d%#c\_De~_~3l1Fa2W~_Pb cV(aVh_;H싾ٯ}-ƈ0LD*t;_JaL9d,fRsF)~y~?'bh_<] %F2dL/>옗Yݡ(\pmY jvxtՇz=~z:WfZg_!DfJ@(%q9{S]߲_.b2<  қ HVOHy"tC#]C+ꬄ~H0GG^`o4K!Nr2yn݇Hej'x\M r?ZXPT~/S}{M|5t$pɚr?Ig'Ioiաղ۶EY2h-)QNv"hs6DYFmR-י)ڍ-Q3yιYw>'?E>a'.g"~8)?7;r9[hTE.9|7sd)" ЫqfV5~˅,̴!4yv=I 8pQEIrN_Y({^wҋE3zQ.YݑXe|W(RԬ&d.'sI'F&lp XهPPE^]N"b%[:E udeZj $'˼=QE~uåibIS)㶡1^s:4/:G\zf)H$I0mzE1pB%thv3Pfsq5yXX2zBϡ .f6e Gy'q'߇Xn{vgTt.^LF<*=}oF,3mLtUsYxcx0dVWU;}qHul=:>L"- vDEZ_Q u|ZS\K=N5?Qc)~?5$)zAJeSQgmm#{G.S ?ئmNJ_UHe V [ T"\ +$izf^ v) 96ނ; $W+tDnNdڱ'BYi𾺝ۙ]ОGfŲwZGza_KtWu\>Q%Z6]+\@w$6}{QCE~hu9< QV<adahwm9Յw5r̈́q| OWԍ͐40iweNgQ.eR7SPxQ̾M7 {Y]>ZT毫GIj=-L#!N'J2׾ŕ%f.$G?{yH_,F$C\1zbXR ZkmlXvLew>_w 0:! endstream endobj 83 0 obj <>stream h, 0 _%G4mUFa;9)Z Q)ݔDHH*_C;%Vk.a~Cp Ά>4#XPE,װsV1kͩmCv1Fv,[c 0 endstream endobj 84 0 obj <>/Font<>>>/Rotate 0/StructParents 117/Tabs/S/Type/Page>> endobj 85 0 obj <>stream HW[oF~ׯ`_Dq.!mucUZA ٖSwcu6{‹8s$^gxw.nOnvyJV)9=ar!d4nnKdTq߯ܓl{N$DQIxAT6 lvHgn;-)d0LSx %,&NR2 {`l~fƓ,$d0?31&,KҜ( @HrU75qZPbd4pt:wE Dsd82~.'2"Q)͆1]^0pHI ,R$7&VELE7DE7*ɢw'4;&{g^% 8-/%{pR)˟Xm(e T 6@kÑA%O R -0"'& "P O+M8YKS V\ɾ䉈v1SF9y1gs}ҜL^?g ᙪ~=;sck0##rk4E8` B@^bŽxդɄhz:)Sg Zf3+ĹYB%R@]KW]]-|@'_ n*#\?gDU4t/=i$,@"Oy\_{6MZ=]R ɴ<)/6OJ>- wMqZIB+*eԦ IhF'zHKT<#$+xgm[<ڼhXGچ@+dͼM=z u>z>{@ڃc=Ac >z* ïVT*om+gHs''͌c{)Q4 Z>JSW4}lCЇB_1}Cb>퍌jb];}KpMrIF/b{bG3VLiº£o1ٹ\lh.\B{MޏߝK0AD?l HRߗ)<XqGHq~AW M[Pu֚)KP ^c?Z0I&"9=IHdv2RoTǭ夙b^wBQɑE3n*=-xN-R 8oő:xsg^9fhgdRWLp8P|Mhclv;re*6mmmט]cWɒXO6 -aVхq|9DN4yO#söOّK-y Eֹȩ y]Ѓ# OyNaƚ{d*p2K3@юhyVi}u;NVE\n:M5},P8f&ض*cJTᮆ+chJpX㸦4[F(="" ^:Bi)Ms4G)m=JM#(ty*R!4K}J;m-a5h.!h23LF|L6&"ldu zEZ8Zg11-gcCmhǷZ47UzfUq󭏙6< v"ۈ|C 3@O=J6McȦX6P#[-%*=3*[ Lludcd;GmDDJ!?Hadlܣdj c+;9΋8[ٸqQpk"ۢdh[ oɉ^=?D/D=g>j KEh0׶>xA>xZ$D+b- ī +5悬Dj%)2z#ю +f8V)OҼ~P%Md p\sd0ac<Y#.^뻽b_'n=Wb(s J ?2 X|{ސ~BfKfq?H|ԚK;E5i ,:{3MyӜd2O ,2>^W6ߴU7WJ&CGxZ4iDnu[LU*m>HLܔ 9L0H\hؤKvSk/dx\l]]{_o`vW.oIC,פ`QGXE!U kƐ@8"m[u֑0 h$ue#cn(o녟5-٫ A&U5ݙXrY(kW8.JZ1 <]#pxRvEW8AI Z ̀BIH W蕡K=?MU$(q^7 L[u5ʔg ݭ}k< gM&`H{1w˖2F Tr@6A"ϫ.jgQòOW*v*~_T1VT&lQeRlv tUyy"?t,z 5zoA{lfrLQ%L kL1] ;h$!q"ONGxTӲyVHP:X{q3Cl2N8g3y%_DE=Uϡ\YLۗ-uy;z0=<Ūp?~F{ߋsUޕj27}39Vzv^5whDhb ~ѫF^^񧵝=!W钊MGbk{5HEx3"ӎmlį^&775mW", ca,<:6mÇƐh{g 4۞F I ,G&WA B2[ETۥTEm(ntT`iR{f G/·\R*xdD~vdڑDIơ9-L]Üfmtmqol>z~ŎI =aU ]UESZ]ýGq8i0i w#9Յ^ϲ+O~Q:5?QmE_etf8ˠI82U(ExOLAEUS7%gk9\ze6 lѠr@֒)-;Puq7 P'NK\;5P3HH*~('> Wo+Eg 7+bHR *̊k%Ԩ\YBc}r endstream endobj 86 0 obj <>stream h,1 0uK^iH Vq4)%R&U#Q q$$٪zM#`G죎iϷa3p`R[c2H@AT\AVJFI,-kHKmͩk7,29 Zc0 endstream endobj 87 0 obj <>/Font<>>>/Rotate 0/StructParents 118/Tabs/S/Type/Page>> endobj 88 0 obj <>stream HWr8}Wv_ȭE\x*V2d&शhKƒbKd~HݧGGz~y/v)Eֿ/bFC6g^g_ޜxFGe}}7xΜH 3Y"+Q*z2}\"eO,ez6)l|3 S %R6 |:nIiR*2Y ^3QȒd%J$RIYTq:4LL IܘTO#ZIk/2E/`L>++OaϬJ_R&By.W!IEELxtE{$Od4=Uq81+XOalA^WT"9+=z` >>_62D\pA\d 姂oWw8Y-__[ɞ?DEExѕϧ.;=.is2} x3c [c11%-rofq As1X\P9n& _)%:eh~3P(8g;U*߲m[ih{.M|N\?G3+' ,͐` WIɮh0ȸ_ \W[X0To0+d<-Tc RpHhE Ds8G̢Bh:qsZ![.Sh,T GM-c鋡Z'|\1.iym|ꓬR>00TaQ:g[0aI+t0AtJ1m1/39i4c7mq ]I@j$b#@1l/v5I]SZX-Zٞeց",(؍p .Xl'4a"sǭfsue.@KΉhw*a+2 O5(FH ?T=6{ :JH. <7E|PU] [`kqKZr F@B _]B/t^˵ײ. 2MH B 9U-wLUcJ0YJ=_\C+sM9 YTT,SA^i.Ũ h`2WzBGvE#9 b[7l !!wu*r^7VH¸CPm2qYi[[}Θ&@1 =pԺnbK6?n 1ݔ91|[iλSt5]b"w&񣌾C6o6YS|`;:b (Qw٘葸fnQk# fv J}i [Ʀh`D0`j$.@83 PZ^\$*_ }Q~W-Gmm~m+-z:-΀V6g@kz+;=$"=ij7 s}!ݚ֝*[l*w&Q,/d'V շ@xSH!vbmxƫ6.G1ǙrncHwFXѿeAgߡL"J2 Vh|-:v< :[U °bkzfNܷޜE% Vbm^ۤ Y"D.u-%vsYxId(KI6H^K2KW%eFs\ydʆy0dZI 9 N>:Gj6_$ftF=3_!컦>а5M҅mYc!i.;Y#qF,wJd}{ YDZ];$j_eHzW)r!g)18r=D m`c]MC@&-*9oHϭ XWxf|'n?[\ٵ!7逪Ӥ*u ]kؐI.XZUUip0 :5|7;}[MgHHdP3@ܪ2gsZgW v(BC h;Cb xeMoC+kzZ\h e U YeerB5Y]ʰ𖇲UV w"ƣcpg|_\[<, ~nL:ZFDbAՒzmx?R6  `-Q )Us{#*QPބlBhGQ`7f4srʆ6Y!rUS,{SS9"KfգcVrl44833 S(r8|5wf`-ZYZ dHAP=eLh#Mh x Gw ڃ; 6z!mG\#do JEm¦7"z t{:E!%Yk%R7BuRD tHb˖'\ }nK4X!}a!SVE)S }tb}DuHXd!$?lf SBd6[^ eO'Ȗ#36 vwAY;'Ti]2\"k&8t/ ֡45.o)OT )sxEG%❳)zxnΛb!40!xU8 RgEk ##?/g>Qd%K8N관ܵJj iVf[f*GTix*Kɏ!3]ukR)h"wSL+l?gͽ8Y d?NhJ}q£$}P6 ,O,KPXq+ŝGCYύ%pGrXxWE6.`:Y-.mUf`^쫷'|#Q=0=a@8\ "VzVq{:N7]&B'eYfٺU ?kă٫IdF%ٯDkqZ N U/Z9SKW?pNe bl{#c}uA }H|"3dV{Aa,Eq-Y>#oȗ"6 tU}?1Y2.Tup8CwLEe;`Rv ALOynJ\$E顋fDҥjQfPcj5/yH35nr1-} 1z״: ;4R#RD.p$MM(%^}M=i(cW84P%*UϨ1wf*2(MhQ+na,ȇ 5g$ijQi> /d`OѾC`ZJЭQvߓT9\oW~{DQ++CnRJ^bh!kQQh销r\k5mJk+$̔erI⣙%O$rޑt~ˎiG*VHHe{f3+%I7y qlse{0 hݤ"JTp8)Ʀ!r{TbR @*Zyw+i9 r)٘/ηmC6'N R'1cڛhQ$lxcfRLc0Tl26/h<Ǹ;}Od2azY,+}Z6 ua{ ͂9e+f])["ގh|:lw&V71[wmKV뙭'V2~-6E-|pږ+Fa-MUf$l Yv( :nxݖz^@h?'Z>?1DTBaȥP\[)v.ӁG,?!D)+jꔥ`N w1D?%'9 r9'7.{zTc0⺁=vQ^/rnw[6RAi+_詁4S?-e'0jw MhE4 QaA+(dž-# &s(D.=֭d)eA=jԽU*I"?o]yLj 5 bDs帤9*Iл*;!@7D#SB;vcJZֽJ~qq fBw~ Pc8QuW2ǯ<TB"2J;& t]#4#d&ҟL 'a3<1̡h}^%fd+|WYSM'^(/:Cm9ZW#ճ͌!|SNff6Etm-rZ5}iLFZw߬UӠklJf'o"$`ɜݵԈzwI9XW6{< 4kGҤStORBjXi]fV;Uf%TFjĶn1)P@u#LeF 6OZYp3|]B\eT^kz   ?|LnE}c9j-, 04pp·k⽝\kecFJJY_5'x` o6J(?.  :~ D߁:Y4=C;S,\dnSĂi<(@sN i$. FV2q61bxp!i52ClF%h!4MV)$\9fJ2V "&fsOye2Ua?&/PgyVR[=z>, @Mz{3@u.uF}a(CbEfD ա)JU(d)`W+.U`P,If5T *`Y̪jUӬRWEUTDavwq9w\؎+[ p7Wd{ g 5⻲RoX$v{ĻXKb Yno905T#LlWE"6D0p@MEOj4?(ly-+6ƮƬ&=P70AYOkUk3*K1{U) 2aI 춄sؓ;=)3 4U#iŢI3:R'Mfj s bj!H9_jžƠ^gG!_(ꊋ{ćI-rco91L.IØ,ԾcۭqaYB`ǓO2#=; s]KY+!)u @Y$85&Y{#\5?iVRſ_. ]G*ZcM-,TsnT{!6hHپ5n+'3zc`?#FP>h6\AǞDɧ~,Tq~Ns~ڋcJx#\pOHAC@KXǎ O 7i4]64#IӬ=P/xh"ϩ_ՙ H}PogԴ!85aAG2 S"=Mh^@NϑcX`e?g nrgq.X?8t @s( $ ̈6vdc5j=_C!8ָ\aڠ.֞C'c>z?3L.߃?mqY/nڢЯ%/#'*K] AHȔxx-\֣|)aeHP[E9lnd`2D8*A|2:dfTX0!P켟 >stream h, 0 _%G4]UFa;9)JZQݔ(D*mI r0^ vi&L~3p`yq{l>Z!KXQJFI,vk\L9aQɴK6<2z Z 0 endstream endobj 90 0 obj <>/Font<>>>/Rotate 0/StructParents 119/Tabs/S/Type/Page>> endobj 91 0 obj <>stream HWrF}WL[E3V*UMZYrl-Rddqvt@&$A9>}A|˗/Zwzrn-N~^>?.' pܼo﷍ۗN>^.f'/7w땸>Ylw ,Dʤе(2QUzZߏ?vrzO"M3;Y,R!v& ,OX|E"^6K\&2W`t>;Lg<Ӥʴum~3WT.$~_\hl[ϯ YVBO^ (C$Le~)c& Xu/iP ^ 2kbP%YA\"zgk}%ݙS:fg7)8zcNl͉XÿƼ, .@ssկ@RaPmX@~T~syؙIWsw2wz,ุ:}~+sYT?J *X?uRh8˥fW tPT_p;o|3EB/6й GQ~`V" >+oiU*fyB㤒DqI@p P @ӕ pijUl524 iц:\- scS\/N%)blʢ[.%TխC @JMVF}mMjVMK~fX6¬%vt`'h3Ba-{[kB /p\}dP՚teb$zI(ajͥ@RIHJӷeO眳|㖜={lAH3UAq,-=]4*@&;Hfw=$\&#캳ǐKQ*n> qe^QʫቯD5|m}u]hkNEv{Nhw1__:K*}Y.y#G C)3o} !%'|X$Vh wX}[LtIl(u@UB)pA,dvjs\ J&m D965HXu 5:.HlV(HHG N腡 H2)_yD`1_f=L)Zf(t/Ƕ̐e b?ʩhsˆcnt*VCمV C 9XW2OYsxfбmL CEg\Lpkt* )zz"hm GRsB~[hY*25< \r)˝xw{Mlf!Ԭ}E!Di'8#جSs4'}<5?yiɬaDCٸѢm 9џ,7z&JCU0cцӌ0kka%_"{G oK /{67Wֳx^RV)'sٜ_9 /3K&K-Ep^(&E @&A&0rZ\{N.+LLZ dήPŐZGX`b#31˵KV"Yzl7(`a XTj2 *9kU$y0Ik Nd%͡s( C#xjWnG W$͇0[0{g 1}wjڸLBM_cXi87G:LΥ ρg&ݾͧ;Bҕq:At[=M],"v7$'.y]WC5ȻOoH*jqGC8MAlRH2+Uq ˁ!$[=wCe ߱pid GۡN_[ Sl`Y0:O8pǡCǚc>FmFM=h3ZQzLq_ e;Tj߫)Mn{G"jpՃSn|gN`69&օ>~~0 Pj!:8$EVy*M)xp4T즇RWRF`;;`f*YLʰsmS50d,}{i%6I<\O*. nM Ob԰iZ;^@:B DH>7cY8|Na0)$ȮaT,٪PaYIޫ>@d5/Y~P4 /#2ҍЉUz7 5v%wuqD! ;mT0|+TkN[vMbYdOɼx5850S`o|S]MX}=TȲrdyw@ TA yf"a0WW_wfCsW]@3/ݮ2]^_ܦ  (a_o[swWsyGOC1{ L&Xx:f7O@U`UR=NJ,/(0.Ԑ4dRcC- &y}u mrMn*YJ MJ98vL𾸂y} ]PZlؾ5 2ZVyh`*uJII+ #i9u/l $\G 8BB>Qz(@ f_\3M#֭Ž#ue_@86 l*Vx?iwCm-% 5v'<ʨJ OoPy*4K)ViN$6ɧ?Pa~Ipf܋T',b6 sպ<ឰh&iՔfhi$=s{3l }WM3-Uk4 p[ On5 Oscke Ԛb2^k2Ffy[T櫠/Q3Qm._O砟FgTP+*EbbT@Ti}?-k"?t'6W{C-p|ݚ߫slN9rw` [Ġڞ2f 8V +p*5$$vijZod莕*2ԔB;!֞*4{l#!e_w3 WaQ@%C(bb꿞eq*dV3ݸY<& ͪDM}d]޷3ʹ>8VfN^p;"5:;!м*9GGWim{4&wWꒊuCb {栵  xڎm,_R9oNkZ0nP csd3p o;/CMgyGi6):=fIZL BF#J7wU[}G I&Cr*tRS5Zԣ؆F%SHGBߧ0fCK3dDf9Lc6 }S&Aݬ Gsషp?)IGD4'PF%G7 /eե5|{~Wyi[#}#DHV8a th4[w# ˮ](\=.OV#9RPljZȑ `4sc͉ endstream endobj 92 0 obj <>stream h, 0 _%G4]UFa;9)FqR|{)!'|?8e !!݂)K4m639fW.M%rbB09bYf}~1笆aJ5g,{?C:Yfn 00 endstream endobj 93 0 obj <>stream H\j >wٜ%PrNReby6l*s)do݀@q;@ڂ.]bqi"w8=8YWȁf8}ކ3aK txg^삠+v!a{Bhk 5YliFe̓T?}YV-ަxBm̒N(}H)&,#o0 endstream endobj 94 0 obj <>stream HԔy\U{y/{/\rt,-PLPTrM]&tf[2R\Ҭ,5Ṯνh3ys޶qn@ UQ|Ϝ4ቀ뺞.#=%wq灨:z|78]ô3W=%;h$stj BB %B۫R&f;;E5{u=*%+/Rm ٣]gMը3B6|(P+zEխ(5`(009UmJgz6UJF Z]oz:{Fب4՞цg?3*&R,41]ɧD_1V⪸&Q[ⶸ#d{ *H!uh4D ZiGģ` C&a2\-f%b2]#(S5DHiehzTzʧtQ)FYB|@D3E)!J6YHJ$BCiMiK3ib,E%VrGCn$;L}docNEtL$"^v=x|V& 1B Чoz9+rx$@1H}sL"MS,ub*Re+ÉpqhH@w^HatW_$6:F2bgȠ$SkuʦV1ZrX ֋#r o/pĪP+`%X k5nNXX7Vhhne?m1va:3Yi;]hg3ݙ\2\ pB]]+ŕiDF:Evm@w-w]z;BQc2c&X󾬌NSW@1ئq*sj ,Xu-l%>PlZ;)UnUذfvn$voػgo,gjzjҼj!QeQUS}ثf|̐F>*m4b= *+G7n5ߒwᚇI!>m%O34- ጫT_ܵκƛYqee6xFK)Yڽ44\zxxozOIV՘q}yo'~:#Q(5 a67[4}^fncEQ$7(nj\hD=јz FShbyQ9 nG\8$M)~OWg/,qr{p; SIąB$'8 Җ{u]{u<_y16p|)61_a3" juA~ h4 M "hD͂Ae* Zmfe{>;;;Ҏ -;cmkc8;x`mM)}7dSmMlh3$e'l;4P@1y*LE(TJR)*MelOa!("PjP)\ZJvA:AXKt.CzJ/-}K?/42P`"Ce 2RFPlh|(>(#c%VI\(3ʖ kI$IItɐLZ(Y-Se )d̓@I,e'RVY'Q6V.;d얽R RM6h-5~0C8D@SZAv:@G tnzAo} I0 fX0tȁ0X 2ȃ|X+`%P`. 6R,0N#(h ,Ih4MhS}O >' >gd?)i2 q4R6 1II4P8Sp%xg܆ v  p 8"\p M]!<!|XyUXQ%T)UVSUUEUS5TMU[UUH5QMUjZRUVWTiUFuTEU;PUTTeU]RTU Wl^ +</k":pGE\/_ ~&#?ȏgY<(~Gد~y'.˻98$8s<>ȉ|0'Nᣜ8s: |3OӜgx,>Ǔ9S"OKY9y^OEէb}F/gR}N/u:__+eR_ѫ5F_k N-]o ޤޢަ Gz~я8tN9BR.-%S-|WUtoʮDijꮶa:NG$tNVkڻ(εq=czHO]r}]Oׇ^s r7 vP7t]w.%BokzM_w }#WUq]=uv]?]KuE\ W̕rE]IWܕ&ZG6F.5qk]3:G]t.UzGq\7;6!7 6eiKЅBj%"9ae ^L&8 8$1ƽ8'UTB~*8Nm^ Ie}wtUki?}nF/G? ;QS{V{Fۧ{=K=q|Ot-scڋ)gɳ6aZOwb"O3MnvVFKvYGVOnMt5ݢ^{_vUS>ǦyVX9`xf{I]f~uêu] 5Ūս>avTZթz]_:f 8Jr8I)$C@G&Id2,'z|DΫG-bY3kaw-)%wrrAf 2Td"%'Itd d9i'V,`KIY^{N)什N;ɺrYȆ*{`g9Gݳ]\sUծ'k\uRT(J>0aO@`'a쇳>t/px~7%6 {={eރ &&e]@c"*7ugg ؉W}hjЂe !I_otZը>W"ZV)Ma ka=l~֠.!7F6fs[Q2[QEMx?bgRʿmf<O`v.x) ia-=c>gq=|s5\qW% 8qdKIh_8/)YVͮH.+e ` b;FEloHEn\>jDrZ^>/Ub`73MvtUnqpTeHH[7 >EUmm鰔GFl_;]⨔o9Q>~?^7ђ>/q 8 ?N0(>?O0Cp^Ý-ȝͱ?߂#V6z~;/Wk-oExSJ/睗ap:. Z޹24/^pAƆx, _s_ܪ9gUVM/e|vZє>/Za$CO8IP.D"9HpX'>2+YlЈkL:'jJGaJK8BEu$c(P-bDz2hEn(k)8Ǫ3(`bZcbƢ@D/p1n=Sv.'ir5j,'#K\.”{yR5LpggkW:IWw (R)2`l!Xvh1mC*K-H͹Kf 0UDW2zʼnTx'{F4j׭( d.XJO&0U -&4)F6@B=Xf!a|JC"+cQK'v—bLrKF)űٳOK{p}M,,e%pQYE`n:%LJA%hF7?pA# B ؿۄ Q|HdslkP덎 pSg.!jGv6Uj\FRE:f4z 5j6EnֲMmFSK)[%c5/*q#a1FS[Z87rA/v7&wWMfw7#4tO'L(^KU FcOh3k2Vsj4)M2{CՒ ):!Rs>2OIKKb]AORd1Wr^W45zt@Me!əKg>s]CO:+:?3pDF9uԠjPomڌq4#`ab0Խ74Rj.B@Vr֩o*3P|˟^goqҥEw4'=hoO!]/8N)&-,DSȣ҅k]tX4FoP+ȷ6U UۍR[8Ї#^L__3Xkk18XkLQ'_yxC?8M_+8^QPc=:QsG_ \Dr\^$ngݪ|GdObB_wCV iVf^ǙQb(Σxƥa6 j#Syu-Ww{4Qj!552V[ZiZme7hWKj,KܭIɼ>/&u$9xOS}0U(`Dx$?@>!RK5vljÈuFEjJ!b=o4Su-CԠUVke<)L^mYD'|f+(OX1y[׈k=Sn:Nt[,TO}Z!/4XgFb6kF4_RV2QI+uQی1NiIA>DZ\!Y EUxk`+M&)G/9Yq=^sGFIOPm@+hx\<[6R2yNj8BMP(J{Jin"ހ0u-UбD[&$Szk3 Ŋ~"Y'Ԩ?}#qoG̀Pa66m |-ah MzKk}oi F/# 3dhtl$9 `bs #%~:qdA> b0Vsž,^ޮs_,Ox$=y vqa8-)\tŊ&D*ԥz; 2%`i6ωۿn9i 1mDDxt 60ec4Az̓bS?6;}mN(f[:IcM_u_E}uҌma'D~E KuB+vU Ƚߣ8¸&ydœ~}u>湛])k9uŲhh.1qX:_cS Q:iIOd3n#ƪZg-~<ɬQu{T\ zRm֨s+~T2jPz3Dsg4h@,Ɯ?XB|tհ9/r":)I3{1qOĴCoR7KUwc|#( Ѯ /Isԏ!"vdBrޫK"N)ˢ\T}h'qދy'Gr:c?G~Vf$7vHr S~(U"#" 59jYw!aNܑ1$[nS)e~_z{|{;XOn 8bbS^澊5l\[5lO>u'yOXBПձ+fqjsE۪SҠ\\Aglm)zAcb[]jh6Uf}C)gaXbJD&ӟBcs!>Vs4_ }457vK\?%6zֳ[ B7fb3IR~2^7UH;09w;??3iRf0mڍ|]M\}qo}ZkwՔ%@dIb@<;r#5qL&5Gc2;mdɅ&oo|y6c8qcɏ&W74nƞmߙ<OZgWkOi$NuK52`3\"\R=S>BzDgc`rr'6H{5!UI#ŝ,_$ӝwcQ2N>1}M;9ٔ.ЈjLpQi]c,ٷ3}d4Z3ЙFcVCed8jX.U^ni(g,2 FJ)FNr^9BYl*|{Àj!?-FPc QD$*4 cXT`-*:ERq*-h!~w_|t*o曳s9{ r21<[!*W 9tXRs_V;9y~EE_J.[8s9rr Y9&x꾟rp~1Eޕ~LOjgɃRH r+{4ʽb)vvK!$wwSc6!|rrN˽;JOI6LA_0 ƋmmG{zEVvtVt`_ -:kG{\lEvCEJɭ[\r^/lc:jdt\㹲QqC!Mg5&Mc;QU"mc?"5E~|UI:;49܏ᚔKw5%ܫ,֙)}}rZC<.Po˄`qրg)o 1_ߣ B|/4^w F̝&{gDz}\GسF7XL>g4NGpDnWC,"α†r1W.2.st&3V| @R0@uN$뼩,K 5NNw(oo;)xK|_e>wI.[d< UWe OAa195oy Y&:oj#qvƤĻOZ r_)wyTK:&TW|jY]wP54E4RTrI^b#>yR<+I@K^>]f߿Bjg0bstŧɹ3RIL?*ӂb /||Ir~_OK T27%g}Qxԥ.?q8לk|92<.ϫ= +4#㧂z %{NՉ}wJ=32Y:o/X-v΍:1 3.v" _U OƠN>>ްƋ Aڗ|9$dY̲i%+X܈\I'mE+##\hF*~f+3>OdILS1GX}abaC̭a9aIݖ-[4Il̵}iُep20gه1k-n&fo~oʢeYĦL$=ߜU7fӌw7<&f&4p=uc'Ys A L<{nyF5aa^@Dfq(gQ nvia^vؽ{<==~x?_.'ߝ 6{[5Y%N9gR[Ũ*R {(RMbTDpU5W[1\Jd2i#BPS# WvꈨzaȵJһB&<\φW) 2|J+*/J{?m;#g;WKk@?Y|_Yym;[ yKrvTsBpjwmSr=eY:8]쯬T5i'fU]&o^E~ڿsSg7_&*ܽ#Q:Gd=ee-e e5ee%ee9ee)e e1RK,TS*J%2⣔S(/RL)x((s)s()(3)i)ɔJ>e%22KOGɡdSS(a!A~>ޔ^ JOJ:%ҝҍҕ҅ҙ҉ґҁҞҎҖ҆Қ⦤RR(ɔ$J"%ҊOiI(NJ J,ADSSQRPS((J8%)*$, 4$8(0 e?ee/e/ʟ?(S~J3'ʏ(S|K5+ʗ/()S>|J1#ʇ(SޣKy6-ʛ7(S^Jy2e'%ʋ(Sʽ{(wSlIr;6ʭ[(7SnHr=:ʵk(WS\Ir92ʥK(S.\Hr>GhڣY{4kfѬ=GhڣY{4kfѬ=GGh4f?Gh4f?Gh4f?Gh4f?GhͶv4ێfl;mGhͶEZI*٤0ZkR `XeR VbX,,-X VQ B<\P *l*&i`>ʁ2$x1*"spn6F@!0LS@L rLXX`IFq&q` Zepn(08>}pYonz鸬s݁n@W th[nKRd HLA+ $L0lјl4b Z# hhZ V@8&0Ҁ> ߢOct 8 qG#a?Ypbt^bwL -?a#F?`=-־WnlπOMiOL˩]ǘx[;[:&_^^^vbKùr ǽ@ vEW6 WMNM- d< >D zO0\.-^b4QƹJ087 FjAq 7Y@&0 jbw=1C0h_@-g}Pk^M=#Go ݀ u:|mqgqK*s@$LlA#hib Z8LF́f@Sl14";#0PgR9]z:$I q;&sG%G$%d䀬>^ɞPWMq{)MiKZubDAE$0"-I[J#M@F *Ke@s@졕 {m}_-LL3i o 8S+SIMŸvܶwsw:?6izvp_ LgJ1[1jW>[ۖU2Nq:ǝ*ٌm&w0jwuIN=nZFMD q1jBRT\/rK yE~\\%&bgnQ椘TL-e~n0z”)F`,3 6/0+gOnE,R9~YI$7eaȹqc 8m/|Qa'Zм|(1xC9b Qx1 Q臾RC(A/DtG7+D܁V܂&hqFxqz\kq UȂ•D.l6ll&l7 k+_ ,R|)>|EX ;x›x :5W2%0s<óYxO)L4LLƓxcDL0J /_ȿ!B /_ȿ!B /!B tB tB tB tB tB tB tB t!B /d_Ⱦ}!B ٿ=|.#[ Kb endstream endobj 95 0 obj <>stream H\j0 ~ Cqv1ȡXpl%3,QC~:?[>27 C 8DžBc u6{Wn7٤:gZk"ΙW8>stream HV{t] KP!!aa.)P5.倅 HenN+Bˡӣh)rhU)&D=3sﻏ~@" 1tjb*KZ7 PK]/=OYJ{Op6kY ?f" KV^U9)@yP0$Hy}[\(m1l- .vlm\V8 m S3dw^, Mvw5#vެ4Ws-k+e-._rQ >Jf:D[h'9BǙZg g'Vb!v*.J+& 9SΖ ] .w=2*[[PJe^٪S(o+Q.Cb5dի^L[-j98>u*FLN7Td8+|"Q\uʟi @ A݂#|.Q4Sho-xQf}rΪKZVR-GPònh駞 w( %h q[ne#~ YH˼>5MoUdѵ#l4Ji,TPO׷M2P +-#c:5B%U;"S5G1.Ȉ:dpA~^ǥ̌~}<лW3grRbBݦ*Rzy@3rOP`a=Ȃ=fZwK7[.a$V|ͫkƹ2]Ҭ*tf܈y%'\6Kʪ#:kI4>No/ d L[:n1?BW t1&S˲" >k aZQD"*zh#e;=IhtJ*͓ _gɥ b~+' r1|9 Qt`9L{3lu2; #ipeHCE\&>*,\x6`^30d>Zapތb⏴\;/hBg ^N_n X+eeVn2,|agw#is9V\;_IBJxvM>wʱ6O) XSq ^P 4h9Dz;o;(ơ8{*Ӏ9VscXWmGmyw,3o |FIƏdhh˜m“KL. _vQn~g@VD)K5Fuڹt?W$K1e򳰒^2הZv^S 3e@|w$j=q-/1 918 %i k_3jGVXtFcЏL!ct/ǽ T KJ|]F6m%oJ3-TLitah'*gu.< eK+wKkG5C@%0>W:YL&&^L$R~>6-Oٕgٳji^I~$gdQO(-JrP,VjSr5WVUUV%UPI3<:Ae+'YdVE`@-O N bj띮4wc)[!#UJ#URJ)&Ц# uYi>^`r8LFۦ-4fq9;@r|9>stream Hj`@  endstream endobj 98 0 obj <>stream hޤYmoE+̾IS(EHШLj]9gxsd"罹gޞ}9碱ƹdP1Ƭ7'Ąo6L:.{IǃHd$l<9G `Ө3fUIWIWI K4d+ yo YppOp^J7Z|۫NqЃq͢1] JfQ XG9F>V= NQp◢IF$ZWI1G@:pT8ְ82;{Rl8 B.Y\"Yo%gĎaꍌKވ .!g>&tY ^e2.2ek$(\&\KQIVoAsB]dhi,+Ɠu q!lQ9`(>gA?`<,ՓL8?&kG!~&9xMȢ5,&Z(""JScL@'HE`MLlG&Y`P(Nvl~She837o5ygqxnG+ 9rx:0>]yZ#@ B+kt|}esO& :w'pzVC?_P[vSgE<(mB@yG FmE?AѴ?6OT4 ٚBUBű l('2> JJ}MVWny0ZJ, @3=,bgaY\Δ-.-EbÊPcKۦJ.yϡNhصHq(h2h9wCU{Eq(j`D?E#lA ](88M%#Q*ֱf,r_,&K,$ձH-/,PPAÅ&1Z-<op}2%SMܵWJmzBR](/S J,&P5f>_laN RQO})Fbv RhwclA0P=PSC1-("&I̙{6[P$9|AMWق"hwjbMM"08˖> βuROC19_P8lfNj2gv}(&Esɱo9(j&>~Fa[',g-aj6-?9B%El\Sss~PdrdvwsJv7[gfׁ7ouu7χ8|B$? z޿tiwT~, q)K_4p%}Lǔ:Ncc)LH(5&LFRfT9OFќ!C?ELFRV}z%+t} @ձh-upV"iԡh.o9=g0([ ~O Bz=-EZy.t"SڜO٧w64BSh7u;4&a@Q[6;se(HipMҤoPm"l1p iRm-fK,&P5}%6zz{6[PLZh2's uQEQ , &L5&ըr;Q9+%˰E2څsh(:O .*];1  c&25 endstream endobj 99 0 obj <>stream hZo8WcE$Eٶ9ݢI{cp峕v7#F{,Qpqf4ZI8S34IRiq%q%W0F*@+ ݋BCQEQ0(0[FP(0ղ- +tQ^ì^E4@u[ZE @. ދb笗mQP]i=gZA4e['}aoQ6p#zߐ _;FXyq^44"F@>;h_1n'Yh}4%iѲEPFn`֡B>2ac_ZPn𑡗؝k Ō}4;b&[u/xRu" e[BM7Âz \oP#-uQ<Wٳb^Ϗߜ|b<=Vl>Kzie>)&=}^~>|.@yz^ ʐ)qIrttAI".[Uݝ?1$.=//ڵӓȀ8 2_2f4DA@ merIM,Tŋ,z6gT;oޏiyG~H1N<|go3jCs(ϐ8SS5vy8.?uRmz2+N{zXQW7:IrԨCuj#]B$ a o5sZKmøŨ9 x/s@q"$#@*Xnw-];S-M jچȋ6>a@tsp0}WiH[]M<٨֋G&D[qq,)%6өYW-& ,o189I|F1cd<10HՉrct(S)Pv*"Vkm]~cF`:ͺՖ%Wa*UsohO.C,BM+Fj$.6^%Vvu*:xj OR/UR,oi1Y E>y1z,bR̮~W:YL?[គRmK:F%t+GIM=ZIoTɫ怜cZe~zEz:fdS:gFGբ)Y$LeH4K oe `T6Ֆݷk~u]<͐/WԝƫUTb:q8=*;Q<xB'Ί[DuOsB)nU#Q%v/ s6'O7mzQA Q- n7?P+Z$1$ "`Bya`8VZuoc|ƋI2KWE,Ӝ]aΦi<˱l=.Sv ׯ䧳ޝ~MVk;y;ܶĮf{uu!&)TRCg. ƅg잲#,Ӿ@lbۅ6G-za{7>Q)C5[KU9.fA1؟>BJ;Ʋ߭>fkJdaW-G|}# ZyI`ktU8֏gMYˇ*y+ˍZYeH).<GXykM(>stream hޔYko6O·&\hM'W(~lO'{wϥeig(s/IELi gh\Z*pW+9~2m q̖/JV3^U2^102.Cx*<Vk' gIOHX,;; K4,%l(ప0 hv OНR@YLJ)h&Lc4 f`ixW<ɲPD0`h$ܣРyiͤ@4)=LjЫC#L ,[DLXv ŽeoU=L':&;Ξ $pg#?G_!`4l.X<hBL[ ZR@ b 1ӊZS,k`(V+X$1@іa .[&ͬ^~=F];m ٍHx-| 1BwjRhZoGZUj>׋C@f}[aobg/v~u[]q,ݙL/CR˳εfQǡ#oq[VcPŤ⪘h77x򆾗C 8[O&LL )b M h(\BQ[u1\(c 8S OW-b5wj^1$bL~L1=Y]L 53UA-ѡ eŪZOA $Pb==GE(֬c2d(ճb WrZsen1nSLZ^<~nT5iuE{%W..{JL7`S'cXXb]]˃j=OT΢$N2VP֥OrL'ֲвib ۺt"ibMM+86pzV倞|4 7ݜcR$;6{gІL ox>amڱ:&NYU#Fngu#iK#'d6h/Щu奭{2ϣysxF߲E[?6JbYrvSNde"KJ"8¶8d> M'F$s۬(~lbNn78{lr1oWS^ie_5 G^Vr5{WsdfdGJ߁Л|}9̜$$6#2+8\G|@ e"pR6e.F'K/}{ϡ.,)@~wr27x%~hyRs/@MxXIe!]t8n};`zDej GNxvi;M=X\Z\ܐZ\xnj"_b);ĖL+$5@ٜ%r<ј"%rԹi(n@PSL]njY.iC=>g#̉-?To5QpX[CQWV&QS5kD݅ԕDJּD}H}&UFcdH3-nVm8~ '}'Y) endstream endobj 101 0 obj <>stream hތWnFy& 8q] q>0H!)k)̙ggVDd xjiH鈧%ݑ<[5d g5\RpuJwX vB@t(§U*2 jDͱt!i#XK-2^0pH$i0c$)`l!Al vlH=)eMM$x0k0T <,eTmY^{a~\u3f,Ŋ> Axp_sA'g7?A`+Ί@MAP<r(BA'(4êi1n%05GxH,-JN@N):{FroFB3G}I>%ؐy..EWeAclF2"9?'tX{$zug˰z*u) IguUW,:i 29*wsDӻo\Q=ӻf~EʛjՕjͻP3d;:k'8mz47 N~ i/6" sN&ڊQNZPmr9hr.w$-XS.GSk;G9r͐nRF͔ѭW`U]Wbe-5J_m?R.{ntzMI7ܸ،¦e]?67 lH-(ǯOS۬f_7 m@Yu,)Ԩ썰M񘟝Ei}6c?V=AѯlƷZ2!W^:Q_Mz֌Cf$e`rUb* ySZ\ڴnq2pP䧲X ]&f,b@ї&&Q أ6Sʵf_{{}]m=sW]1zJVu8XrbUq;6Iu˥ӆ=,Fg:مlT[k6EtY߯[ZU@=f`iJ O͠z7C| ?_!O րw2]e,̀iXo˥"SH0(B("sY?CPzV4s*lV^OӔ?>&߸fWPH endstream endobj 102 0 obj <>stream hܛMo$ǑJ,e쮵`f|"xFDkD( ͬ'Yfw XF般|#20)8ͪKY++1JɢY%fGM[&?R KSPhDY#kDœ20SHyvSȍN%*\ũܘTJ$TubiRŻiWB"ɦ9*Y~[IjTT^4ڪS}$\IO*aiRtuIRbjkUGU)FUV겦j/Uuwh9::[sdNJY[/ШjcoOSr3.4*5k\뗂kT[t, MG7#5ɡȾ5h:ڢRMǬ6tͨkQmTƬQmժ%F6VuȬFLy,ꊘ{t45=MM2tj唚Ҭ2_4_4s{fε_̍j~Y|S3T{Ue ]7ڽ}xs}׿bDF캜bdU$ޫٲbINux[#zz=z~gz$$-H;dCrDWc+։;b#掘;b8-F0nĸF1nĸFl1eĔ D~NXa'>gT̘`8#oFb- `@ t^9ρw{X"!»=Gfu<cj4$K[Kϟ(43eKTt?ק=Б޽0p%xƺ}pF?r[?70v=&aj{_x7KNjI2m>3"D<հ.!/H "QAuS0IHw8-ck8?Gt8Í~u8tD#V886w8=) qrXtXaAtXaA(bAtXu ]T s\`.0{7:2L7\̰fY&fISfra0G#3Ms9La0{=l0S)g f`v0;7AݶJxC 3P7s9Üa0g3X` ,X`wX`A_+3yF!F3a([4FDقVx. Z5 4p0,0 o(x=EFQ%X0cأGy{jĕQKG@@0m$q[I\@o*d #`(cތy3M%`v0Ao* EFE-؎@\"-z"џ-:Eϵ:RǴ=׿^B-(@aDxpcD/Ѹ2/6̸:3ӌ7Fθ3F\4 \ph-mR2}_St \F0T1 U 4F@+L_" Th$@ANrR $@(BQW, HFD '@2XD9xFqt~o|E)EXE4VB|E)Qt4 |E+MݓR\ XE*Sw |E+MTt XE*Ut TE( 6- ^"D EPt LD ͌Q@!h PH%\!@yDD00Ǽ&<D$@2D$ɿ&hP-k4Nlj:xD#O4 D$P4&Dі(ZE3hx-MR4NJvjU5ev3Ѽ)7F-%TFJy 5k0a^üFkDFkDFk$g#9ə60&D;;h[M7&:Dv O=':DmTwaWKt/1\^/[\Bp~8'pp(=J N5(4Sy,"8unN/g(dSj9uNHJb\~w{NaJO0Jw}'=,"O=?#vmK4οYz3M姿`ѾԿ?DGtкDO7(u=΢V#z@h\S ,6'z^nּշ/^rg0ݸz0ΥrMܯwv/]a=aģh\Gt[.$;sGr瓳qNξ{NGr:9>gO>:9Y͆G}WХ endstream endobj 103 0 obj <>stream h|7_'A0)ޛf ipc15=hõ`m`o ߒ! RTI PK_ [$}{X5'|+|oAȺF<ǚ^5{,6a V3yl/ K bN83L_`ׄVA ca (L3% vXΠ*+Au3gP3*cuFeG`TvTr F0TfT3'p(IFO  E1cKaC9@ m̒=TT졢f!q" *2d6h z6'3a D,6A娌m9FWlC "!\& 89 .8N!oѤU1!@ * >@ߟ| **+(@eÁ|l_}p{N=>ek^.\HtŗK:]MOWzjӕWW'fۉymyk=v=}_/W.\ֺr51L[F}9QC\WډwWQ-oFW_*Y߷gQ\۸a^<=XvL~52vŬL|?je}ΤżLǪ,ws&.fn2GL,*ei3x5t0.gƥ0. o=f(q93.qiyQx\U¸¸4̸Ƶa\3(q=3.qmW vf 0n/=n~0ngƹ0n ~3y0ngƹ0n ~3w=\3\qz:\3\zE*Ǚq*2^K endstream endobj 104 0 obj <>stream hޔOdſ"̭?x!Y/ބ|eJyحeTTut^ߞ9]m4kG-eF_?gzmJ.jٚi՛u7h|/KkֽxysJZGӤ{gŨ}3Zz=[ZuίQV1 k"ҫ*z7z?!:M\յz6[TVMFm"RdUE{&Ccm!Ey%.݅9ąD/i~7(Y݆ZM[W^\rIdGcgS%*gS[}Ye^Xe5ʰ˽Vd/snK\>Cc.q,q(q!t )QN4kEN/qٮu.[QEݔYaLz%3׌Luz_}ub[ o}*zvxVq[\7mM"F]XQui:ģȹ5q^-m-UguJ7tn!U֜ae_ǝ6?oO}R[[MGJ2Luҷm|&pgbۄϤXΔ~8)m3g68)c[Δz~3wI9:i~e~݅?} em9W?7>wgд/sB]/;v}s티af_g~.>v]QEH󬖝}պ㬶]=jH#D>H#D>H#D>H#D>H#D>H#D>H#D>H#D>H#D>H#D>H#D> BX( c,:b$ B,$ B,$ B$+J$+J$Fl$Fl$F$;N$;N$w;ɝNr'I$w;ɃA yRnyj©.N_?!= endstream endobj 105 0 obj <>stream h|VK$7 olL rk4+(%U1G#Fc>k,uqan\a+ָ:y'~UshHߧl=#G=\zj܇;XJ:0AX{u޷pk0p4x4x4x x`09opN`R ~~7'_ ;`Cvm#74C# 740wﮁw  fo0v70ws9`}`07~ `qf㖽V:.kǰJO\A>N`>4|:it?0`N`N`N4 N0W̅?~|՝[_~O]Ӹg>qԑZGRGjAuuBUrfs͙uvtvtՌU;jFuuֱck:ֱck:ֱci:1cJ=>q=?_X/z/K{/z/+::\8Zǡu8ZQM߲0~_~i_E~_~i_I~yCqRGGGViw-RK~j'I~~j'j~rɹz'~깟~j'I~~j'I_̜ꋙ٦C?~p%wH+G2[llZjΪwp, @] @jôM[Ա endstream endobj 106 0 obj <>stream h|WKn1 oƢiwEqXP15ʞޞg4?h,u;j}u7{rgv`7;e g} gYg~բp88mmFE[n]vv՟BE=͊^dyFHVhTq3;Hѓ+' zrD'G zr^Qr(9Hy3cV~U%Ǫ KU2,9v⼢FFufՙm5ufW]&uZ˨N45gT!9n H%ǭ ǹd%Ǫxr:'ǮVvk bD^[ykW43+P *c$WH^#9f$GʑQ*GrR9cʑbVLY39Ve8woަ>jW;$ן?q.qy߸GKH\'.[Gq Nꈵ:*ޏmiIhܻj1ut6tu #chAuuZSk:@:@::L00Si:vO~hNG:| i:Roo ٴw}]{}wzߵw}]{}wzߵw}]yL[U#i6#]!ۣ=a=댭`?`?`?]KuQpYzt?t?t?t?t?B|'k6'몁UX5]5~~~YzgYg,`z0zߴ7}MY,`L&gM{}7zߴ7}M{}ӳq0= gӳqO endstream endobj 107 0 obj <>stream hބ7_% H!Hvd8pެvRUiVTZ6+? qG1 Y@v*EܥHqQE[^lG0Z<̃ypiaRZQXˌ#Sʠ(z( PyTdu TA`htEaA`W:8Җ F╴e0:EF'31 b0Fp!Q1`C~k0/8A¨!*9b!*PK0 ^) C`h05?Â`X0 xMR` h00Z0LGF} 1 cVR;9> G@j)rwe2QVDVGG|2 nð>?>> 0\XX ?A||{ӧԇUY> 7i*_vsAysھ4=9ؾ޾|ZR'#琝CsHCvsy98;9x<砝sP_ZsVT)SߪHUU>ՖztO*zϪSL{VH{VjK{VORU=7%UfunSӬ͡O:7Z>T}չ9$6:ͩVݠ5?~?]|ٿln{,OOF[%wN6/Y6NwN7'kVX 0y endstream endobj 108 0 obj <>stream h|=$7 .O"Ȏl}GU(1p@cV>]M,Z#"\3Hj=(j'7^SOiXͣ>stream hތV˪\9 /3m=U%UbV/dw9l6]RBMRN&Q lWSD*v(U霸ZV$JtvIjI= SnjʃR˂oq* niXP7P-3d * ;AaYVheX%kuTʰR3L6CfFA)02P jp8mfp 0dX(5VF `j8qPOTV[f&I=9sfif0'?"+N82!+ҭ%Ylf GCQq8G[h\q8ǘ !ևE Ŧ晁ČMFY̌S3U~kS1l-fTa9ѽq`2 -4*x zCWF3 pT>80Z^67=h۷S{|ߟo>|ۗ?/{~L}<^޽4G W_KOu/Я=cy]&ċ|p ruO~egXquxqW1zތefU\2|]+%;.)vYF]rV>J7F7ge[r6gXF<*+>D.h(k,sG'+ze0;KQYF(ꕝ#Q6s#`/Tgts@(ktvyP9? w@9/(&>;8r\Q6r9@6&9;$r\3@ZwP$rަ~%ZZ `sm+G7Pk4 `smk`o W\ ͵]K;K,f]Akj{T j\uG=@~ktkysi7`m 0 endstream endobj 110 0 obj <>stream hތVM%5 +9_I՞@B 'āq%;-ܱ8̌ؕr\׸Kq"V( ?g!F- * R5p*"m`5B0Y1g+֤WW'ژZ-^.e ژLK|ETﳪ">JT/Yו%T'"?6gneB~ ~( % PWKt!sFxNtMp@s~)/ mn_oO5OQW#Z+MةbiV-wtK+Υ2cxߨ-Pg29l\5{6\v&jM:7$v6[(LLi5?tIZgL\:bu漩I05z;58/5: P:$;KX;5͇fV\YՙRFk%9rķsZf: #VgM{l&i,otmߨi wcgq)SAYO Bw |S3RlkMdN g88gMM=Is48 i%i;s\+=lZ$ r^AG\жL " ֶr=;4s^hk[{=;4s]hkZ;;4sM4E`L`gPte7<:'iW. endstream endobj 111 0 obj <>stream hތW7 I<I0\%@;U"!3•FoHqfɑޘ6[ocWYB`!3`F<Fq_1{JF+YA@Mk5I&{o:B3*;5d,>!0գk[ݭ-oVs .{s'}WH#DJǃz;|$@ѓ{Qaa4oQ,#4pTt5(1!a^;j(X,Y ,(8FLDڨGQ!ҨL %FlxGtX *3D  fg04)8e#M2!C)*c `zPf0W.sQ>MEmUSx.{^I˴]!\χ-U^Wbnbyp_[ٯ/| On+F95y:ͩz «WשplflC؊d2;\妕Ož@xL;M*aG4:>j庌"[]TuOz3]Z=44I7=}TѠejny3;<~dnZ^Wu>u3˃.G{>~|?9Q{k=|?_Z}?y|pOOG~}/{yJQ^N.|}Te{zuR}{K|}J}/zݾ_>:uY}'p} endstream endobj 112 0 obj <>stream hތ%5_!hKZm%BD!jfT"93sޡSZoC6imFOpކ/7]BpcvK;RXk6p۫f=h)يmrqAڦ8:lkEC› ~S1eHP T I*"Ƙ GTdKTX"<$ڈۡTPMe#TߦD133(<{t&xxf&\|zO4;;TfƔiP*T-3TfA*m#A.C23C©! #F,PfMSpatd&7CScZ*x4V*xxJ S)ʪ51:C+SlC\)јsО92x$_Y+T࡙ Fɕ#ְ-Lx̜ \MxL<>'׿O_>S;xk\vl[ˏwuɶN"ur-Zc_.N@tj.?˙r*}^W)׽_gkz=QǾʫ8~W%)\ΫW޶婈w6ר)mrN3>9~wk} Y`k\~uq?!d5מ{Һ=C.WIӞ{=3:>"mT=TtsOJ{s?*toy={:q7!5,u{7j܏={{8ʽ{9q/p>stream hތW$5 ^b;v,= q7Ho_7Zw".3㴫bW=CMZoCm6fmmI DžވFܘHyRYd&&+j#6F7 FSN@-rp3.`6GBV$L X0hbcH4BEh$BMH3R'BU 2"_ID 9OOD6IDX(28ŒΉԣF֨fL@Q21;R3D1PAdوS3@<~# gfpHjFiD3zmM(&GA[$F"p, 4RsDpj0oxN*[2\i$r104NC ,+Gx+ǔD@GP# K_8| ˯廟~O߿/_2cγ=;jHe-p]=wUS.rY#6*0=Tu^t>^UWjt1Ϫ>Vuiu,>TuUg;uœ坙t>T몾w;}OEWJ2kOVWj?K*R95S5sd=}2gq]}#]3GꌎWmʩw']WEt}ꩠt9|^.?Di}긏VO{~TraF8DeQ}'k}l?o?{}^D.㼺zn}glU矿.+ciATWCanOGyޛo]ޙ>u(u8?m}TdQAA~6QUI5_! endstream endobj 114 0 obj <>stream h|UK7 xO"ëd 0bYy/MufS`d{Aw@ $ : 2ʃ4 kDeCf!6ǚQ`,ci &Cg5+,h 4 @4BK'G;WDX'!TC$Z" E4 Њb5D0'rމ89$kK ysmN?gIQCSs9yQ*1u$QW=!cB%AT&Hǀ$gsD?o1J4Q9$Fceubαcα)s쟷Ρ9r!j\òh9sqΜy+e;J^ g.6|\xT^0R'̗sP)s985q|9dI|9J.V|;ʙ{ v)>|z=sy*З~QۗwӿW-[k6ٹޘw\mTve^ת /f(Rj)j֬G+ӡTOh VCfzo|1keGe&Ö4GӋy?}며6uŕƼ(SW^=ʃ.UW{}}\o(ce}PI{(ǵ1l8}v%Li=T]}=Iu=޾R={<.߃=>J{|u+Q{}t=]sѱ:N^;b={{(SWg|xѼ(Sl>Q;Zb=Α۫;ZBTO;gݾbh{9~ݾы|k=T߯7=T߯!)s endstream endobj 115 0 obj <>stream hތV=$E +B޴-. N!T{wgy"7jsH;ZCǧ5@|)^5D+gF#P pc&o0fSfьf8dFpmV6G[497#TA{_-NB(Il @(=²PG2UCxU^)b!UCbxX@(e1Bɰ@hTVeGkRVQ_Ќn1yZhuY$k:+PhFG pQq|R @5pXhƱf pc 34C.Mi84Š\2c =f 4S\(4kL1s9fr昹%fn9 hYc㊱8,p Ç_h}jˬ }~Ǐ_~#?.?6ydz&Ϝer,QFG&%Q%y<^Ԛ2L}.$IF(.QG-qۘ8̎5b{5ML~Ժn;]r2Sb̻ZWG5LgO-#ztǤy=t=^iեuTg%7s\?/yZf.cKNuun9t͓nt:jk;̚uQ}Oų:*T^i{|7J=վ{/S\G%kK=|ϗQG%kK=|/o:*Ry{9}?oh{}󽞾7^rԾ{^Oϛ}\G9^ks|;QG9^ks|oFlyծh:JVX{ζ]͎QG) {Oٶ8wμѣQʷb;m7qoɌ> endstream endobj 116 0 obj <>stream hޔV=\7 +*"8S`J #v*#E*weܽq%aw3"Gz5I~{G#%Xf @:Dh5(8%MgLj4k=5|F%mX Mk l[P@HHQ_@Ey#Ҭ,z 8.Ar#p3pJ$D0n38@#x3U5308GeY"-(J(ꉰ,oH#z2=)zA)=FEC<8ZTѾD(`Haɞ9$B AQY1RcD(51YlX)+gaTXlj_( %fBX-M;˭0DTvpH ͙f9sPf!\,gxyc!HF|c̑"߽{{6%3?_?Gm# =k6lf2ᱍ2Uk8W滆otM9E N-Ӭt5/D8DGe=l;Z|1k!ji=V]/f=U/9_ouC~}Okt=o;oMy+RlY]VZ}=;?۝|[ӯT]#ipYM>GU=6XDäViD^]c..vŗ}U]LraUH뚣[{eS>qRw9{/uoW]B-/Ku6z/5DRw^Wu5DG {]2N^Ke+tH}h}z=|6:Dm{ד'g!Z}o{s|mN6.CTOR}O~|oOA(UߏO' 7* endstream endobj 117 0 obj <>stream hޔA\7 <˒lBV-ZJHU"M_V֝3Чh+铭#;7/iq;W1Fb7#Amx!1'6hXM,5e:b7IjsZ{V,cK[p,{6[jk{܉۠]EgÕؕr%oԕEl#r+|L"5dBꭢC!Q/iސ/ sGX^cYdx f5,yIde:<e:ޑ#/DopK1 cq.55tI50b\=2K5LN)iqiĶ!>G, +تwՌ>\>dxи+Kx 'ʑ5:z|z|]y op/Ţ,]~"h*j4t#\1W5yu{^ӧ߾oI~Ϸ~?>1:NetPYWG-qdF^%ʜe\K*yuMe;Z;e!Zs/Q:ӻ[^W{< \]y&o{wcu=|=S4C?Y鶪(?|*P'md>stream hބKn9 @XG f]_c(u?$ McQ*Zo2lC Vn'/9njgmf,l!,msaɻ-gqqG~6ջggm ?뷴!r fOŶs0yojYz+"{r8Q3ϸҳ> O@u2#v+2VԹeTr\6grvn+nE.c˭޷"?~&v-۞ 󧩜EϭVxFwrMN.卼ѝ\Ǻk;f'T\5E%n7wFtet'hwrNV KNnl-{;yLnE;e[wlNn{N2\ݎȷ›3{hefcfw2/GfvzdsX~>/|v==21{}K`5_yߏ/#{12XA0Fl`cX0# F l~f8 0 a0 0PZ0C ƀ1` (Fat ]0Faaac < < < <(< < < < <(< < < < <^kFџk a.]` ]vEX0v!Bص Ƅ a®Y0.]`#k܅e 00wa҂!0.]R0 ]va B؅?3~3&N;wSka܉e׌c܉s c܉s 00wba0v"DiCa D؉S @؉aa'N`t;v" o###^xxxxxꅧ^x> _~0V0::º .c@XGXGX@XGXGX o!!!0֢`,kkk`Lkkk`Zkkk/af kkk`tkkkPUU]0**jaaau aaau ` ""ZPZ0TTTT OOOOOTTTTT O;6`;Yx@`LJ@/~_/Cpq{);{Nsž{NxPQPxw!Ż a Vط¾b ;qR8N ?x!}a {_R}^8 GR9ퟧ`\h endstream endobj 119 0 obj <>stream h|W7 |Ia(H WI 0Rg. q۽1ƘT-gdMV0@L bBYc]0t:+LYyfʻ7۬`=;+C/V}2Ac6jXy6qՃh+m y ' Ѥ=2<+cuTd!ih : H5Q9 Gd$0Ô=Џ(Y|1#*48Td@IOuǜkPXt0cUh$&Ryv1 55y`y0 o i.~na/`yX6xe@\ ȟ_g G {[ހx6Da@ހ( y2`^ :W {I endstream endobj 120 0 obj <>stream hޔVM%5 +9M$V{ VrB89_:7! " EшG> 'c#rAB $!Ԑ PJdNW42 0sUd U5k$^W ioCZa k iCZ9j6>n%=2fD#7.-ps\!1VEj,bkGj(.Վ {­OPT UJG.*R_NDt" sdjHF%TCdj*C ]ǭ0@]LRzU| U562޽{qo|pÏ/>`7?ouY?7?|eqg̦;{fv:z)YVZlu75 $ 8 FfW'4h5l5yva@ހ}7` wFހ}7` ؅Vz뫄g [ k w€ٕdѪYVZiH3n̾@3w .qe|3MIϨ7qr>BcʸI q2o޸[iNOy5xYV3wx=y#U#3rg3t;+;_dYV3$) >`yYn by{Fkxa+`w,o €Z7@++v 5lly0 o мv7@`ɀg4w `;, endstream endobj 121 0 obj <>stream hޔWT1 P?K $$B<*DAu;a d /s /C1>׀##3;,!E@yЖd0$Y` $!dؐ$U ]Aǯ,3VZQ3:6E^I00daF)0c2ѣD& HD$+"o jfxWhZDQfkpT$Y׈zѨ \CVfΨʅ@93\C-X*tܶk=0|p Q2)3\h@f AV^\;!̪" 3\ "O# UQhTEv gUv}Ѭ}`_Ԣ*eaf$9 q ˪$j\N~` "1z"Zd+QzsTG߹Feb0PP'kj+(~ieB;o1^.ї/]s;ǧn^/_||Ë)^ ËƖ3+ll<̟&h푿Zxam`0+l[e ]gxUvc@4Ajzxam``gN5 ƀ:P':.==zXq۳Uڕ}6VewT{ûWkSrܶTvcWvcUvcVvgGh={x60 ƀ:x6gNvP{DûWk i6Rٍu1N5 3`u1N :|6G3߳W\uxRҾ,O\7 =9 4*lWv5:kZ^ UoFV5V̮W>O̮FFw+o , endstream endobj 122 0 obj <>stream h|Wώ5 |6Ė * 7߶/YK3^3o[9 icGc0Гj8@C  =d4 I>KQؐdrBϡI54UgZNp!˰2\Q0 ng}@9 X3ܨbG4 ):! WvTlQVgtae I0#Յta<!'TaPaRZ';0P1d KU3roRYt`Kژ8 UBX.T<d*B Ɯ8CU/yW#UqOC88faDUpxvfxgsS X JAD 1JCAP*<\z6)ĩ ?3dgf*Ōx0#WPvtRgsH#~yR:oaG_7z4Yo~?X$`{ƞ-WzemMw}e%h#|:ؼOEnJe7pe7Pe7n OKrG-o淰i` ƀ 5~7@jnxgz1k> ,%TvcWvcUvc΀b;ڳi`) 0+n{e `|*3^ h> 5nƀPjvgla> 5P@w&PM f#-ç&PM7pc@M7pgk_ܑaT 5r7`݀] wvMtљ-ç"?4P5Pb@gUm? endstream endobj 123 0 obj <>stream hޔX=$4 +)@C:]BTKe9_f{8 7Ӛ6ؿg߫l7ve0A] 7a'/i2bDO h}5Y6zpv:`1%F#Ljeb[[h|捔'ܫㅜ;=9v5-i K-u<Jք%e-PrB bXx &!m !8ᅀ1yVHvԳbX#+@#+ЏYyp䥞h 8;0]f `r @ͳg|LuȳR*<^ˁXzcX1|dT[b>;ݤG.(b*9*^c b Mɧ& 5ay Df̌1c u#1h" 񺠈2bD@ ws{V ͉kyV1vx`B޽{io?}pحn~|/Y|~N"gvlig+Ξ7;!/\9Fϡ:GC\sP>Fs>BYbg]̬k|r| 9o?{F-^KT«5/dׅؗ}Ǖ-Ymwvwv-WvVAsjp5 XҶ.XfhfHfpfW$׈{ ӮU:Ie̾ ;l-JٕF5^¼kxUp  wB\ o\#%,WBr ߽Be ^~/qkCNς Y#W^0aԻ.rޮZݐO7%l5Bzfamٹ6|yӘ^|-5\Tý.|7uwWv>]|W>D0 endstream endobj 124 0 obj <>stream hޔV1 P QBG(swYab-ͮ581 2㿎M``>jgidA#X,<H2EֱPlL=[7 b$e5Tò-.(c۰=6z6  zt4#(j)>+CcQ E3çBX~G2\cEM[>s p!k(yY=e-٬kkϼ55]SB84ܸ"#Ƌ;j&?2pȏZ,D3p1>[ThTjffU!z$7:ٕ{&*%b4!2\DU>&-2د*dU+YGWy*o@=2C\*qsq ɪA+5D*q ٠kh }QHL]<˻wcX~ի{{zx&{go>y͒c͕gl9^Gv uF{zx&(Xc+lZes3n (- =<;8~nn>uvc@݀P7`7 ؝ȀUGó;~ldVؕ}6Vрo߯9P~y{>$>ąGy ?Pl&`eͬ^Ug+Bw}Aóv5bX3̦ʖ3^#;IuFz{zx6՛DGg. ⣳Z_| uFL== =<XZ7`5 XuVc@݀  ]g$ón7 R7H> u3@`uFJ== =<X u1nӀ ߱, endstream endobj 125 0 obj <>stream hތW=\7 +*"X~Õ ab Rr_kqo^2`^sƧs  \A~Fy xp 3.'YE$s`* r+&.0dc [c!l8-/\G@ xR @= 1>:>r%e)2< ";"!^c(ٯyԓ5t*cdXk56*;3|Rh<TE' *4`/A Wza4 S{T~C$T͐=P5B!^CSq:kRU~2d52&>f;TMӯ**7O cdjGxS(`/9 U~UX2ƒӹz^CcLHjw_/g0x|>>^>|HvninvoeF*{_*{ٻ^`OhqScCO-sVvcTvcWvc@݀,3ou1n v7@`d!0004 k۳;3"aaah`)?mCe `+n 'Έn P7Pc@ 'Hn7 ݴ]٫Rwnw'hrScC T7@Hc@i  ÀeuF=L== \7`6 wnu0o53*o\>|mIo7张>stream h|U=7 ʸ+ XJ*"ʝ_z(9b\Pq45kXS4bb62b5b'nȈB27>stream hޔWn\7 -E=C/ P\h$]pS#&43vH1-G<ԽEC K oo bF Ԍ&5&V  \% D 0 .!jF i[HHr4phK.FFi(B4Z5wp hZ 140AbbRX# aX#'ƆdD+ Ej(B U Pp>o@rgEGj6V%YFƊQE@/XaFjΊss.r_7Xbr5Ƭ} s|(Ģ+ 39%D5HP#%9d;3Y>lGYfE"݋$%E=5jpm-=kt#YD!IDCnX<`W^͒rXz5K*!v&ͦ}hkY(汆y!U=kQZ_C*փ++l؇H}a}e^ܽv׷>? @n>Jn^h0vrs8yBD=b]e浛n'k!yBsyT;4hXW(;y`Wy(j"s51$&gb- l^`zr8~.ݺv<+:v i[㩊];TODzoi{~ݿ1)u-GS(8T?×ϻw}aw+^~$ u6msljmBҴs/EoKu:ZG-SU7eK'E6 )-c(y xKR~xIwϫt`Rb endstream endobj 128 0 obj <>stream hޔXˎ5/aƮR)EIXEH{3{қ{vz*T,Ġ8>C%$ 5-H JUMAj_ݺjPx`_`PR(Q!G-d'ŐHMB7 UZMhސr9ncZH)֠#$WJ USRH\Z(9$&1dҽ g%RB ([bD/H% ȸ(f܄1nBj1jѴ[ F+}a\D>#)3 LAb[ }ɠXH1Pt 1סKF[P.sAj#3#q12YEMN(b!FT?eLZ5#QQYU SK+E;qNW0(GBrsZ?h7}8ޝ91Fcdȅ8#,ٹ%fƸܑї ZlhERhaxWVqg5՟;Wy1~W1 8%~Vt4 [jڻ^]iEVzX Yx7rsmѶ+Z輢u.+躢OzVtޢ%.h?A_aR0)+L2'LZۣ˕"ʣѕG+{tZu EJ+_wA~u]I= 2meRiʤIo;-Jϫoh4W̾72kW\+Kvɵ_mx?\^xh?4oe똜c(a!mz|t49q>,l۳lƩZպoxX9Sz5D,Q?_l8E7>ܑ[z>W}eqMo>'ܚOT -'>3ϑH=e_xΞjk~R>q.m|Gnr#u?W}eġqfyTف<'8<|NxxyxYy1IV=T\]-tː*__/  a'˝ָ N[`قmn`Ig/ endstream endobj 129 0 obj <>stream hޔXMo7 +:z%CZFȡn|Ij4\z3YʅC _C%$ 5WZٮS.986 ,A5;iA-h50 P[5U 8` M!h :6ǷbDΈRHEFD8pn1gWCWC+*8T"CU$p c#G%ZKGl8ZՐcΐ?]?9FrFlP+ggCl"BU(!3>"l8ő YLP0xVSl*XgF{8 a28kh8cDwh71_C,^Q$+=a`f2b:۪o*FN58CFYG#:6RǍm*[– G58T'Bp2rLZaM8MMn~Jё UqC_+:@ؒF0ͻ]_?{Kr|a^od>~ϗ?9]?<~|2c:y}H/!KWơNZk/ALھQ:8tȬ,u 8oz8BkhQ7b:}?t}x~4:F~#nH~Ӳ_;n~ӷCc?=_fg)"MiOv#K endstream endobj 130 0 obj <>stream hޔV]k\G +>;/4IBjLiCI=^ųݧW`5Dn9@CïNQUGC&C܇݇ݻscf}?d=Z`5UGkzb9VC}}QL 4@УqH-ͻbn3УgPȖ12=aFXv3} B3 .bkIq%[cD41 ^j6Ry 'Gatv jwv+ #[ 6'b%zv"XE8[dv8A^d)cEr =1111^)Y)=^?̅< ?y[OZ޸_ |C7_χ?}zzgط6T?=>!} *%З!g`m-:Bp+\g06>[3ǢM3M3sM'dɦYGgf!%f%eYJǏf-%g-%g-%@>;OlNYK޹eYxp=ymt_>stream hޔWMoG +sl_j@75r_R}-Z鉏#g8+Ѫ)'jIٿk"iZ&zb-'F%an(@ҰhR|͒erPiuP Rax 9UvKT:y®7(@hjZl([On@r$@^eM,AüCa4z J{* A(55Ak4jq $]5ȗ\њk`ͩk04C L {fHU'4 e؄bc [lа2zh e&Ш7A)4MFo(MFo >zðra rv E, rq C]Ð|͐  ]̋>"# y5e /[ ${g(a)cr 4"uDࣱ*4<4bùP{zk2޽_~{w7t~w8Ї͛7zyo}=6\3g rx-KRKx KL[(%lY[RoR8olX?~^1O4KGPq%@ RaP tк~cW(L9_UvE8޸zݧ~]?<~&to&{.DH8jyDbr /DD1 QL2Xhh9-SOv ]t| -sZ]V)mG} ]tG} sڦt>o;#-t2,qWqI~&q$n8JPF]n5v!"Ѹ}.DD1<(Fbi_b$Q$p-{l\xN˔vySZ<ʠKuNrci|Wnls4ns7جsڦi\%޴Q2 ߷w en eo6-і'` w׏vQ ~0/Q; endstream endobj 132 0 obj <>stream hޔXˎ7C |A "X'Q|  }wF/a_CZ$Z4HZ3jHMh1?d3(H4p JfHVР2r'--M.dB_Т?ԟhh\ƟT.9,9ƐY V!ajb$BC[P0aA#\,hh| ,hl$h ̃Q]-Y)ffEX;%W#%ƇYY2),5]O*x^J\bX]X [(i TŋXdFh ?F ,GŘF2fKblMG) %z 1[, 0AY nٛWX^XFgN6_A!_FhWШUʅE@ЪEH!#x|G bû { %#G #oޜ~FUO~/?cw;t[O۷-Џ XPSG?SftteWc?;8w32SC<8N3`({PxA$OWfuTvE=5rkoiyNѲGϠ>AN/#D_q*ˎX`] ]v,`>*b`\4kuh†m,rxl/wش?wi 96<'m2K{5C5>VPoW> ^qf(ۘ uʹ GɞfyZfu:P):C=UF)NQgʨ<Ӫf9Nޜʛc+ˣmvw;2u2U )E.]qaDJ7_7/7%~˄r,]8-o/] qrDd& endstream endobj 133 0 obj <>stream hޜXn7 -EaH Hi&pҕEn"H]KjWR61m9&R λ@\L\.Fv Q"C"5,N%hx.ƨFr+N&R gGjdGTËcШSV\FMZe\%_+ɕm19S].U\+@,:@KZQ,%9B(#q]'9Hd/9tˁ 8Z#{]#XH-QF$>hqu;pD_5* XB1h6 bä"Tj-R8Ē%9J%VK&ED,]0YUA44R.AUZK"Z%f]')+Lk66(8UAbE)՞)i3XІsQjDq1$ 'sҘiĒFH Hǣ{'ͯ?~~y;)3Ɉ\~4^Z^XW .Dc[8֩z"=HQϹqo^Ǘ=Oz=p[G\|)W|"\UHçsK<(rstx)= /_o9uÍۛÛߚMFUݩθ9>}/ew17u[EvO#8iq{0۾KlQ~T~\Qv`̈f$3 CCCFCFCFCFCFCFCf =nTS1[`=rr$nlº )2.4,&(ˁ[Űg\'gN&GZ'g뀴NtL1-n}q!ɏ%/~C?aËx8ƒ bã 8P8b8B`W5<>n;ztvi !KKF9dtGF1l4!!!!!!!!!gCnZ5NkM&f di"C.lllW}W}=کNvʶӱj4j3NqBwˁk__{5kS^_p=rmZghӰΐ6~CJ[7Ư`hk m=_iH endstream endobj 134 0 obj <>stream hޤYM5+>?RAv7h--){nWxnO;[Wezv$fp%ft(?S,Fv1PKp` 0FG&GfLj'Njh\s]X3XaBLu{]։'%wj$޻٩9XC-9$bi)9rYx,9w1jcVT+W+)\-p \j-/!5G25_x_Q*"Хˇ t tYTYbR)e92! p, %R+4T١O% x!( aZ5HT"=ؑ`DU TLECFCPgq*T I-,"[_V%x98*4GhT]ȡ"4GƊ`  |AhxUJApPH@k\I-m/?!^{|?õpޅj^UC*RR瑼 iI~ `A^PH /`u y u>XE`+56wċc#^؊ǼOv8oţwēxk=8Ǜء?xփwozc=hGc=voCϼX=z쏴Cv/mG\!;6#k=dGfh?±;6c-Yf{Ո;u^6ތhF2@3 6CXh~W׫]*uW]v#Hꮸ '[w ѭQ24.tw\PBVH [!u+nt2v y90@A L]pcq"ع03RMzVz_=fN<;…píg. i|ȪpoQi"HM$| Kϛ_'Gч/GN;dhK4^x%/<y G^#/xᑗ`K0^d%/2y ƋxE^{ >EdG!g/-ZQ MN#80,@&܀qGnl) >&܀~l#7Nڏm`~G^Ў~G^6b?Ѥn?y$Vxmv8|#y_ߢ[prtZ#7>OKdG25~nY;ܬq=ur'Ip~}<֟ۓ3xV W^e& Lud)R KA,Ų[Lq"N"OsS,V:yL<9Qx' I>ir4^\ajt_,ɸ4 endstream endobj 135 0 obj <>stream hޔj0 _E8e[h`dl!YORB)to?ml/֏,,M!MZ@jbA YxPQA9fIV|DEPEul'FF؂+{p!|.j@wOew/0Z >N4EiD$%єD$ZxlNm\,oϭY~qUvz[,e9Waf, *YHZ>stream 2014-09-19T11:29:58-04:00 2014-09-19T11:29:41-04:00 2014-09-19T11:29:58-04:00 Acrobat PDFMaker 11 for Word uuid:201118c4-42fb-4963-ada4-a792e9065c59 uuid:bad1945d-b230-4d23-98b0-f89f03241c24 6 application/pdf R2M Micro-link specification Schneider Electric Adobe PDF Library 11.0 D:20140919152906 Schneider Electric English Schneider Electric Schneider Electric endstream endobj 137 0 obj <>stream hޔ0_eߠ-OBxB7xQ#zhh!j!gCFlL 1?LҶjw^ZX5 ^®B8T?^uJ6R,ê~|OA0n#x gQJ=ϖ $ f:3333`AcI endstream endobj 138 0 obj <>stream htn0D7+5DTT*qv%HhU5UUg>I^:8!w@l;-q1614&B>/Filter/FlateDecode/ID[<1B6FAFFCDD900B4B818557326B05C277><213E18AA97CAA843B657983D9A54C4AE>]/Info 3896 0 R/Length 526/Root 3898 0 R/Size 3897/Type/XRef/W[1 3 1]>>stream h씽kTAG{vc&݈ ba&"D0BQAJKA XhaH FE;E5% VzR.?fλs6EE=>Yo.S$;=7HvL0=Lrdwp*u7N%8}G 6Q_IEG$q_H&Xyz88rZ|rBn$[f*H*8gl+y(`zrMڽ>)uf>=g/MfsuIX*O.&<}{x6n<6X v=Ʒ,ǂiK2ԜYRl?),$lnrExsgP{P2;L |m:[}M:yӖOv[?p!+,:[+)J+)J+)J+)J+)J+)J+)J+)J+)J+)Jԫ endstream endobj startxref 116 %%EOF apcupsd-3.14.14/src/drivers/modbus/MPAO-99NQF6_R0_EN.pdf000066400000000000000000006102731274230402600221360ustar00rootroot00000000000000%PDF-1.5 % 987 0 obj <> endobj 1005 0 obj <>/Filter/FlateDecode/ID[<4692FDE684BCE846B0AF183FEBAC1A70><79D92D8E108C1D4585DC354B6010A51F>]/Index[987 31]/Info 986 0 R/Length 97/Prev 200389/Root 988 0 R/Size 1018/Type/XRef/W[1 3 1]>>stream hbbd```b`` @$ ɺD2˦W9`vfǁsA$W4|K$R #s.F2 dw< endstream endobj startxref 0 %%EOF 1017 0 obj <>stream hb```f``Z }A2@qK SLbvOg` lPtRaebtY>/Metadata 39 0 R/Outlines 249 0 R/PageLayout/OneColumn/Pages 985 0 R/StructTreeRoot 366 0 R/Type/Catalog>> endobj 989 0 obj <>/ExtGState<>/Font<>/XObject<>>>/Rotate 0/StructParents 0/Tabs/S/Type/Page>> endobj 990 0 obj <>stream hXYo6+|lRޤ, dU-AuD-rF$MGna@jn3is a3f ä1'FZÄi8L3I f,G}M$h` z]DrDŽ"l jxTNͰ.yA򞧵$Z:=iGjr)`Px=4>)S( F=K]##K2nbt> mI|є-Ep!_qaӦ^J_ob pxQ6ݶlfzyi endstream endobj 991 0 obj <>stream HTn0+V%9dB*UijĉJEj9%zIj<8M@h4 ų7`ވAr$5H!~!ФVSBFHA4P9gf58ǽ=BP1Rm}p 2h?1~zܗ0JTE(x24TF} 2MYVcDtMI52)#G :(~Uޒx/s͟sr?dCT'h/& 0 endstream endobj 992 0 obj <>stream HTKo0 W4H+zP Cءȼ-Elib~Ma$%LJ(b?+ ;- v-L>8:u&u@CeJ*e^`r[Vħn,ڑu̶{ $}:P&Fd^j~ A|41V,8l JZ{YV5:eaʷ7](Bkoy-<9Cm%..&z 7GI84;MQƼ;Yz"î_BXFQbK2##oaO۴|+á,x't#آ9<>#d9j.qmcC>n;7p1&1?!o&e`}To1'ٍ>WCY#]xx ;1t;&;a1-->stream HdTNAWԱ[ʴ{MBH`(($N<( cbϫېKoj=4pTR9K}v!2V|j_e*)YN$Q㕤pR|}wje&٬;e2%c@U]5TBմ4dmkM֐*3BBkomv6%@"dN=0\czc#i5KCA_ XZlAַ Gɖa}ԾP>TF(TSrTW#ti瑵ޱ0MDEcp&C')^K%F漭݉ Z_I+8#i6.{!6OӪNZsz!ΑoHylv} t#1Jk#.0KD.}{@(/غb]P_yh!emUD,w쟞CL<"u;yyC.ؼx3clKWF1tq.H endstream endobj 994 0 obj <>stream Hk0WG fEߎ֤`!ڱ|4鿿s% ^lI>>sQjJU4o=5m]|QWN'YZU/iaNp̨0CũP#7^ 4^zEZ'| ,L#]D{Dp =Hؤ n*d2< K78 X~lvnK6\W  Q endstream endobj 995 0 obj <>stream HSMk1ﯘ Y_ځ`YMq֩;#8Ћ4OQ uB - *AKNcMa!ʉV/EiU)7h*D &h>upVl>|4)딓FG(iKK]DD%cG@ZYZF!B%/:VtjV)؎EêhTŨ|)Gct2̝01[]m?+w:|45=а<6 >JTCi{l^YpİkzuW:НEnNs<~Z1gyzclmL3%maz[қxB~Mo{s5a>40,դHʆt9iWhym 0 endstream endobj 996 0 obj <>stream HSMo0 W(-@Q`Is؀blIGrl"[x||§bŏV^W,8ڂsmK8/0Pc?¾htArҡ%8h^ dϪ))!~_ Un5WK7[~now-[8zk5 6b^ .b(aJYk/ⱓv)jU-[8J"gpX>KeIɑLj^2RZT(0i&R_Ѱ͋rgZTM'ddu)iu?DNt=ۉG|3Q:r$t%-$ ό9尿GvXEv*P;b#qK(-{|=bl xDs$%xmؔ1IRm݈U0% K&h=9xdsy<#JmfziFm=qzy6MNEE8I]:ḧ/x- endstream endobj 997 0 obj <>stream HtTn0 +xX,YN6=;dnYliPl_?RgK/"dvl[ S3QZhɣxx"VVY㫩'4oaj%-~__daEN<-F eC.&g)7tkOQi{%.XHHK𶊧B JAQ(kHH.L 2qxfF18*\sd1^T!p`dԂ$vìB {2{~h},fljʱfx:$ ;rQ!Vydj4(x%J͜i&qL5MTM+Kv" |GYTtD&WK[̡ cTkq^ p+:Չk…[W׉HiRNUGʊ.aj{$$k~acgRq&>,Q31^iPPlG;ZR%"g7R6j +t endstream endobj 998 0 obj <>stream HSKo0 W(,eMP CSЃ+%(n.%)gi=9SDS@SH@{w/ׄC\ޠd_MyՏ3εM!",H^=%m䰊 LNFfPiHKk;EtAv`.>0iUrThbEwU8r*thcV)HFmI(@H hؐa,_}ೇdc `Nu(l~ ; CThP-wZ2i(󸡥~\X_d䄎8|h662 4r!fps=?MHL2^I3x)^>TInGbƔ_IeasJdM2 U"?p@Jqe "`SwՅ`/,si u4ʖFz9 WN endstream endobj 999 0 obj <>stream Hb``$WR~  |@T # 2 S/`M.(*(%8H8c- fԉd9@6_IjH9(3=DR1%?)U!$5X3/9 ($5j%V*'&*r"(,!!0b;CҢ2(ɘ I8/ endstream endobj 1000 0 obj <>stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 1001 0 obj <>stream HyTSwoɞc [5, BHBK!aPVX=u:XKèZ\;v^N߽~w.MhaUZ>31[_& (DԬlK/jq'VOV?:OsRUzdWRab5? Ζ&VϳS7Trc3MQ]Ymc:B :Ŀ9ᝩ*UUZ<"2V[4ZLOMa?\⎽"?.KH6|zӷJ.Hǟy~Nϳ}Vdfc n~Y&+`;A4I d|(@zPZ@;=`=v0v <\$ x ^AD W P$@P>T !-dZP C; t @A/a<v}a1'X Mp'G}a|OY 48"BDH4)EH+ҍ "~rL"(*DQ)*E]a4zBgE#jB=0HIpp0MxJ$D1(%ˉ^Vq%],D"y"Hi$9@"m!#}FL&='dr%w{ȟ/_QXWJ%4R(cci+**FPvu? 6 Fs2hriStݓ.ҍu_џ0 7F4a`cfb|xn51)F]6{̤0]1̥& "rcIXrV+kuu5E4v}}Cq9JN')].uJ  wG x2^9{oƜchk`>b$eJ~ :Eb~,m,-Uݖ,Y¬*6X[ݱF=3뭷Y~dó Qti zf6~`{v.Ng#{}}c1X%6fmFN9NN8SΥ'g\\R]Z\t]\7u}&ps[6v_`) {Q5W=b _zžAe#``/VKPo !]#N}R|:|}n=/ȯo#JuW_ `$ 6+P-AܠԠUA' %8佐b8]+<q苰0C +_ XZ0nSPEUJ#JK#ʢi$aͷ**>2@ꨖОnu&kj6;k%G PApѳqM㽦5͊---SbhZKZO9uM/O\^W8i׹ĕ{̺]7Vھ]Y=&`͖5_ Ыbhו ۶^ Mw7n<< t|hӹ훩' ZL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km  endstream endobj 1002 0 obj <>/Filter/FlateDecode/Height 1126/Length 3522/Name/X/Subtype/Image/Type/XObject/Width 613>>stream Htk|g))`h?撨* ZD)FFQ$CTDEQѡ`ADa.JA-7Z6u$yGc<4z8vY/#g;YLK?<z z=)^Ô;ņ'FaBwÄ>vFc˾:z3#[ILw/Fb*%}=i<~Y[,|`4&qs4X\qLۯ=gc}z|qߡYrƎGGFd:-NDf_xxVV?%t-{Ŭ&G};u;>/}c\7? k.V_qŹa˦W_y&l޶kSag`(Pp:MeI6Yyj*Sw}v+57 ̪/_~m66n=׷l7Bjϐpz܊v)tVd͓v/c5#~fdoN VF{ !EFX2 `Id"#Vdۇ"2^@ޢl2މ" B=y+2DFܛ" dw?Bv"#67Q+By&{ !"#lk~(2Ȟ@ȖH+#؆s"#l+y!2n#ۂuUFB6gDFX+ y.2V7!ٴkEVZy!O[lplLDFVrйn#{ !OGVXڀ*#{B&k"#lqBV'"#Ye`a BV&.+V!ce[dd"YoEhBDFXKx&2Ch*"]"a"#p3y)#~!EFZCaeds2;%2z'g!dFdM@+#j3)| 2Š2!2F& d+"1VF64!"#6Q)">VDV^֊^m`RDF\كAHi"?)"#Nd5*@JO3"2DFZYo?ԋ Edĵ"jBJMd"VFVn&2DFȈkEV!Kd8׊]{"#Ldĉ224׊1%S9"#NdĕALEd8׊^rDFȈq > endstream endobj 1003 0 obj <>stream Adobed    ' "'''''",////,7;;;7;;;;;;;;;;   %%#(((((#,0000,7;;;7;;;;;;;;;;   %%#(((((#,0000,7;;;7;;;;;;;;;;'fe"    e!1A5Qas"Rq#2BS$3CTUrt%Db&46cd '()*789:EFGHIJVWXYZefghijuvwxyz!12a"AQ #$%&'()*3456789:BCDEFGHIJRSTUVWXYZbcdefghijqrstuvwxyz ?*)[ /{@rVCtrSf 6{}qm793aq]&83t{7s=dF40X/Ph{~xx}D)>Eo<|>w[A?CVh;~xx}D)>Eo<|>w[A?CVh;~xx}D)>Eo<|>w[A?CVh;~xx}D)>Eo<|>w[A?CVh;~xx}D)>Eo<|>w[A?CVh;~xx}D)>Eo<|>w[A?CVh;~xx}D)>Eo<|>w[A?CVh;~xx}D)>Eo<|>w[A?CVh;~xx}D)>Eo<|>`xNFq~7Qq εED ̹ho߅ƯH*Gpq*&Z';X54;yG(ULO}37/:(piI4( U" """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ ""i#[״ÔbNJcd3.*vs|&)B2jgkG7oƷ||1$#22| ѫ{^.)PQ]I7hR565xHh$A(u'dA%i{zz 6)jqEwω|اOA8"zzˤ7E4عȂeEnjz?1A/o A/"o^uSK-- OP@| OR uE - OPA."ﺿ %PUn(c2``{yr +.'˓\O BGKӾLO B<\vؾ+dl+E{2,<#=OmvոƖ.V{FϦw/0UZX-6s_[exlXT 1vO:!BxQcUV+(⯉XYʉc'vq~#J*`ѧ""B" """ ږ-g>EK"|>6DϿM>7gL3ҫ{^.)PQ]I7hR565YDUboA`~ݩsGV½Wv]zpRUC+ּӨ{_I C%i!}(oYMAcPXRK\m`sk|R}a]?-eb ~ 癹gS+<d4;IKU prS0snѿ@ڳE .CQ#<+K4m"\y2^fsʽp̋s.Xo[N>K"R1ul?KY)IJ#]!v^Sok컿} w6=Sp6 ^ TƆT<9xNѮsp\Tϧjh/l(uN>hꇡoTI:*c", F=6@3i&ϨEVmEDED@DDDA,Zp|%ږ5g>D.|l~&}o?gߠӫ{^.)PQ]I7hR565[W؃Xj>EcNkˤ MiG O9Anw):M6Xm$} P<#U^:'NNg `TEM [Πkk7 D!co-7㦈pwL? H(rnIml Wp){YlY<&A0vpZ,ZovG>V1 ,5I-$FAPqۜDbF$ulv]wڗ V*&HM^sAq6N9Pz q,us1M|u[=<$kuY8 K> ߾}YoC-<wvZ/swiWۢV3ں%]" """ """ "" wP3-qC?b-Ju =p*""" +5UQ7NyYy^>[M:S,Eqi\>ܸx58GGe-4|Wϰ}un}Xpi>`\+/h>u#}pz% pTov:FeMۺxSCD `(zWa5N+YZ20k$ AI H>o'EZGq~?z-IfUQv-jX՞K,jp| ]>7gL3|>6DϿ@ԫ{^.)PQ]I7hR565[[݊Q#DqYu祩T|^#ӖYsXӨXk%r;qOq#gJ7G ylAkexjz1 AN(ԉc:TnxFz' k@ɭ1ݿڃG<:adR܋i.d|򗽌hX6;ך" wa) 7. `II-6l3trQӼknAZ 7G%$L -ma+yֆomC4&v=ih0(6[a7ta4|wv[FcʴU'ں%n] " """ ""*%'4r֦ut4 ew#52%K1fT2jc3rssdlKD/[uS?n&*<_ \/d}{6J_Z -i۽)}i۽)}h$7hY+0v$ ȸotFKZ}n7pj*3WbF:MXb))sc[VUO %IhDx&p^Ԃ>zكOXI!>pkkp8ixJgÁՒ\ SXv堨F4 ̛ 9u\r=h%3_yn㘦 Zfjp#m>sX5]&No4 vu4 y~S9l9л%^cw9Seyev黃¤32xOÉవr-v[sӸ2wňD@x7F]s =H"QEH#3R~78uUD umDQx]Y-o&e'+jJ0ذJha$$ܨ"ؽϝݥVcʨUΨ7 lwsۅ};WB z1yek|>kQ6cyФ;X}[IʕQ 32ɓS;~OU (kG9ht1OYm;O'{a֨$ɫJO3G*5Y5USVїY+э+;]<%Z( WҎDTT4z-ɉd^m0ZQ59YJKSkEDIɓQ hꇡozjUDCHTQ \. !z*ଙOLnnYޒ CnֆorT1\*}-Kb6BZ )*{JZ ]#ѵJqWx{ZnX MRLp!GpKӗ֛~$|%%u<toi pFgw~Eأ斮wT7FS+ŭg_1փ;ŜRTG)h: WYsT X׶qȨy/ߩu/ /Q|ߨOދvB~Zg"̫6ZԱk=,jX@&}o?gߦ|l~֫{^.)PQ]I7hR=6GW؂#ԕ55C7U{9oR vQҵXXKZmneIS;v(fQgڂDA%$ Y=ƭe1O|ios[ va}KTt7=֞ {jX|@7[ 2cS>v؃' \q6Xnf/7);O+mm風>戮`i&C|~4q9^t9n^is 7TG)mGؿt4~f#oT>(;#-[s= FR5|/oEcƶRҰ:Ĭ+7_'EĂɰGgtN2GDtN+I#s-C*J .{H6qC1`ho%Du[t |q/7/ʻK`M1mMAE|*l/ph$qyOi[*V#IF5D,siHRpfwpa;=gWRPf P\E&!86kW>RlYf[DYhDDD@DD;RŬȲb{A?gߦ|l~&}׫{^.)PQ]I7hR565[[݊Q#D -OPo{2OQ6xpr>(b?ܵء['H/W$ ?|[83@aln1O} ZN!Juk}5@}+u*e6nbtrfy{C˘C_̭RrX>4,y蟛^<bcٜI:w,Ȱ]lsqdk7sq)(#4]BNP f \+ D͌xOq:N< i)y{cc IXIru5IN9ws£?3i87+LH󠚲 洀:6%Db#8a7Ɍb򲶺SIhn|:ZDkhn|h\M1)4xg`lQ{)K^FRםYxNWr{{4 yeK}g0A` sZ(L5v*w/Pe3>hg{`GMNHV ."y{Pt\2k4Asʐ+iRl6']xD,ZI}:.;6lі\\:]xL\8Sq{X-k׵[D F/s=]cH#5n!iWJ&n? 9ȺewCnՌʩBD&EßSI8Isvy*|ZTANkN 8\nSF\_bSd&E|ggtt{rWK1%VmͰPb lx4PkFª/N5UG$3zV0 Mפ4>a3ϧܖ/JbMx\\:Lm ;y[a벢mVdYJ| dT־<:qkrܥ Z3,n7Ȼ :g))oxk$U'*p85-Aes ܕ\x'T]-˙ I@u6 ^dd$ C nvx*do'SX9;A*9thvŮ_<TlBxX Z헶@ZD^x%PBq{J5*<*<%]qd^Wv?"n3=ۡl> m<|y'5*.4xO7gL3|>6DϿ@{^.)b7zIB}þ*})An*/}ԟ`P ]C3|NLd=)dPR@~ـXpmrZMtx+M%4d|d7Ϫ룧2:{RP\~緷j|/ʻv7ƴ)NeOž,ssT*iQse22FɛB.|;Ľ'ybn)oMӜӌaJN,K:è;BVG0">mRm9HL9d>,1I]\;͆͹ڋz. 71!A7u(0Z6]-A[mo][H*wqi:Rv)7pvږ3 lJ 4t\ 1,yJuܭ3Ŭ܋k%tu6iQN -uiA6Cjc xf\`yA .\wOm'I,\E _%U^'Gݥ\ǕQݥ\1%]ql^WvCbnQ4h$`\?PNlYR6ENE!S3.U '١Z[ ӣ<|ݫVIbYu)Itq) DVƦ5",4""" """ """ """ """ """ ږ-g>EK"|>6DϿM>7gtL3{^/)PQnФjaA;ObQ/wҞ.~W']4sXoYڤ Z{3?dT׳IഐF`ʡɾ['H҂^DS|ܗ% ?.4̽׉nD,{d!<}kH=@Ȧ|="\0 xR.@WyV>Q/F¯+5(aA Aݥ]1 <*u(A)nCbnr[ݫt $d-/{Z&yʩG[IU܌ͱ7޹O(^a,65zW^w݄|Z'{؃D*=4 #ȺӾ#ȺgAU}A=ۄ|ZwۄZ}Ϡ=I =4V x5쿓jsضBQU +}c=Kv''|X@zNa?=}If}gԠ?w=K?w=H'n0> >PO|x;GzԂv >^م|Y(#LORwˊ|+A;م|Y'}WqR{>ހ'|ا»}WqRwم|Y('\S]Rw͊|+A;wׅ|Y'}xWqR{>ހ'|د»}xWqRwׅ|Y('|W]Rwϊ+A;wم|Y'}xWqR{~ހ'|ا»}xWqRwׅ|Y('lS]Rw͊|+A;wׅ|Y'}xWqR{>ހ*]|I#>^}gԝ_=}Js=H>ƨΌ;>W8fDmms:B9\B9$7pk)i6.Աk},jX>D6|l~&}o?gߠӫ{^.)PQ]I7kTM TKV;Ob݊naUtv+{(&Ϸ처~K8Y4HkgXRiG,|K(UH(xA,@{CjX_owZ: :I,"8̐46e]v$-+Ȍ?~.rngkM#t]av8Yx^rFd lj{fuZփq8eFDP>Rݠ-}ch!tζV 2-~D!sTa<{d6K:qij]5@T *l@R^H<^.D r@ r<Ѐ^Yz7yZD Vp<*Fc=ү4f<-պZ]t~Wv" (v~TԞX~ꃚ0bsOi]20e6̓<^lbAn/El[B}[ĭ4L]j**()]&9ukؼ5p͡cpzCTiZCpu359hoal-[Pv4]Ljak]a@ͬ,c e(h9G2ܥ[jQV4t$ > vֶ$4A}e#Ծ宦hY{K ĐZ݆M9w,3CK0A~PCuPⒹ4C(!!m#~U' tpYBHac^uuJqf˃Vk}Խ>/g=Kg& o|=Oc6z--A>gR{ol0 o=ELUWT):eMHiGsya3o{l?AMc&z /}7Զ<hY~ }It_AZBH!f Z\jԂc&z /=ɞ}KatvUk=7ԞB~fAV/=-tq|E̋55otX͖ c# iA{obv=4o-].-#L1H.5ڮE֦lXXPZ_$O~o(}q2蓨ȥ5袬|R4끤M#IF7æ@U=& <S8,v(7Աk=,jX@&}o?gߦ|l~ԫ{^.)PQ]I7hR565Q/wҞZ_p= 3? ^;QGe'B\mZa-* *H┴Ƽ\HPf=Ɇt$ZmOPA..̥ՊzUDYW!<b7Z\E/{) -k;V-MDn3;G^Z stReoOWwmtjcH-[ދg _Andcun+mp}!:i'5* z+kW|іe֮ Z|'5Vc[,H=;Q^x+U(aWϔKѿ{Jcp<<.չZmqt~Wv" (vu')(v|u'hsv-2!mw'uWaQ g$[3s5Ƭp3 =۴C&hx!ɑj(Ol.0m.v䃃K8.!ۗc%ɲ N\ԑb "H-}y-U.uaFv7apJp5^O-vehqiA9Qi.VFktG6>5 [&l=Ŕkd:D/9ߑ{,mNY}?Tp5/H't1ݤn'o:W/\:\*H&交EU"%!z(-fIv粪[9USMhp-Ybii^K/QDL>ֶwԪZNOв)KKGڀ6%04訟4It]g^JSHfفt6u)!lQ5J.m9r K lh FVwVP4^ZZ3@o:L<8ː#g: .R :ћ1in{FU\M{Hp"lEVW=.io`llVgFi mR d?ܔ.,vPMoI㥗7Աk=,jX@&}o?gߦ|l~ի{^.)bwzIB TT;ObGj>B#Qڏ<|-qZe'Bf\vm iYSn$sCu7ȷ4⡺:D[<'kL3FH-WDc/ #<:͌'Y32qӕ,i /Ap(=ZW >[Aխ9 Txo94_$0<`:(v|t,?uAܞ]'3aOJEsS[غ:#"2n>Y ssEy sj)4nl A-Wy4̍1t/a`H z 6ӒsnhtLQpu-;{*i-w4oukUS vk2h|6Rdu'@RC$sct76:@x'Zӽ3id-~Pgmzvo">}= @|)[ i+tt[/V7mRCE]T zz)Z/bMCkVHHqq%v," 6tUT51,0sȏ":rR*7= 3ULZCEi,畅QO+xOOݔ븾.4vPUwIwæږ-g>EK"|>6DϿM>7gL3֫{^.)b7zIB TKV;Ob?݊ڏOH" s첓 aе#N-*B[{j5]klsdxUStrHi)mEK"|>6DϿM>7gtL3{^.)b7zIB Tܟ!U*_O:Wتr>E[ܝ+V~YI &: \,.Ƞ7:a[{s]'BJȽ\鱚:0,pi7!$jb/ b4 P{`TT:'MlnpgՅ;r~ꨳ-'֟AZY>R(5}}'֟Nh|i>Rڃl kE]}}i}}i7Zikd$Ys@v.!.tuPwQC'֟^ Prdi .qwE 󅹸A旅O?Խ驪ƓO- G}4}i}4<}i{`RPnsEx:!ms?-"zԇ{c Z ((:f^ z7ԫg%PCt,۬<_)#kY<39g~Eee}v 3r]ҶSn.i[dD@Qvx_,_tRw`~ΥhcMs[ضX3 { xֵ9obǝ 1ꆓk ˏ }k2uttR9PZϭsEEN 4cV'0\[=H$1_Dz׽x#֣U@>_Dznė{ }UwEKZUė~GIZၺfhMXW)<7!l.`P(:Wb3[Y[/,Mn{FJ#mY]rwUd~$}$7I{t},u''=kxm!z#ֽﶓœ]{t}t,},:i#5܁bḫqFh ڃ'S[hlapB*(_D&^k aSPl^9Z_ SvDx|5glpE}^= &yNu%A :Y4Ndhps#( \K,N_Oݔ縞/'jqL9=qG,Jp|)ږ-g>D6\l~q&}o?gߠ{^.)bev#S H3U/'UK 9@rtTGȯ Q#=,ܱM[^KK::1?-"%P1aygRt\:{h0,xŋgFGm)`h'{ȟx:/AYY8]BS/ nW\V-Vًk]s[صۨZ$kIh i;/m^TfЯ}l G\::E3$vz pU@ZiU*` Uh9T jr.\A^rApP*ޕB]P`H-bGY'-vq}'ߕص[l[󒃡wAҞXl ]qC ΑQFFPoVN]@Psr]kQ.D; NzNve3i{ dJVj*J9 ԬNjSZCr9kABHI:CY7[:|RᑸoUӊcʃs,]Ju\:f~GT.3%m曃0TɄ{xCkAbojw o@|_O:jXS,j"|.6DϿM>7gL3ѫ{^.)PQ]I7hR565xWéjHf+/[vA-n_,*a4]pl©/_~ ؑ|t iA{uZj5ݏZ x0U{P†{3#AVۇvd{ᕗhۺ]Pu?}kHMK/`.‡)]5#HostDdG794q2 slKcٗ6pQ4,a nZFH[3̰DxϭVfRnApJn_$;P 'Lӄ}h&mt:t/'H׺RxϭhMwzAz N=PZZSG}#A5 ke, q0GruY|^^Vk>Q/F‚M= 8K9 mW {UPB\vM$sE\]=tԿM̿Ml7(:kZ6fJ4dˉ>p&/"n_\V-F1qbURFYXYaQTsg9yFv`PPcX*UH.UհnU@U@bʠPV +w P\UP:WuP*¨\U][h.^U%P9䂻{un nyc SxNPsn~݋13~i9ZZ6̥9 \ǟr4u\.%L%܇[`sc̻l<>{Pp{- ^ O  ?}}*cu; kpW6xO5Is.yNK IXٳa.Qn$ 6DϿM>7gLҫ{^.)bwzIB ^KAT|nOmڏ]|Obni?238A+1×M]N!ܢ ӤUHZY4Z@Jv'i]uo^ߦ.ml`jATM)GVd*ZidEa&ჲШc6 U/%y׵T@HèMSpVH*ֱxG;dQx Au-:AcwvyU3)t5-'Ov@#P Y >צ>EoH;%ktKAuݨ_k/M,v3Lk"6<  {>e/dO͎2֒mѾHeqqD;W*i tO `QApxh$h.{8_^dmpKudQ!q?ߩp|^BMӞ7nށ;ږ-g>EKy@&}o?gߦ|l~ӫ{^.)bwzIB ^𠂪'~ƺ6p`~4Oeiڏ^և|zqط hwGllsk\ PKuԠLyz&<V~b@s;P{AM`bUM  d$k`Cw^9`$AܷW|Ɔ `cC7W \r pFb5[@vMq+ \zd,#{M'C>pp۔\u/@A(` Md _ %}Gt5Hkb5DEf:sIFɘHkAUw!{5Xc 0ڀq؃XE KYz7F)dl{-w[]g%PE8V 1:ĹcDrA j:yU֌ǔ 7}=o֏q?_ڷc3}4_tRwm}4_tAS.|*W;Cob *;f-6dSh}Cʪ¨ec)+`{d$2h]vzsTtM+e{SԆJmsH7-_"EC*x$,54njnK ƽG ݽemZl*ŊSގ׽a;m: GzX_7^޲zR7%7N0πoƶzPw+G]K2Rnzv(47׈~'媪4΁vnVuV`^9A\4GYgm&k9ʫnF!}9Hh@7Fٍji88ac<']v"[c8X7M}$S:>PٟB / -iܮ@EڲZ kɸϐ ) Vצe=2{ ;e+E5H=%w/˰S0%Kn&J\1Mk$,iph{ORn4@[ez|?Aถipl2 _L-?- ,Um;׃ahe>HZFҋIUOS4%`{o{WX/|:s;uy!˔f6FD cWqJf] Ydq,w Z .'yVA-K!ь4y ,7n 141MsE%H)ѶC3rVA, iou1hv-WMJח6Ceܭ\~#5̌EXMӞ6ӿ(;X.{;mLt:WjX̲]b{2|>6DϿM>7gtL3ԫ{^.)b7zIB ^𠂪'VWj'VΣA,n`bz/X{,=hpnr+s\WI}ovuΟr^u·ZL19KIYl6C{CkTl{C{CxTM1'dNkWCE'A*~s?\UwUgS4+X^6B?\^MgYM?mk+pqU4 d1@ q]xVpDH^3ֲˋݷj ec+)Db+-7g}ڠ'Rӝ#RƜ]@ #dP"ZV6Ӻnvi@eijbdBo+] T|r%ljQ'F‚'xڮf<[xگf<uʯ[ţ܇W" (vq7EE+(vq7EDvS}3{U \˼]lFL#VεyW v+AuO]s{5ҵ&  ظ啐u5>h晭$ ̷xn'OBߤmPf*%TH+i[Z79d0A-.66$Re6iQۥPtTDAX$[ ր6.A?D4*XM ksF[lwb'(7lJ/ (l<7O#vB#FD_=H; &}ֲlkX]ivB!LZIqü/l_QIԗhI/bI9Mq>[C,ZqYnԱ+=Ǚ ;gߦ|l~&}o{^.)b7zIBv ^𠂪'u"U?O'ju" WsG쮗#1 /g|-[YI_=vvf ɦdd 1bHru,*צu<=7%P DNwC\nv dRKD^cp5;}CgdvY7Yʪ Tei{s5C#H,yƜ7eMi,۸w5p+5 /a\'ϒo҄ {da>P&Ȭٱ$G_b m7]ԮÛG;V<ZW8 n]g]/Z~5L[Tk+!y];J&ª{vrtZ+Auoɾ~ưִ4vdM_%UւVQ/F‚*xگ4f<[xڮf<qʯ[ţW" (wo7EE,(wo7ED[+ܑ"<ꌉOIѿfC׏@N~]гiAέxdL" a|μpDPn짒R8١hpuwXEр}:@jsNpV-FʹL,k8--.sT>rZ['h_vSԻ0cs򖣂m f{~C }ʂɆ `ُ(,p@I%ķ xw!.4C nkayXV~Ibps`$9Igk-s*`ex>D:L)'}dPDF5\e,n3mD |Lw+sT:I&H:jXe;RŬ m>7gtL3|>6wDϿ@{^/)bzIB½^UWDr)0r$#tX,,0*02b9_&[ l0؎W#ACRwiFZUsv؝_ /D ,HH#Ե&ȵEk sAgЂ%w@Y7Z/r^<%K]:ET[àx{)b茐[he(w-O0t2v@DDfo*W:7lyUǔ+pyU֌ǔ w!Ux{a'j ""ubTK6 ɛ ~.^ːܑe`Iʰ?˜}5&t`ex}Mkr裰!Ge%]R8,lk7Hw{A[*IHYg1pX5K1R͚:{]GJ vZWH1 AaQpcH$,-l͹vWaXZ$md5Duq2hv=<]QjWat4]ܚD<*~_7M'݊6 !|4v* m %ҷUTs}R}ܕR05;^qSu(*q}$J;?f}$$rqA]; ڃi!~yO{ ^HAf0KqkY q yˠIT/tuG҅"G,JmKzY;PZ~L:2w}:G\Cu7{ܭ6a < @sV M9}2hԦ|pkL*t+S$:پ(Rq!39G`1A (9 igߩK{agv׺AP[%Msgv;,JpVc,Zp| ]>7gtL3|>6DϿ@׫{^.)PQ]I7hR=6½^]WDP]P аIv(#lqրL-Զ'J\Y$NFi%if^㯽7X(jߥ-`ut4:ĖqT1Jܯbi\7*@:VGI&^ϸ:jѵιhlRo7#ˋ6YZܵm[.ppvAZ2LWtd E9^f6FsB5Hfqsk$a2=31> ^c{K[m [U,QCO7dFXqjyΌ$S={d14N۞w԰;g ;@m]^)TȜXq,՚GY 4m̑̃mw} O<{uKNCRXm{tyVj_5,cNt^%`U#}- 8>U#{:i>FBT,URC]x#Op.f{*rL\$?H뎧.ȭ zF{BΤCovR$XS(!lwgTӽ;wBlJ~Mq{cV]b{Y.Ա= wgL3|>6DϿM>Ы{^.)PQ]I7hR56½^]WDu2|KXTT$e.'DZIp 4;:Ϙ,LK34v@davQ8 tWOI܃mz8F"ʚݕiY өG\؃s5i9:w"&2OX͞6Gg.jvM@\aai"܇[VE#KAi;`9oÙ< Upn*sD{(ut+T/*%Hn ĵ<$ku+1e$` p21``q[HNţ k FÙnƑ}$$֛\{zxWLYr;v86 d jDr&R^H ث[48!`쑲`o1RΉ=goHޟ6>){)' ] h\F%ij{hݡk"7OP|>!}jfcF؃mMyoˤV {AQkm2GvU A)fgc`U;^Y*Lq{cVcte?J}OtAԻRƬeK"|>6DϿM>7gL3ѫ{^.)bwzIB ^/W ƚNhWk?j:y;U9c)?+w?!?Y>g>^uw4s~RšQRXؚ\@\׏k]9ҊZf{[tv6Kl4Icʲ1;K7Kip|AbP;HM'g͝Hϡ7$l"Pکheitoֺ0j lC2M[3l+?񦉠XUӵ= $X+S*^^8eQY5XhiHat4i_E`63obK?,پ'p ժ&bxwH˹ĸw=riy)01J,KkM cYi1Ts]WAwf6sHǭ{xIXM{oHǭbU8;9(>nv:s.5ߌtOPG+oڮX*oC5v`e׼kpaoӿmDe}4_tRZua˕ܫK맆LlyEmѹ>=XnoR;+,|5Ϗ k n]K2HwI-kZuW/jݛNd lM!U48v|as\]چe苁st 6Q7gL3|>6wDϿ@ҫ{^.)b7zIB ^*j:y;U]iV2 's]M~0Zv9}/:؍vZDk]ˆ=RI-msWœ-^! =; XJLFBw1giZ}2vU <0ȂSYh -Fw3o+.c! UܧܞpUSWAR -Z` y4u&%xd1i8Eʓ7!obf9\5xʶe$ ҥg׭gL1L=: :/ioHAZ,W IZ0Spr(gmF*!ŧ&=džgAPwP87y$'Z}Cb,;{ou[M\DR+5CmT|wkDIs I*ٻz&{y $EPMkX.eŻPdIuPDaIۣ/ȝP|;zU LUM;7knt0T9I[vk3Iĝ=s37eWU,R91a`Z vwģ'GoH,RjoC5*Ť>?jfA[NշZ~03e@DDo~j>/)Cң w.}Lh n\St֠.U:ҖX*Ac" TW6>2t[-M9k_S c H`sleA72h׌ %s3,nMk[W{ XmcQAD ߝV ƅ ƒCE&+% $lV*CZ!)*+)db]Y1:G"$1 \n5$J Irzո܉%?irģG$Kgs;WXjDT\jʸd190H>e%:vCX#[# /Ӗ`6wDϿM>7gtL3{^.)bwzIB ^/W ʿƚNlWjj:y;UD}8-[Q~[-> {"ԝ_cI;U;?'dʣ!:n"ZryA uζ'Iu[RZ܁jwS( {r/wx #ZXEXuuɟnRwa~ڸZF#)eC&[7)K]!j1fOd37PMYct^sal-T9r؏V0o;U,cmnkp*[S+ֵ{s*]UM{S~Svi9N \=28\M1'27 [܇$'Rˉcp[p`JءeH pl(( kUIYlv[`gӿn`gӿp TLUt w0>!y.SsB0#Ѿ{2 E ؉"J~a#VfEeUi_j*wẨ?bUPS:G&INgR>'HҤE( C4m\Mee#4_H4\8ܟGZg'9+mm%#? $e]M7P"9T&g!5s@:O7 2\O"6)ic!%VEcK1=|DOQoo {V|W -^1j,)VTm$.8oFy}5ba)͇yyl^l+-kYV6>.M6UxʣStP9Pڪh 6dMgxU׻RŬȲbV{A;gߦ\l~q&}{^.)jQ]I7hR=61xW‚ iV+5<0 I6Yok\ZjE75,8a 9eʶ.a6tiPTG+w呲ȌgIͿ.VceD a`q.ȔVC0HA6H4.nv'RɪjֶA~M!THlV& \8rD`2˥v< kή5EprlSX4 B{O T%9/E\5O"K4GSܽH2A*c_b?GRXg{ƼS4ԣIm?T1%ȣ?VbJFct-HW}}yzzD^- Q[mʒ1"5˜Wt \OohV8t6DϿM>ի{^.)bwzIB ^jj:y;Uu_5{ti**M+LhbiʢKpZ,,9LN=QM,Ved<(x#7/cϫZtcx]si7UᏙ pZ{ -fgsX:Ca/[EI_fܖY4dp{t{uM#=w9sT]!cCMVrufHAEߦG-z>m!n$trpD8\ܸX{o!GdF-gث9VC>fyVabd4{]_0i lŰ18!sM á!%K8XZݮWv-䑎Ua]؂3Cv[D@Pmjh[ڡ}lR fyݞщ X64۩sy\b] lq1YbAY-#ꢐtjvK1~C?vYaAyORׁKªiAe/IԭUM}e:-9(Lwj&6iʏ>ݫ2<U6RH{MŴ[ڪ*&Ht3QX@U PUuܹ0g=j.?' x,;gˣ[r~?6j(2/\(t%nP4][@pZ=DK5fy,wN*Û|<5;ț+f ScKvѝ!)^Ib=  @ѱج`#lMGfm4MS=t#eӒX8doyadt0aI nG;MFg2LJS_[0ry c9YK\ ZjjŚ4Y@hPoKύm8:jXK,jp| ]>7gL3|>6DϿ@֫{^.)bwzIB ^UQڨY'=`bBUQڨA4!؂m׭eT-^ ֢_=fuVхFب#1uD1b?mrr[6j)ic -`AO <W4k*` ax77.bhaD-mnE>2`qMljĐJ\΍s[v;KZ fC($gqnWZ7y u-g1u[t ~AR3 x!iΏ-[}SK#ALZVݼ!FmY؁uP9j+sE mkJFa+G͌ ( âɟ3w`粓>? dl|&y/̋,ѹ̶V*pt#nK ܥ 4׸#`91[J))p8 1;2-M ܀.yO*Cyjn%y>Vi%y>V5p)Qv)Cbst0\٬'z Ob`fgݫq,JVPhv6!gMN#.1RH xDm[nafA7: TF IuPݖ`*25,pd $mZÊOY t3/jEKy@&}o?gߦ|l~׫{^.)bwzIB DD}_MGO'jʿƚN@;l OjFHҵܫOF*0ȣcInFTETYͣk-ΎI֯\˘šsä FWN\\]k5v$ԕQAFWԩ) i%33–jFQ~`)lOSZ[/aR7FsO]\Ji+"fTXoo2y%7dSB/wpb v]8]ȵ;{)IȐ SfU2ʦ͈k.NecÁs@.@:-;e`6a Bapnmf<5γmDr+ۤ}6" AtTyB3".ֳ l>s;C鳲n.wISq6oȨ ڃWU##u~uAsWZJyddTjnu+:,JHjx&kv.ʿnu**9K<_nR'߬; q|~WحnWmD6ؔ/K$`}8Or#VD8XxD.vM7>]Ka٭@c4_H~B;ZndӽmC ->P/Rk[`ȓ#*2)55e59`S6KmkV,!^7XpAt+7V(UߝS8!\1|v@r]4rbE$!ex1qmVS޵PQ޲2|{lܪoYN*[Uk6-^Tuh09(epڐEqhwh~@4}x׭6a}EJ́j#^enqx766Ҍ.\p2[ | XVM״DѬYj*4=dJ QyN$J^_(,kow;:t %km67 M-5FL/"^tҿ:;-,=B.2THA(Z֧ROѕ}nKrY v'2@wﶩpDW>O<18E/; %dn]cV{Y.Աk= gtL3|>6wDϿM>Ы{^.Fآk|wۑ4&'Kplxi PAYtvZڙ%iskױ[0oLzh+Mx9˚ߌ OX,/YJ9az!S>"OoT8彊x=]R$;B'ȡ|v!{xBQ'ФǿoF cgF8>/ q I8El,WoRw?'h#knY~%)w?;oRN"dNNCN|ͽI|zq{''βuﲏ_I;oRN#QizwJI> I|z&G;Yzcie E> Iޤ y$Axq"w?;ԓ#_=p?!?;oRNLvYz#],AH;oRNL; if > Iޤfp#tgY$;?:}ޤ>ԓ nie 5y}?xps6$;) trEx#:W`1)7 -`<Jb KX6~;+ ()iE5aU@0 Ni/WU]ٻ .1a[FæKo+|%Ŧ$ ѩ?9Pb9ĒnI(I&ҊNUc'K#fk79W}إDT7JI^~mS%MJn;>Wl|QѰykrKOYVx8ZG7[A { C *)Q 'fIi^Q"`w1ɊзFJxEr4lX󠌑w1)<Gk`ICX[O5׀\8oFh/EgRyI(=^(vtJH"߮*~m \7HJWU譓 XD=^{# APíy>8A(8A8|q֞㎴kdZ +(v8a\%T!S$ôEPr'؅'jL;EK`ONԘv/2\g؃'j}0rvó^/A>(9Ɠ$\YC؃!a"{ ~4vY/W C~4!?L;4qb'aןb#a)0 !>^)Ih\_؁~5Sql-HAy7(wU4NkLM ч`{>)[ `\))+ndiaT=cs\ Bɩ|E%$%w!ϝ7Qdݎo9Cw=%ulRMscSw=%ulRMscPw5ga4JuFճhyVsa4QմnAܟ!U/$'PA3V®*Wv`Zal.ŭc$vm%EKT c]H֨k 8;93g}=+esK }Ĺ;t]vzZִ5] ã'nwcZ'ظguFؙyP^L\U{cNP:}K6ܸnAb\2I^浢/(hk٧UxqZc ]cpW&e1qm@fH0\јԵ[EI k;tI:c[ʫ;Fi/ʠtQG4q:q3{ }:ȳ0Nȝ{>+eΘ  o .>7Z+<%PA>7wUDW"P AS%sNGzK<5rsq}QkH6&FYM0!+vҭ`ےnPKsI#y7v(⅜,h,KWk?Jܭ6[nPD׌ ,}w};+kLX3|m3 5بHJ8)[`A9]Z|1[sF&1c^F[b4+z:ZFG,EQԫGXZvAl@{nTsAP2~%rV٤a\|9q$jì)奔>nyJ=jN>gĸ#zIܧYgm0u+Ѷ .4Aؚ#'&uX}"akHȺFn!VOޠj^_aN rZ Yɠ[]p d?˅^ 5^u SԒ_HQ]}܌\.*AOv5ƒuQ|":SuQtM5E{ƨwހw7X4ylyVs? 棧QmǕbOr!U*d.ma&~ݪʿƙWvwkE[E%lTQ91l=KhAW-W?R6' P_Jc]ﮫ=E#Ƚ`5e[j:ǑAy,vVErϒʡ]9CMq>T+``NzFǵg6-ZԻOq"v)cu3XGcAز56`6^0 ^1"0u}V LYt/oE-;#'-gZkIPJʢ iz7v*yպyz7v(cίJ#*T[nVr#ݠ""7u)9b1M<ܷV-iRpă2M+ 7d,ZhmzW͔ eo{kA+iz RnoBd{!~j߅ݕ~;VCgn*(/{Ay*K6c~rqumWiiˮqY\ u)AWw!;/ =,*) /W!c4JVj,JPEAN7bg(*N;K g3ܲ:sX&=Suߍ1}N߻7];}~{Ww704pz:sVч1Z͟?oڶl9* LBT]( L+W4ly ܓ%gL+U;VmW mX4-v'_hyIVV+6-WcXб[b  Q,s[ Jfq_Gc  fo; b-v~ZgCE[cܘ[ ,7ko d :Lבi&5,Ab>y#=H+oG ǘlUǢےyYAOгF~ZO?گQ봿^aXpoj#sGYRƤ7_ic%xZMbu4ϱu`9稥kp'+Egc sT27+s8.lPD갾ff{ < EsYTZ.O.K&fpdu}ntW {5ţr.zNֹgx6w4YůAfdw tZ.oVOjbr#ݭ&?G@DD ooM*XG4|H5AusIchp,|ov;V/@+[A@e9UߒGF{V[X5i^Nq$/@AbxW 'wN0 c 8_/i6^FkcYWOY5("'Xy䢱k!4pl8zNҶ{&Vik| ; ևv:h1 ݫOpZ8̫d]$y esȪGǨ䲯_ sHKA+69,P-5īn |zBjz~05gѾWTK-dp1܋>Ws{ 5 rDh֨mms};cYW9k%pq%փnm22*r7I|\dE7ϖ7,J"M1uȒ*%;œwurHTWSvO',=EO[7^y`oޛe<7^mTW |d~{ڨ@<Sʴ[,?qb<32{y S'wg]ڭW+wjtQl$4˝`P5`q r" (7w~'R"9(?wcR?"`/9.WL/ O~erZM>- ʲVLA7dUms!*`<Δ{4AYYUa֠XWPGUdC+*cʫ 1!Q,"f!Q_ǵfPUeExE%헗΁`g]sy @whZ 7_4jXZV8̖@.,/R<^jAW.ppg6pByIAXJ8Tnu)Kt2%C# MV#v\ywS+DR,|]#Gv*sȻoYxG)j4Da'/ ݫ?tL=6~TD%s\IZ|fB[|no+{G{Q|A٘YQ٘YQyEޒ&yEޒ x+xyVp`X㴭Nab_p!U*d.Uq&~JnU3VPv-O#ʳ?4z;F^l8+1m ,q'Z'yMBATrɘs_RgJ뼓`A؃A(B$mi"݈$ |F:rFn mv|H42rY,ءN-Cvzvv -ck29\~9v`gڷ?ZmԋPڃElDa> m{41.v m LDl,P*,1-0Y٭n }u;"<8UR{\Zt`ˏHWXsoH[ÿ*9X M#js.*+7Yd3H6r.x;5cS3t^J8ARy& ZlQ 5-n>x*so$XU 8!ցS Ä=gZ_+{A, @ý_ob}\\α#k*ن [ ޭe֑`U3?ap#b1l%S9|˕\('fGT 2|I, '560/-:Ԝ_mtFrU6GLG-\,72h$F$0vWv<Z<_wtt1 GiN70K8iBy ]mZ/ X4la:-{MEVNLG!R,SXm6W)0F""-3k`INI'̺`#]ËsX5FP|\)iH|䥦Bdz8;-U`Utr:CNocAoй]EֱYS[+ͧ>U>e5k^ɀqs ǃֲYX {vsAnO}1[ܧ|nB bN;ҡ8akK\hyK*YL@x7 /3Ok @VM [ch`fΕVIE% sXMbgY-Dt3hcr % -YA XjTdž7O3l @*CW_Z",<y *ڤFzjgTd&Bmҽd kn ⠧B83sqWb6*3PHkT4:ȽJ"H'5R@#=Z,FgFPAP@6VeYV^ u_H{ehCPƱ9X"nB7EJ#CO 쇹D/W Y&=I %F~T W?A-%Vy&7<>#EfVCMXe&M9;,[%3=9kd6]qiƕ }9i\p I`$iu+$4 r@ |3#lz$U՘0FQq,鷘%niL1^̎fz%IѺ,r+w͘|2P:G2N/@S$!PEAm>`8Y ϒ`[YU6kIdqmơM& jR:\In, sZh]5\_K*`9{|z. >K\-0kɩnw"+~REkt7\nQyW3n;=4Q4ZEܥx"t%\;T ;>tuFwAv|z`'j YMlyWy@<»>^u^ ]x$vMfUTBY qǢNWn8]w^(چKP^p!=4*RnlArFMX,)L\{n;Um#+Z@Ց+Q<h5Ԟuy#h+@ ]+E!{\zո/;oX4KfÅD7iFӢ -!MSfWx^ف˱]Nʬc 4mvG*JGZvNʤQL[EuQ{tN,J&8}(#\Hܜ8, e]5.9ޫ+~$S()1z##Q^[&]lZ-nt*E؃7ZFVq9e܄lI 4IzV\.-'Fd-݃.j{JM;K\tdm[KtuZR4^d344_[C tX6Rϥaaؔ]1Zi&51h깶ոPȚK ]C H yTzQAsɰ̣J  Ka-T <7_HR '2yII7õ ANDgt\$L\~mv^z_r e{YWsX @ʃ*]-,n:ퟙ_+L(ýNuD.n7ࠇD>©{P?" J7ae oybك`魱hvuOuJ29 &I-b.7ңaIoRӍhRDݖv^oRӍhRDݖv^귮w(+}ծz\V9&D&<<+:ݼ˳~st]3~k) YNqԱ0tFKCȕ[dIi.c p \ZA$`e5;tw.-`/㤆<M컩q\i +g{,2cƶq<-:*Kp":gGl9KHcti&ʹd|G*7wP,UJNZ_YIf]#|=y.s ͣ]5x$32@i .ߩa(i,Mqn'Xϐ!4hSMhacXgL9i~kTcRF%K#kǹX5WngcقXO-˕Qfa4 Sq4i^%>̨y:E#<\04 |Aih-%MMD{n)h -mOBhɧӕ5 3-&AeeoᣊÔ\>H{ W5v _qm[ZZ,@#QxBFzC֝3wY4#+9:̀li:Z,s08$ G7+5M`l2FzC֩zy9ApJM0|򽆻x۷θe>>'Emv6Ykᣌ<2Y#`.͗ Y 8-6[n"# 4ظ\h_η3Y~un.@W~W}2ʃi2Dmխu#y%^PflF9K.]ޛ~~5̇3.Ϙ; PbbLMX-h0%v. $F![<'V( k]BzQ:ŮӢUȦd cl! 'm l6͗'|K*'JckAsC nU6my]Sg~]C/["c1# XV* |pц3A,ȝ-Ȑ5\֒m`t{p\8s+uԸ45Ql188l@:Y&FzAjLЅ =3&}t669(IQ3*jjwN<v-f,Lo<}fU}9GR@r@`A,DH9j۠x!ԏ ww'8N[na` ?|~|}1j 9GRnV6^˝`~|}1jtb Z2xBAX'qȕͿU66B%]ckidMp72.|7xv>\ ^٪GK.MJ~|}1jwܗ)q8iZHrߗC41i0Ǣi^|SM"um7p:`T2pLMX<.@~hHzU@23UF堤qcC?jQ^R8$ubMM;Ix+ݞ^ouFzr=}m\ܠ$]gotإH~LٴPM5ߨ[tcGmQ+n5e2aE]9ьr 3؃EgFzC֝36N.e68Iۣ&9¬oRڽVwmmd{{u}ߞՊ֊׊ЊъҊӊԊՊ֊׊ЊъҊӊԊՊ֊׊ЊъҊӊԊՊ endstream endobj 1004 0 obj <>/Filter/FlateDecode/Height 101/Length 10567/Name/X/Subtype/Image/Type/XObject/Width 211>>stream HW{teh6-Me.4ͣm AA^bA@Բ+ u^*ˮ{\yEPZ|3y'ͣyL~ U\fi= 4}{o4*ʘzz^kjұZe#ԉ sRE[lm[ )eV}s׍~Ȳޛ7i9_ ejE[, ,-MM,'|@~#ua|Ō$5p$.yz`Õ#f4hOACtF ^3/|Z4~Y w"k髦᎓["C€rtpH,Xώ'UL?~GVWGvL[<}ZGO}m?sD/3!π~obi˳ J;H@Z zn?{3S//_m T368 t) DvX/PGHӖ3px=C,M M(# y00uB`1?`8/k~|'Ja#dW?Pccw9gDʊ?8F[{.6\ܻgwl.g? 9%`WRb)P%xbcBa˨i$!uw~M/ledye<2v3Bt"45?tH@~hRU7G,E#Ȕ;o%{NWYji͏VFn}M2L;]6>,q\`qŒC')Ijް "S|Yp̬'$9`eK08E=D׳Իıx6"& CDFTbX.7\'a-"JH8 !*ATn O/ޕhԻm{_P. dDoq.V Wk62kkro 88v77Ai! PB;(p.]򊡾αn#׳#I-ܑpDbӠHYAmkf9nJZo._<~ye$,r=[B s mLڱ([ .z2* ݡs H"aSA 'DRbp,X)pRя<۪? 2Txm"?oԹE }fm|epz qox9LG9dZBRhVۺzK笷-9^`|ZsDBRt1I]"eEHS >*pBpy N #92;}GDܵ7I2nOG|lYl9>ecNۜ{,#fH(/"` ESBW߰PS3,!C6PE Kmv[l[>)̄H%Vz6؜k;/8f&0d'w! 8DD wNȌB^Zt=s$V E7=h<ۤ@iɪp \ 5WY4"zU7ms/=p)E( +_KCgKzud>Mhn?Rig؎=s*|ot /Qyi}bgq?45KpbRKy| ݵ|]8Zb/&By͞M(O\$=h"ΥkBvg$}X5۲1Q[mEGP}WurDt #6g?mh$@o|r x1\6>ÎdDm5p '=t8ʢ+yJ/D ;$09+V!V! R*$ۏ?M+SXVwM" )a3BDẀ3ft՛?5h5JWT1@K5(SĎH⭈ꂰ.N.v[LyQo=Sud^cRi^$] n,8>ҽjXy޺z)v׋UZ3,%QQR5ip2qmj9íٗ~R_`)I4NE#CNwLFJ1} 5  _5X&L25t 20kpӁU3u编SK&KRFw>iǣLu"z%#Mt$+Dw";"WlSʪhT:KZWOez} 2}c1ƞVAS tn4y@redi_6'жgQJVHe*5؀~H7U Ǘe6H \v_6Ɂxn@$:z^B~ZBg\" f#DYQ|UM Mjq8nxŢ+R>".{\/mv"\swؾ;(_iB\YDI5%5:Ywˠ i"XG9ffw< Sg FN4oc{t귝6VU;M;9rs$8v׻c4)MOasamcrDuڰ=<աL= rZ8ЃptڈZئjfd) $݀Cxi@Y 3[O}Bc`Y:'''<`i-rm^tx,proŌOi<.ƈod=8b0\ :[W;ox&`2y5jGrPq eIJU5WU{?Cg0ᙎ+[w<5G_,Ei*$-HTVtmT I ɎE+Z~@5ufq)ۇ 21bW8i[ xPаn&RKa rӸ~gyoP?'{W빴yΟ?e5s;xIw63so1>ia⺹ Z2:;p"FN]P0kTz S>XeRY$=qyg΂Be_g%/zY&b} LQ1Te("G#b3 RŞ 7Q~ug(gX<#gs@ @ @ @/ɰ򒒒2B-GsKjuvvYp>x8H0˪ ve%hkDk@ @ @ v6&"'\1&V7xχ2+H:H i"QksS C8FJUw7iϋ*ox~ vuvqrtܿwy G]\>ts޶]-!9ms?d۷g㝟{qf=j0 >SLyt񢩡]bLStdM-*jE {@>?AWSkIp VGOź/?'O5z4/{Et'5%CgmY7|oR޹X7L  :$7|2cyBhh~=kxl +.{j\.wՊAee_rŐJ376ad g^|y 9='$;+zpPO?|~k32Yf³y1in/,NVcg QY5%,Nvm{w6 }Wvv6koomߞ؃ndfvğ{̙3gx[{z>x VUXq=ud!Y?*,<}s.$o6UVVOH8oֽ{>i.dni֨(EF^ `p#)[ .MBa +?^NC7AWCKO[guXX]m-nJ{fH` ~F$ _; |˜dfzrh@%?maj_7z ͛LO/0 E>~*2 Wf߶*#`_^^jk332E'F]^@J]_j};RZ0)՟tcMWBqiJI_" ׳wMS!Y 3cyyR7rp'ft2[.8l[26I@pF> =B~~X,Y 2300` !AxX  +Tc<`͌mZTΜX.7{[#}޿xɔwslֲ~Z Qx@ (***).*8lj^#0)r$t眗/^% @2EBFEmGJ񝓳!3n&xk\ jhNy#]Z§q?ֈ] ,Wnp86jdӀBx‚GEIIU*t\xO#ʠg&rd\xm.M 5+&z:(j%wݽ#e 4[;p1"!e1wO\~yyy`ڼi߁3dvx",6v|Fu{x-$;gLsOXI;ɮy+d\W[J @>0ȡŰ {^$gĂU%G$Yq'SK(GFV-KIIx4~"2l OԴgW،  HKtéq2W;(P߿t``ƤǏ}0$8}q_o~E(!4:Im޴ BwWOV-ڍ' dҖ?L5/a8Dgq8gW2'm/o:2#$]D TԧPX9򝳃c/h.Fπ<}]K%Jw"_VWryrR0 ϕX6Jk f82,zq!SR[ 2322 yW~ZĐ!1v !4UsuqDB~~bmmcn:;:i/wsv3MDNZu{߈͇9Ѵ5!yJ L;-$9(y>#n΅GYi9|70d|Miki}A/\ÏpLƐ*Ο O6ܺ+qHZWoT`7 E !s D/a#ۑtJKK],- ڬ){CbCEswAx-]XHfՇa#Μ%[`{g6qUCq97( ?fdX@ߏb)Ɔg?iq55q780jW ph9),]Q\޹zNv[Pz-EwE^noRGB&Wc.BbFD\謮<7Ӕ,_W'xh~~ȃJ=m-wqrr7[HYR}WEAju7ߐJf(]U|9ڣܰ^eĪŅùxx^^@;IcA1{g0^գ7Í ǎlT:4¶ZĀ&OpoN,_Ӝ;N `oX3AyiyOš@<1(v{TQA}(7MeycG)hPfk3A('b'%9ӋX x5EeU%܋k!]~mo@ݝ4ĵΪ+,7o nWXJ*bS595?({SUT᧡mV;ؔ48Q&ru\^_QA $UEej˒/b/1!a ʷ,N(+(׋XM]wL#h68(HEQqbU+>Ǝ\-'/9ߐsEIo-=P2>Fuq5f}oWƾsɅs)9#Sgܜ蟢vPNB2_עa~Ay9RrJ25A@ vP 04~J@084D܄B~r2~(NUUV%%&F@|썤@馤"?99hiiHrj`Z8E Kejkj* L%!,*B~㤕 7oHQ8VGD@vuu MyG022r5?1uCoTp٣#j掑lrN.x8mᥒIr$ڛ}=9ɒ2&]ƫ:Mk:~d}q9uT3JfHK~?N.ݱp۫md&NYhlf>)8J f|bNGfx.D>$*; (3HQPL[n`.7 endstream endobj 1 0 obj <>/Font<>>>/Rotate 0/StructParents 1/Tabs/S/Type/Page>> endobj 2 0 obj <>stream HԗKs8 yLegSqi&'Ŧ䱥MC$ͦF㿻^=n+/Q%5rǃCW`f׷v@rx4AS9KZ7%:?-[SpŠH$RBays_e^`2zXf 4 ,hv?JP:k1Dّ>3'Xp;Ú3$gs)RP5GL#EY6sU{8;&0|]_74XH=gnB1Mkn1ϲ/y8x0@愡g\:cLLyy*%9Y:&M:}MN1$cF0Kf0'c{`.y90r1̃i_`/oxL tv(77 DIhO]Z yc7?K#u­Ê"&Z+lFUOKˍ 5fj@WwubND& !';7H`R2W:YXxDc +nK?HTJ;*1U'+KSkWDq3犆6N8X0[q6} G xi 7ᄆUkFi@tM it ,~1Jc.K w)Rݙ#՟+9K)*csYh'{~̣Jy ະë4rL|jɝ6k5ξzZN6Wc(DX[9^PS ՞x|nn^I_|iݷJ7Z5^aХzCu U8AZag=ܢ)g9pph,j4U؂_%c~Ϙ>'ReYa=3&I>̝ЫBzd5%ʃ s;tg9Ao|?U+ï tl~K6-$e+hB(h[[#ZaAI鳒 ZnC:0(NۨJ7T`6Tp@z|ȵtS"uaP&قlVG/5]Z舼>Ic)Hl L =hQ`` `3J ( Ǎd4 o ن33(JcݴfkKT;1h~gLՆ&d|DzD $"X3D3TڊDvt:ZX_{|kW Hk\l)x(Ülm&Hz)bC)b$J_2Qәi:6uT xX5` %ܜ'{xi:QvYB'H j*vŕ3rUmR`j1qSwVRAWI%K/o,ij s:߱7t'CLvEe@?P*mԱNçT ?YI; k/|oGvl@F%4x*u+Gt ^<+cq9.e ùq|A D.5c] ߚ i3ʷA:h=il!贴!Ef3 礖Œ칇['Way#z!.tbioR-`۠1 Ac{!Xճ^V"TY7ϢDb;UU8Łʀ泴g튣]:Vp8UOs+_=.=U [rFVaVP;d%`!'P!&A`3,+[Dȥ³WZM-#")JTݽ=Unگ}K.TIRm!W iZ0m>Wš2.%r0ĵ8ϓ=؛O%O4)@NP)j4aTT !X+A>;L+j0H*L[ZUCnUHהH_ dy雮:LrNtdtJSƶRETCADM훸b/FI|p! 8fǫd\\<{kk?qUsڻWZt`S3q{ZU:VC̪؆K;VV#YmxgJ!w$Ra|,ƌ}؞Kgbxhځ0q,'ge5φWjSd`ɖ ^xj*hnM+@*A8ˁ:.h1(}f gl+zhRXY'qJpyaJA+ɳx:]!V эUw鵛 ,?M=]It#Oz+!dCz{PVeτ`4xXdHDAcILj _XpFRu: ;[Y"VPaS3_UK ae<Юj"УN0YТӰc6ё;ǹ\z;/4: N~1<9LuDS*.0`NPS&R=W$VXY=ZȢɻhV{,N׏#_WR<Au܁hfu }LiLHDKR_j̗avIeX4J6XSoUnMb:sv]\*9W+y|)&[&M5]gU|>2Nq&T}5m7-c@tzb*.tӘ\dC$?sn&1)g 9*@-x zs%B5:p6kowAƁ-W~ V7᭿*:f„vqpc-HVCWJԞMSjc!jTU̫;}g.; ҠY5'r+‘엣 1ixTILC7HT$|eR)²r3Bޞү`8^nU;m{yݭGvey}tiÊZd0T}0E`}{o/3ٴۛ~4MNKiSi ]0@QSl7[{^sfǒjzOXz0s׳'khPbHchlޛ;6k,hl$ >y)eg|np ־qxCew̽yɛݦ S.@ ؾXm[JjLw=h{d^WkǡdEأL>-?uynuJ5KTZ+ +HD;FzkYCo79ʵ4|6QCk/j g+@K.zfTef*SUpB:/tXƯ31SvB<7RxLfGf 7;[ֻ*'b;!L:l5}r7א|poL#.Ms&Gْu֫d7N 'ai))|b D}E͌mLJ|%>,σ$} |֦C9$',= $qCdy@cQ"OvSn?8Rbt&oj !iB7yqx%pk;7ov ݘ\ux_T|b#ʁr'5M.Ra(_ ?ʧ&1A< r?9݇NO*~3(8 Ԑ/vr4wo`JԕͫZ0R[\os%T ȑ"gK^YbU-WwQ&?˛%%y _@U:i{-u/1 +{x0>Ie LIqW'#{}_>stream HԔy\UD\y_xq!I]ArYA% L l1KgƽEk-#%m\P1/h3<{={D{kwz[LLʞ6MAӓ'V8 дљUU@WSO89SR|wK;NvdzfΔ{twnIFVrb )\۫3d;F5{u=.)3u&L,Ȫq'fjTk{! jzT(%c2 C CQ[jt~ mP]èXkD٠unإw 0Q_[g oԥ6j{S7SuKlmrL@>! bWUqM\7ďRm1P<#;ɧdg/VABSĠڢD'tFO ` p "OdbFW  N(0CE$z^ i%CT,81K,/BnHD&Iȃ)lA4HESiRLE;i7 Yl b1-EbXOdUv[e_/~|@%tL!Svy|Z&t1F ֧oz+r$1\CPAϐ+DHUbHm ġ5bX4/iF°pSkurtc볜'∜ڇ ;*|m]+ :[@k5fhmX'o-vkOڝx^bgq#HppvplrNv;NLrFȉ\p._WkmWb11[llqOVGTNSW@1ئq*sj,X -f%W3ʳvZSҪaj58Nng9v]dᆵCj4rW3ҙRƎYY;5]kLՄlڮUC5݂^MKwzBɸ1-tU{篺 kc+V8P_:,,€3Pit5[F+Tѳ]h}{/}d1J C ժ@ xAPϹnJw>}>)mkem[[nk6;)k5yu_enno#fYnVjrf} ;V5+_hȃBכ] JDW_db"~wRtC#[89Ś; $4b3jZFlSKLL Zi+5oY[0X֮%p\7q4ss5u4qe]iz'| ~ TF)NDIQpQSD3-?hIQJ)Q TІF4OP&C{S4h<tBѝ+MЃB_}Knc(aRF"EKDU i 2h{ȢM`<} ^E}|:tV+:<_RyR}W@}UgwP}r:JU/x:.RuQ.%^u2 TW yH]S ^~ժR5ϩ[KyymUE׫EU[72x o-,V.3oeƞ7⿳7}x;`_6y'.ǻae={>>78?䆼~nqCLKF9d?a'|#3vq1Gܔp3>͹q>AI[p4~OܒV\]_Wɹw{$ Nqw'!BA[Z*@K[juݺ`%F?H|fP+ Aa(h4 ƒi4 -A *h ڮn{؞mؾ>ʷ@;CP;#H;*췰?hv1vxgmMI6٦ߔMi6Nvʹll"$CY"rI0TS *I4a?;D@I N*C9DJsi)QFIa.YHW@K).Tz@@$e a2\FH%CPDKX'qPV([+*%A$YR$U%C2eRhdIL#3d̒92OY$DIJY%kdF,[e쐝[~J)Ji6h۠'t'$DDJ4xK4P&%`BCg>pNi89p. {`/p18g\p57w<x ÇbUaUDPTYUNWTUMP5UmUWW T#D5UjZV*JVmT[^uPUQUTCUQURUuUKuRU[*\5rx~#|?ׯJ?߯ jЯZs:دK|_7e~| ?gHΣ;`*c]ûx,Xx8| '!NÜG8r*4>|'ISSOgCz>#z>cz>z>S:W֋DK9Ly^/|}IЗJ}E}]7:}S׷t7;z7{zz~X('ޮ~G?vi8 9KrZLy]yWѽ* }調Z㪻ڮK8tN1:Zk\;u{O!=u=\ou=]zF zI7 sC7 wCHҍw.%8\ 5}E7s\UWw\w\vi.q%\1Wu%]qWZOhmEƮ w] teHW]UqJr$f .\Be/ICfFJ06x1&\B >NN?TQ @88)yݳ+$WvvfׯU!kڇڿhiM'PF^ZD=NYmWi,==mV9Վi/jWӞ&BHhi=j.j<=<4ErI[iM.eO?xZ=-F>H7t{}oUO=JY)+c嬂Uv/c%u-WMlR;ej7v+VԇqRjfV~2u?갚%@ *!%$.&hadH&l b,YkdY9a B-fͬ6֮RܵM=dE*lRIf9tO &YJ,EVet夝Ԫ[b-%afy";~識~;ͫ{$"Kg!bgث5:{e؛Ouv smwqWvwWpqr׹CJR+UJ1f<= ;P:GMfd#x:'b#LL֗::?tMMe~^w -c'^9ᗇA jA',$1qφ_jV \hZJ75xZ$a <'mFlE7Nzzd$Jtz'XK(/rSeF4K t:2Ao\X&c\A5HqLˀa_ b=n|Ŵ,#!4O,fdxV_˰?u'S}MѨ]v(\c+>$V2Xça ]`U))TnEE\z, _F9323u0,fJ>-R7|aZK\rF9 sg7zF>lT7YrB4*F+`n?3 F!1=-CE@%z7:*1Ns>>NEnbQ ِWArsI.u5,PZ6M-vnAFG`ԟoqƼZOMmi9 LUܘ]5i&~q݌x}z<t3PzM,W-|=iͬX[m-bIФ4p g eWK&j0|vCqDa+s! $Y`).Ԋ@BRK$!qjP9R9rB?lRQۘ#ڳK',qTl%FmFq<\3zÜa ]wP*X'SL+RTK}0m7X\jxw~gp>Ջ;t=H%EcƔ6My!z(y@##Jaor>`qTLjrqh0OgJO2&~ Zpxblfڌ!NfEr{0򔁪TBjHRRo3%^ykDZj2VC VOt[D;s8S PV{' (#"P$DV66W@$KLkLԐ& }E8Ė:&5⇝{~w{( x:/pr9#TS"oZd) ${Pxby'df{Max~FUF:YJa``(wP1Y&˴?bmǮ9qolX>@j76Xg5-~ 7оMEocS8_lXGM= 8pE4~]83_RKvZC=| #FQޟ2`oʌπf+Qem8%sSx #N;Ç"Շ]7r5qFAqf6JEu ":!r.2.[`a8 5AHzFPYZ735o\eYNyM_qAw#j`7(zqey} jоڀxqĖge 28pYi7RJmIM=h4+hFP.'U>ZivbaTUR3Ur䳅{Ma-$]9+v@X6fg[@TmJl@x9P&j/c(Xc-k(xC?gc}>g1؇ ƞ9TS &kQ\mB v;{J٭wM+VAx u7=`f /Km^|YŪ8D^3.5 Qs5&C/{7HkoBO y\D[iLL!:,Nj[Nkңr{u}ZRm_BJnOJuI}QԢ֒d=MA<M¸W9a\ B,A+հ 9ǻ U h+//azIO Z}ǩ^?H$F<)L}"- QYH'y>gO_Xa貾rpy뫷7nOw8eSiӊPo1&lhIF(l6XID4]hoD}gaMnlcNIꡉz54x'-5VC/CN@/kgxvj`+F؇/YYqiz'r:=ƿF}/ k9x.2ڑڥYFIX?5A(A애*I?x"B F#T.fC 9΄:'7K-zGF,6TAEGl~y&J.8P{s@"aG4?vޗ3,W\Al C lj2;2|kqFπ ^&|" 5_QA^jyv''!f&|]si6cO` F^͆k82Vq3Q:0Sk<$d~fmߟ;_RB/anxOD{J~Av=Mxc5N|W*rEUĸ"D=roa@ t)P 4<#D !/S!+e, gKrKl0C̆i00Y-mjl1`tld;e4ɆPS0s~2.=##rim1d9.)֧'O9'99a)0۴*w?}kq.K569-q5o^RңSX^P>c`4̐ >/d0σe$ bٯp?L'wX=ѳ^?j] . oh1-X&9e8w~Cs]yOX6)no[toI䰟Z]q *g3p6(h1T1} d[U{[>hþ 8 5ZO|1Axg\CI]WfP|TϪeo,-c}0ށwr_Pf %T&XCwM>܂x eskX͹hzʃr~]{RHޤ8kϙ?9j:9T;O6:-kl؝)kͰt'ɚȫP#Q<ƷͅĜqopȣY'3_&}? oI69 )xK3fBx}4Q-,`&YWK F/r [0,O&CD<4[]c^K[ MbVV#Y~{UkiY#Gv5c6ƉH ެ-/8L͸ zJ{o˓~<-4)<"ǥᴤ(rU+FLPH SbȔrڰ3 ?'l-6PZKж1؂hr1OM}tNg~I9snL&57v~Nc zI3zўVgZH%%. U3>w@">c|v㆛6I sZyOHXbnڷwɏ'ާsԩˢ]_{X\c|UOa#K7G?{G$>E (ll;Jbhih$tdFyQucsy2 KY1.ZTPɼCM4ZѠ골~s[c Щ?RT*&V(jދ$<=^ӶI,IVXæ~2p$ćdSNçkbuJzV Ƀ$;zhq&6קxdy'=ey~Mo囙Cu<x rS~efOrXY99qFՏG` 笟5k%}Uz9g ,[ o|7r}g cvWQkl߈\HIҚ'̀װvufWR7>`;} AQ)36h6amG V@0kt wH47+1U? E.sk+;X1HnIŎ}n9+lDF2\$)S?|l%Rdg?.9ΖV 9y/Un:|#/>/sS Qy/g;ltZmo!JN*4LTŊ䋌3|e}߅g4;s3ۏ rGƐo撻MJ}Qr%2"r0c=AM +c::O{*q?nqHG|@=!Z>a yB~VǢX1F}f}ȗ mcN>Krsa  yҧ3otnTaq)9wB`O N gX)6g(jL-}2b/%sq?@Yl>ۇn/ W6<; '߀{_ &IEtzA_|@rV!?0S|0kI>oi7uQb w|z4Urs5RqWԷjAUSx{W'\aN2đ2lJ촑5O$ȾmԾی6ĥ%?\{غ{gbKwX;.},r4\r KL) )S~km~˝،O"AP7LJW%dw@2Lw:m=F ;7dSGC#1Euu:sd߆zh@gY9gg3saTyAEɣss0)Th9y9˷c igQ B B#(B!@@`RDAЀJcQ10c8ТRuJšS[ Uf{}ҩo޳ݻ97ș˴l 8_/gCatJNP~1zZDOF_'Box-Yc(9Bpo,΅C|U%Sg)r4,3~W˝~%yWCr0-?>}Vs'JW#%˭(v-{YOل#M_}_ȝ;%s/FCXo~ty;ʳ zO/bEj;}﹙׃gyå̉d\ldm*|b4Tq''l(Ԡq[}?5.; x/>(?='٨3ad{ }-dxod+/FEw`G[!["[с}%ȶs!1vp*5&~?*KokxsyvFȳ騑qF} 6%Ԙ7}i;DQ W4WkZ4ԸiiUu&C#p?ΆkR;,Քp޳Zgik hb@-ǽ[W[%|}6 1T ulr\Y.0Rd:h__h$w>j^QPI^6F|UraPT@%mƢWiM#13;\eۛajou/oSv:X8_e]s `;fh,FYXt kMpYwcUǼa;S&H__jgKZVTn:n"OnJEAbGXx3\l@x8c1{\6f-f\ ԧק5iN㟎;4Z+ؾfpm#"rvFPgYF,3հ5uiB׃W[N͹z7&]kN3z9*g8GJKU~9~g\$C5Qt_>@8q$ީLLLݑi'*慳3!T9tO[Pܝ>}{ԻWcv}Ol*̓| dkK⼂{!7u?Eܥ XwLV.^^"wurl9Gc|%ĺBou}e#)ger-W%rK bsdߟw'3Bw:\z%2u<BA\}^cjNv)"AμРJ/5/V*c]tR; `̠>kTW)]>dۤ[]eV0Yf?~-%rnPT}yu m!Vayȣ!7>3 Ďj#bRerrcbe?ZF8z%1w8&f66zAcK\5frrayܠc318~"~SFx_ ;(8N Vm>\5@JҙX)%hI?՝Z6G;j|.ej389<;)Կegdf/1}~ؗ $l(Tu_mjcn?F__Lq%d輭&JjGgH>]3k-To~Nz`S,<|tLR]ewk Bm˲ӨJySI'ymJ Ja4rLN|'!/yAta| ϓUÈU!K~'HV'13L /3 'Yy#;w?U~.REG5S0g\s:lw[T<zގC 3:M&?V'f)i({:deJWF ?c3&^M;7,O+P`St7z/|AzNW- ?N;&{b/r2|i_vD 䐘QkVxJH[g1rӖbYLs#r$i_ݯ6reapzj<N@n_b%1[b̺O49b1Y-S,1r%Ww[nY|2&ò2be?RE",IfX)FK{e:3_|sVݴ3NrgL3䛙4 ΟdE2R5231t/GsEl0:tQw 0 M齚fI&1ޛ){o7kuWޗk:FĭjJo;=JEwnvH&쥼J96wQURmp*ix zVJW{BZ!Oyc.!TC٩#w!*Iyp?C.6UmUnyުUbP~U#)U2%P U4YTǭeLZM+zy-YrBɜOvy$ wȾJa@-Wea\'J{| ՝޻O;WKkY@?ܙ|_Yym;[ {K r rgy*|E߹F!}5n6)VzRwm޲,௫N+=U>oM/PPe<|eU4|߮_C8Q× w ;oGT(RORj()?RI,,(2J)K)S(|<\lJ!222222OɣRP&Sr(ٔI q1є,(J&%2222222222ҟҏҗNCMEItttttttt)J2%HIS(m(IiMiEqPb(єf(JJ$1%N h >K9C9M9E9I9A9N9F9J9B9L9D9H9@OGKO)Q~BG)Q|CK=)Q>|BMC)QޥCyM)Q^ByE )Qo/O߀__'~7ט ؃-ci3Si3Cc{|xx x[^k+.| ,&vb=<ؑcbg X}{vp7p ݊[nnM 8pFWc*r%p6`]\\l6Gpq 6W`=θ 2kk`5 W `qR` P@ bڸ~\V@Xp(Ó(b <|sds quh0;o4L@qfr3S3=87r [&Szx`&j$mkYƹV0ʴ+2J1fh 8@%`X5tcoqmp'ޡu.@g8R=l;27nIRp.H ęy6&f pN5 8h%hͰ)&&@$;ag&Á0@*ltQj0gSOG?)9!9.sd2'/;:}/i0W(T4NŠ@?m J& 2Lٲ9T(CA\߸=Sw\;|8\&UGa ϸ_s|>uP0~xH}h>wx^Tacoc]0v8}[R&^kl [jJRHmI*Sj6b2^:^D%bx>BTkj=,h +˱ KMx{1.P g>sYU{z|랾꡻t7H }|^_VVel;+;:V}/ WFV Hsړ`xb[]glL928}Lt3*5npVJ>5?qvܶwsw[;7hyvv_(LgJ1۫1T9]ǖU2Nq:kǝ*ٌjm0w5I]N=nMD q1jBRT\s%<75ݥ[L&ܢX1Cu+RX)fX`nѹɓ6Xf^Alafa0V012+FBoqY s*. {H|o¬?k{zq !.OuQb>q hDQQa(<xQp?z=PB> |+r9Fg܃ :#:nm~]wv܆[--qn hMuhkq !UW #ґTHI#6.E-\5m0!0aO +~8#~i|S$N|88%p>gc|^Tan»x;o-7:^vlVW 2^:Jb V* ,2,,XX0030,x S11 O >stream H\j >wٜ%PrNReby6l*s)do݀@q;@ڂ.]bqi"w8=8YWȁf8}ކ3aK txg^삠+v!a{Bhk 5YliFe̓T?}YV-ަxBm̒N(}H)&,#o0 endstream endobj 5 0 obj <>stream h4kk0࿢->ǶlI@Wu!\O$fjdZGc]d*XH)<2R!sX؉8Cf!?i$dlB*d8x< 83 (2p ECP4 ECP4 ECPEAQPEAQP%_ Cߴ.}hi=LD/"4T>migkO4"O"mFE_J,;P}ΟjD&բ:eE: _ [_'Djz( 0$c endstream endobj 6 0 obj <>/Font<>>>/Rotate 0/StructParents 50/Tabs/S/Type/Page>> endobj 7 0 obj <>stream HWioH_ r0ڃ8qFdN0-%Ŗ̿:&%yMM]W;7Rx1*δ*R3^/Z4b}l }8nff>{{/vBϗ⺙|\H ]*M﨩ve;L\}+|0 kq D Am>mA(K^\>>A-kA=+N@LXO#25iHLc6bC ⤄Ԍ#cLb̬81w,ͣE FD-/2xl$ :?wg1nqF1T}\&ZB7NC|Gel$m%LP/!Z OT{ipnR5[_C +R?exPS Wi).iq7Rv46v$vXpbWH8BJf T?J٣QI[Έ2F&*OWqb4 .B@ h૘_KO\'sںCueZ =(2@U+1XpFKn.c 7:y^(4=6p))?%$ vk yAP@*xY L48⏐pQ *q,ZjU1DS1ydbA x/L( s'X(}^;7Rj!^J}opSvy#y$NCǤ4Rd )QHȵ͇^Ke׀Ozt%Bpz '/ng'5@I۠Dd4.cS,kne0e1gډG|`VA2ʼWA<ӥ\ʪ5 dMRշ}:we@W*.bǑo{EKMqa 䭜isi֬=n+F8AWܵh^ʆ~V,䩃dTm Z F8Sz.䨀}s `xwÍ s35E-up iLdju=@kox[RsCe\Db?XBoDKA)K؇oxf6$<0Pjۆ*wUio!AUp)`גVH҇]<8vEC ֈrxn`E\Q4  fːoNvh`+,(Lp)yG}Q!?_]Lu[s1W__Tm뗸j<׾݅Qc apqGM3dz>ic+GL OxN[Ďpڶľ~ :L\jGOttb=n:>y Yljy-=HϵXtz㡘Z@ KtZ>D'S:zb^k;[;{=w-Л2ީX>+D bJ݄r"VK~BZ݂_MobX׾BqlԷ0خhS:d, UNYG,p֖+!Q\~<緣GJs,5䉼,c1vGRcK6lk9` ?=ovQ(Au 'v7P{;8Yy::dKډ3筟gvYo2|ܺq69mqL~:ӐUUˮ󺛜x{{ݰlM:,{]-NqyZ#A,(|EPrJ(lBqx,hqqsDf1~-nV-hF5ܐ$}P z鎿 ?`,D(l3Tc͇-v'&?3Ҵ+oh/j:d7SJt4+ͩ '}[U%Rg oFq}F EfCE%n>|şa`rS5~SP KqgRw 1L?E i ٷvV#C\CAbCA6J J65fݬ:u)t]%vK2fv9(YL\᱋C{PVt暡CHkF{2Ms4/4A}g%5&{$C&Qs~ԝ&Bb:Ia~a~a1cw(U8Zv/7͙gR ;5)Ha1O_o6<=o'M[n@jENQGs﨣B0y:Ig^@h$N1A??Dh揌$F&MsPG$}iuL;7_vMT~X~7g +Rʃda ~ex+?#,MRʢ|i%B1ʎ+Rfe+5HC_Q|o[=܁{zbhk U[ꪒ%~t/L=}i|]Zho*Oi]slI8b k Qp#a񎶖cw9^i:]Rj#xJd^ nRBTi!C̖ jl͵@b](&v\ۤC*ӍF^[|od*ٍw";#8 gH[2"آ?z#v|fh3]c3K%Ȃ`6\U_$v)v$D3ҮjU7nIHˑ1m|+<DB.4rEY99R,xiˇ,1tc}ޗ}-Y{xǭ7VPUQ~tԣچ.޴7G;LNLJZ)N~GoRQN"Ndm_:%n.rO!F&OX>joOI&!hw5N=R✟cOuIbFJE\<`|ø.2ԩW4!dFV/H,Ҁͦ.O "4<ߣ~L]"WPO:zOZB1kcp-HuteUTDц UdQĊ#-O9SecGEwI;/6HqR5nfKLl9v9&x =^N|1PabgI:EA=uu MsZA T6Nl&#M pեu=@6[,릷Y -E2 z67K&lY%2QD3!@ \rRr,hWZc+NfNw Ɛ}V8b*]9D!0AvzP"x ( ]~p $g$kp8 y:xπ6~zH\Ie[^-=ySrB˻ D endstream endobj 8 0 obj <>stream h, 0De%1ј"=UI[z5ZJU$EM,̃Y@ "xLx"+)manǢT9q3^٠ Yj%Vu)N"j f)"-֟΅sx0ΘKU=˲d߸7'(4 endstream endobj 9 0 obj <>/Font<>>>/Rotate 0/StructParents 54/Tabs/S/Type/Page>> endobj 10 0 obj <>stream HYs+PL*JWފҊMJ%H,kߧФyHep]~ksm>>̮67%X/O=X\VKǧ'drvYSzXޑ| NMr9D$Wyʍl{S.ʗaeܾd6gq21|Z%R̟&$?&)2?ܙv;3Rp,5R% SO}iU3k<gK /7t~D'&*Izy)a_:N`@ !=1:1pE^pi´t@MC+Z1#1AW25@IֆFMl$ bYsF(HdtɣzL5hX?+xW >\:aPSӗ$O%] ns P06S_rvᰮ @T<ݻk54pk{K#ɕ=F;[gb9~,ÇpW8Ej5'H-n\=!~O/'5aPB ţ{uw(1aFpGPP"A)sS5׀s|mB |AKW{}!kxEj!⊢{w^}/C&]0d!Mq7hUF'ʅW|3L!K$'7k)vUL7~ _G4/Ͼg(ըqlf7aB wUNb?A֩7 3 YW(H5tH0%nmZTAɻ3^2Ayxp]Y|Z4эҖEl?'@oEKW] j\@]D B3O ָw>5͡cZd/!cj !4mtn[ۅʣsb/^w^+!p` k#f=Vt([<|UkLNw^ =^t\ }FKn # _Y^;dGs~\e|v ,pԆ_7o.aS?HhekmLi㜲=M3<\[ "5:lt6Sm&tΪ.=?j׀pS5 y 75[nx%QK5ÄAϓ^ P1-cq¨`:*zǗps88] |>merj[0XM kf-ͦ5%VԒS7fMLpi+˹'v 5٫uw8\z{ޙkK2͡KsGYI"ZFWa]x>1wvK7k2Q pS+"^g'[n7)^mv#:Ң\{ <{k 1``k;24m! }eA,ۙj?,dUS^ZW쟉FVX:kc<|2+_˶t=tjr"mIgS=N8ٛNGXs7(Myt:E#Ӹ #o;NFSD#{c#ɷ㢓!jAŗlm0|ϯ裔$oʽrj{cWtlwm/HEQѴ H]{؈@轙19BQȿl!>BL<€Aa(=>sKſ]o]Wo7y.$dvւJ&rr3 hGDBj5/"\ wl^sB_/% ig_9"EN(m(f2/+< .*F`Q{.K/S!rmv~# OG,nJSk"iTgN X]+˽ڬEP#.숱\a+JSRcRIR[lglS#l.\ωQ|  ޛdHQhe )Ji103):YC;u #}7*]Y[Xzq~Pl >W-VZ59KuћzQi[aaaΤAt{=*O }-/|9Ĵg՟{F@轙1(9Eȿl>EL<ŀ !|nmSRֻvV -+0Ǽ]*^SC$Ms>cQȤ)+0rk=n.? /xoޒnƒ j7A{bpNt=AVfG5#\[A>QbXGE`")DbR>ZGu&rXLvZ].f-o#SO&d>\^"#'/y?g:v3ׄ]8ތ%Ǧh($'-r oPXs3df)l>?=ѳ&=8z'z]z>=_E)*Wu&e$NvR~9qb3zojDw9;ҝѝw3NGxm~tԪ?!:pmwmq@rO<V Zz hM4p &7a_Jh~ڥ wc:ZbkƧ> cMzMA1t CO p M }FA1v CfCd(5b ż 9 G~ P%zQ_C4}/QK8kwht!:Q "50ʰA3?BssPdvB?>bLI]f\~׳c z9̤;{3IKhقƽn̓%6|3MG{U~n4n8y>Lks\-G$f%Oj/[$Xt]LI}hSJTzα9%vYSH7.&h ?e 1y!0s%;Ějje T=i9E8/|hG8{kDjg|#ۚ<Q7-?HEOkvEۋjO>i~Vb$ͱ9%'j4}%Į &%~ۛc'CDkP \K^W >ĺx1x x1mf_۪OToNno!u'$qo}las{48;> JzW/EB̍ ިn2UWuʳIr.ao$eZ006zֈ~{,4A͕Z,ÛCC>-@MAYSOuI?ߴ;7F sLRX7~ ]ڵޥ~t}3`5 J{ w*ENGkdo%[-̘'pwPnNfe:df+/^jn-c l.T1$.|ˑP9NT6TwRK]Y  Ϳjn=WS'N\= S@oI +p;u+-,m^ԺxKB3ш GGr1?.βZGZn|#>O %al4#Mw= sG A>r'ۮAnBn9ȭs!Wd 3 p^V~J6_1G`&N%ryS ,Ҳ>= fPbf^~,_Sf=>vu#z,S ~P=*^h@Cet>PW>TladB9]-^B'8_N骻k*)i~KAWS]i]PnffetnΘQ\Sc(zNF eT'k|Fn&~UlV_vOn@4{x243|Hn{_kqRѦ~"l:׬ճt= %c2c7A94ԩdL4--`,IbשzD;4(PY%gصrP˔Z)ECU4bJKXTғq^_{pc9^iy>D)NթgebHP6m#9Z_Bީ|bHjLB )2ҏ)\/)fz t#ȚN=={iCXϿR@n[3o:ppGl/FDr}#,/y[ؕAѣ9Y `bM' >9ybᗡqsLƤqγ''89g7Ir,NNn뫝 tF]=vYM]& )hΕ(4~{k_n|QoW뢾m-8DjT77'?qJ>ÍJe˸YWϽ,(v?r^cr-A;{c1 |t-wLؠ. 6Q#\-Mf$n@m1{h u/`%)<4p' 9*־Դum[e򊛅NUJ ~i5xK0<mj>@ZH#>xG|;n$ s) z ]Z,%{G_{}, Ht9o֏]9c;YlT?C! ȅAdCN+mn/^䚜:|{Iלk:bZ2dt2w6TL TƷJ3kk\mSW`Qw>pcR;TҢ䊮|GYM ͕W,WXdAOY(AKU~U_yf+-M ⎪le$POH "$9ʐQWt p-49c?iDmqFBZ`zfhj!ӗY$\#zEmIU0QnE?ʔ7gqbIuF!a?b&(% sGF;@Hbk*{DeEɸYa{4e^g,z$0ur/2dofP¹;E@W-rQb0|_7BҀi jby&uq 7 ;XS9^tqW)`fHK\2z'FD+CfnHsN,~AtBlٴBw^%v5o6tGwIJ:Uԥ˳Z چmr1[ki@>x3~}>iyIrR?A8Q$ f{̾>V7:8ǯ*l J OrfwM&\f=9,gqV oq {, H4FUA;=-m,a "gOSZAfN:%NNN=[]-ރwU>\v9YtUI  )q_9NejT!'43qU:O^!et#cA`eRuCABE׏)dL/xLխQC'5t2X5Nr3Y(i'DڨQPKw Բ0Z;R:JvP`/ &k&{f^( `*Q2rŪ)Y L5oϷ~z{жH/s# $2P>stream h4k 冀j)B{jadcÚ6ƒP,aL"_:!!H!5eԣ[ԡԢwdxO <'1k{>,*g>ezz>kw04)-UZ&֨˭*zk_B| +z1:/3i<ϳ:Ս?ҟT endstream endobj 12 0 obj <>/Font<>>>/Rotate 0/StructParents 79/Tabs/S/Type/Page>> endobj 13 0 obj <>stream HWmoF_e( NI|m1ۄRIΐK%;}ŗ<3s]uy~t-ʳۓf'cu;;ꪩn 'gl%;ON-T%[{f,Wetr UxguolO,ee39S&D*6M1M?N8KMR6BZ6OYia-hfuo-ZeEZ\·F 1Kv]O^l&Sa!:+FO/Ѵ΄مP"bk!Bou࿁u4)x0dBgV2 B܂?Nd)?ORHy2BdJX|kݿᝄONF/<.--~`x`ʗ'yi-Hvbeiힸ mh *p` B1eb x$1N4$&N#81Yk2- 5gKOYMJ '>WJ$d@@T E,/NK^!lWWs p:~ѿw7'6FRYFk~B9YՏwNn 54s݁Ep>gɅAn@ Qx:i17wXnj/1Yk T6 5% OԂa/koAt+˕o7 NI[{<;no(!Jvq?ip͖,^jJKK8AHA/ݱןChNB SE͒UeP\_wu\-`U -#zB6oVK4mװ Wϫ k ʧ 0Y n@a]')#]pΖEE1MFh'[$noT AQܴctVИ \5h/Xqdh+\gbZ/ucr#n;]pMd*HgFį|nFs9lQrY:86ܢRD?EʹjZF_fEڗ]PSGT矑8PW@..E,cx0-rm8 ,umzK$QDXBDT}">U seGЯ(}HPZͻ7ZM3 ZtM% ət-ڢ}D)P"/d!KJ8zիƬqnmf1T弸_k[fxw2=$nQضAj\6DWxIJA#SP ɹY q4r2H')|h.d]{=`*܌&bj0=KS4Jєu6rm($AOFuHfVA0P2Z<|&SAĶGণ6~moOmwݎ@Hp_-кQ.G(8- g>c<:',8_w zXM^XJEAUAmx jC5.S9T'&e\ܴ;,Ga3`HsNtE>gO4xFĞ8Ws@hONrL[ȑ:a&4 wZl{|R~ (:Ɠ[V(~ͿZ禕X[i((H\Ө@uʀBMq={GCF2_"9$;iiz$,>Y/9cPH ^H>q ~l],{GòkYvE'Yq}MN4o27IC|KCez(87ߧgr3w{Yvs7 @+(F\KIjoX_z-= É0ɚ<{  n9}6 )WkSGM6)td&\PӇBVHNyHЛ8zoNq{㖌KʠģlD"d+T[5eCaZ[ cn"M73+ 0|vy[B!@mL A6lݗTX$04RT' ?Hꕹ8nڈ⍒j* A[2Z!7@xjc6H?5B)mD{Gc͐[bʲYv,tLOLa *㹠ϑEv{l}Ws`#9 ߚq+.^Y-H[${>֓#IjH )C*Mwl)S/6x3YEa̍Pct?A~M0t/DҬW0Zm3+XU'v/gθ3a6&{UAۨx,Bse|[) U@d9pOJ\;kriN,to:î>-rY)u$ @C&G ҋ6-8P/3"}P}6ĝrgH)d7hf "/hKZ:> dBUpt"t8/G']~w_Z[QNұKfsc`-mI7bm|zyFl,97,e/Fp71*-Y{9"ZZQu8|:R+ğhqԅu D F,r-Y8hbךX҉AzTN)v_&f3$_hՓ 8턵dF K!%i9f&ggĘR RuRg_3 |?oHޣ wn~(d z{ YCwl+ߟ]S:!+`]ii˃h=h*t'vn;=;ힵ.twS_߻Fw/_F@I@BJ OvzC߷+;0B+Puu(CF2U L0uR`u<TYׅb L:!+ViȋwH@"K&vez-Z؉0E.buk:M?|Eߌ.W=ts+M8F-կwܞ>  ůB5 ^GzZbp#S16r7%ߨB# {-{8ܸhZ(y;l~uͱeqxŽ5d)ѵ(Ŏlh*;f rO7I Wᡒᡤ7ՒqȐ$ȐQ8ۃPJ8=Nkk}mSW`U;H{ܸcWZ*yK%-JBe7]W^\~ጵ, 9%ygN& N@,G'np RB@[h9r-qiD5sFB#3\xeZkbĨ96IY# y;Q6L/nd/A)&Tt"qS^X9?"fRo2T=U Vfʑy/^ad}fTq{=$ջij(`kS7.ɩOw7b?^nBW`Gf1y,`i,kޭ:LP;z2ZO?# 9As.m QvWLm+M!R_379F/[6Pd#NvcWb'Z^Ӵ.?HH|3^#u)xV D۴UCvmR1 (TA4GXo#I^\#)+Ҕ!\d{|Ο"xW\Щ>RQJ(uMmkfhADɦBv@2Wf49udGn=*l NJ 79p!ȍgQ. 3lbֿ)݄a|S@ۤ];.$T۟AVg+[E2iV4"vNRS}"aMtBo']})[GWSMYjSgIjbmUwP#? z=]5~\L8TvAђ:8_h̖l5lV 0Nfz&52 J#3r)>{:A{$@ĺMWiJpo\c.Nbqz.D*x5a׮aPsjP|蕏k;S>2u92H> 0 /̳zFđHe[VSx {`E endstream endobj 14 0 obj <>stream h4 @_euwtCI6TdCzvo>p J3DLx#@?Bf!o,jo{k7 ȘE9jq%VuRHb )RMTEŐHbP_i3XaW7-<>/Font<>>>/Rotate 0/StructParents 83/Tabs/S/Type/Page>> endobj 16 0 obj <>stream HMs8 opjjb9UTq"!fڒǑ7ɿ!I!,D7n<>{ڡ>;?~EUR#9o|}8[>P׻~_t.7vAr~@|5;MWjU VgySe(_5+М`"?>??gʰv5gHSPuϨFN19֪Dw:.m)0v.;Bڍ\^BZb%՜wYI<¼xBV_PK1){=Iiv *||00̲)cWs ox\h=9̃i_UVB"/`VMGe"na@Dhe/Fy|l&=#['%Qp`DRBFU"Q5fkr|ziNDM$!bCNdwnF Hz&v|.־7Í] -M̾H\alŅX&s_ȵ r9Fp+&xd{Ö%biQ7Z.ހnJ/Hװ_+` ǐ]ݛM fKX^gxxy{ nܗW o@h鴲Cpce@j J`斣7Fa n lij3'$O424C QHpzM'\p~:ޕ6 fS7 juނҨIY׎E[o^ |\A`rԉukr?)is *aka٭fcs,f(%din= o_ZC406IcԹFWaO(g摒cBվr.IT\E,uOGs͇u))F#Y%EdbRE˦;|XoBF=&ƔCPsTzR}KB:jCNſ>$]hp 6\E:תdLhlpPɨe9Ǟ$pmGS;o㙁2^}70Z?1(A 1)%:%$K< ?D9څ4~zxH/ ?StA"mGt{D=֟G  cXV1C!RffPMBM RxLi7éQHDERߧ]yoBwQ4LpiS AK*%E'RA.BK= .i6%7%7åPf}KeK&4n۵o`͗AOfgr"K;~Tʩ{Ns~8ziRcQ{3 JM S>BS1h r(RLEHAbB= b(2HF5RCAY˓A εK[{K^BTZ̪{(f8[P?{ᚱ׶svA-}+ߗ+s =S;æSÌı)LSJvP="Og!GLEHAB<= @Q7TZō* v &AΧJzv|q,ټsߕU<))dY| 1nɴ7` f Iv4J5yk짜C h)):(S`r2hDB BhQ @!h>hh0y4@x2h@qFK{Rzd3휰ْ-SÌ6Gf$, ^gEqܗG] d)Aa,`*DJ hQ ~Ǎ;n߁=a1:u]QSanV Qj WS<|.`r~;w& Kf 3ҼIfѢ4& AF& 372*B'L dv! d(Rp_F{B#L!LQLG(_k*iO1Wkhͫm㤠qw40m}7$7yj`gx_?{:Pr:f("[>W@v.7:}];A67ޗF0C .il&I&W:k+\A^CգÅ2%'B v!ͅ*$pO!GӅ!PɧAޙ*[3`PQn͞lWw ~L"J{煝duⴟ`s3\4 %5qleRӔd1Ѿpi.~\ZUES%X]T슔d.գ@`bcmKas+1 \F >6S2) 𘉶֎N S$G#=O7c?n1V~!6kUån`C CTV#%DK~ @a1d ;_ >T=;6Xư A} Ó' Qk>Q/8, \UנEjZgDOk!r074P 0P[p '[8dpTh2+!t_n ?JUF@]^- /ՍM6k82Jg|XT0uIۆk$sa2[3+zhe:qLyl2278k N]s8iTw8+QR2m4҆HO$tL1WS~O9V cX_W_iP_F9.(.& ɭnMrFQcXwqFݠv'*Pha"%.xIR#ςf=Ze0kETW̰2d l3<ʀUS1ߵ}p;Fo}z·2}[KXJlE9NVG-GP&mf hD]Zo892* pV2] ǣ9t1nFrXF𷷥gX(=ĒPV{ q5M]cqp ub3:;NΞu.TÜz5 '!t|l0K|frȔJ؇xJrj֜~bט8WskL:#{&NMX2_e,;*cHOsJ(f}K(zÍg֌;F`y~f#}n6st0o:RT7wj^/(ղAn?z>M&;im͊6g"Q R<^l)spٗxv__m ꗧ}Yvz~.S\ ۶Q?u}E^ӻ涭ov&T`aLZB2ud#ȣbO4Z+ۘ*d {mvҩXK[7VYmb6 ,a4sIDKiWf%M dPgQ5\7`״eLТ#MV\ŋnDŽNDQvmLdzOy-g@Ξ`נ! >Zd m[/z5G"~0s~(iTlZfwb%Ossw=w쒪9t-)MD"$@l! QK:nb[3 sk\nūJ0ݨ-on2+ -%&Գܕ+/Y˯F͂:t8f!Z-U_yfK:Z280*$*C xHlS |^a7. $8zuo@X3v j 3"& D]Y$\QEOo K^|!ck<KSnqW [Zy`R u|W`dcGF;@Zg IUx2nVxpLڈHecg^ ABQb!) )=-{ 96zTkP(KS/רB;7( ]*0}ePibo2)ht[s˚k1@0s'0e8#}boJStA)vQeV^F\ʛFD+CڐItuoDvrd9vlJՉ҄׬ OVҩ/]26lky]X7럩9f/БDg}/}<4\icZ'+ٻWg\G reЩC +!5v=B{WXT9\7_IHeLÁ_JȦڮJC TZeJ^ J Os ןEMΩ.*Tnw\oNa9KR7߰&`#WuS>c+j)蜷~OmEe K#ַ,zO혤xcdRag'wW9*G L_K;-B_̪dOQS>=sT3,ijTw!kOifUP,╢nd,7LnHHhղcgHÕ%1\:ߩu`{>w]J<R^8@) BI@P%Hk(;%fss eTP̦$ @1k)9;(Q$ze2q[1RoT7~Q@5>stream h4A 0uٛs.dNZteBBm1~_8( &bh|P&"cRHS2%׾60ڧ3X Z M-Ī\#etl ,5܀Ԇj-R- U0:k= oswn!..SǺ[k v@ endstream endobj 18 0 obj <>/Font<>>>/Rotate 0/StructParents 95/Tabs/S/Type/Page>> endobj 19 0 obj <>stream HWn}G2P o À%;F&H( -)ɁUI6]+8C6f7s%^^k8}*w7[thJkZYU Y]MBHFsG;]$$Eyt]fU"f!叮)UPYiruYG5}V${\)^ ˴n{|mi*=O| 袵d.`L_)f~UzXLb&kJȚ&3, "!kRN:ȋ 5|2`}@5챮Tß4E& [nnhEd]KZ8eQ!Ů*m3nc=:FZw"oTY =ty3J%ɷs:+::ՀqRTO{D?Lo1Y͟aAqeom.c#|u鱠pLmv>J-H4ezқC$JbF4x9ՒBғaٔWXK@:`{# ˘DL-hvD-79iKLM΁Fp9AU=v /͕B-b)mf-DmSf~E_@f77]bMrf_VwX(~oa605z;hT!SXE22& :O7TosyYmtswu7\I v?M*o=wrW1XoSw7udq) : $ FϸY;h״gG&([lV\h9*\#}޹9԰T?wffIu۸qNbFf> i1AЁx_Z1d 4Du/i0޼)r0qWe |) YU0+47n"tp`"s.,6SVXaJE00྘u[rڭM+P(wO`O_}"#%hCǖYһ"gJT~(<čafwb1՞󡌣ɤElEFzc< .4%!6W ;- Le(",h?aUw_vIO+ _UNe#q9OlC-0E1m jUc5X[/&8(t@AdvDust(Ʈd-'Q9 @Zhƛ6*+*]R& 4ߢLVU[$E?!RF}K AicM%xdl'>]U4@9{ .:Vg!(͍4زS '#O(m49\N.88!5 jXgL)IF4`Y8ЉU8u][H(X "cy>g]Y%HuJڍikN\a3Ĥ:}GIlZ;uIC_mEDcU,ӭq^/Bxʁet,6"O=ˢsDHNfHGP5/oB}4 xލE`"Pʱ!4v BM"r~/O-G`(MFE W}O̧v.R5 X&+hKhejR3ޢ{slF՞y4;qN&bR4 JVݵ\?۽tS7Iwf=Q 輔EV%߭%u k; lKlEo0%nG!SʓPY`VV$/&(g(΅[O~;mLvRUNjA/2kPX`;Q;*b1=S_Sxn#90"b)V2,nRqfNM(ΎUѤH-ql 4Ʌ\HƙCrgsD@naZs2 ~]󸌃yfF'LF@-4\ ?ZO/`{E\VTki C0ܡ h@'YZ6-K0o8RSA6 I]DL(cJL>!Vu2.&Zl5E{- nX(]\n i,}xf(A?ܫKq~*C^G1DI}8-[?uB0 9wX3^>v &*6Y?kZ0(/hb]ؕ(0byfr6@3HeHe@rYnr* רUd-+uosgI)׍,9MBlzPi}YE0/4  VM/+>5Ƃu q-m7QۓXwoEgkgGes6rb0e(g% Q#q:worXVGiQ-&!s;3s&iƣ1w\v8sT›m(fuv[5Ha>GqtVr^u,mtDbџa݊w^xr"JZD j`/4,A <"A4@~h*m>HD=71`0sL6!۴2Z{!%M\lb/UޫW;"a}|ﱏsM~ef{x\` ]14W>cZ"eܿ]elrMlټ=3DަM[kڤ4s.#ju?6ems]M ?@'zBw|yoKI{ɒ5c ?< Q6u7'O#IHcSj~ֲYv㘥GSUMmBkŖ/׸W- KН #GtdhI-W2}yT%\}i^{bR܊}p @XqXeZ]] VwczyQ BY^u1ϣv!@"HK|T H$aCZƫ. ,uHjʗsPc^7+|BOnk?[8 \7OAnwp=9/د^Vw7j`7êo"-=\} KM7u"Y]m_x`v,$505t j1e |VY4ӋDw&fDF8AxflSm8K69L0h/a쥣[r!\N$LߣDڝޝt*S̚lee˪ll9xU F0rAVe8},&j!Q^ZXӇ0L`*W[ >.( J~nFhl`"mfd~g'nc]nj EƜc'BvR.9V $db0vN}PR\6a/yȝo]t' A7gN feO`8f_]l P79l֝&M+)"8qHpS[~}iaC} Hfg w$CZ ~j=yˆ SoRb%MN=h#ǣo q-;2[8DVs9'X^N Oa2KX&7K(5e f:a-f+GS * :xXMf!idA5:0l|82#WZlHs5OF"S˂6hWP+ћ]3y ;dUf+Fna TM)9oKb6d:e>h6Mx`F(4.ԗmٮ*[Q{k[.|gàVMR%>qO9\=7,wu!g$glҡp"\M7E\?~xc>+,Bg endstream endobj 20 0 obj <>stream Hj`@  endstream endobj 21 0 obj <>stream HV{t] KPHCGf# ]6!S*%.倅 HenN+rl(ZE*cUJ!; GO߽FH V9!ƒ=3԰R Tea}y$`xokҞ?`cu5꿾~He<)ҕWO*f|w"L+J+R^cW׋t( u,k˂Kkh1/y z rACݥrIRUI&T;hpj1us;LcNa;KnG&`~q_)l|n| dA+N ż|bY,~|TC B3z%<)HAoG=z{&(<`MB؍tq0.nÓhƇxuz'x qt9h&!&sy1sL8Xly:"K5~АRMY^5Kut>ɢQRSSj{ל`~>hga VS/7ZF#iMgt-r.Sdˀ\+/[mZlgYnZ(.:4Wn2|>HQ4Kh6o-9xAfr2Ω˨RS5*ǤPòn#VwS(@%@qncd# YH˼>5]oUdѵɣl@,UP8@SַM6R $-#c5B%U;"S%Gŏ=6tA; '֯Yi}zzgTgJĄnMU yҀf %G81z{CcQiWC ʹn\xiINEyW׌%>淔~͸JN$3pxM+ h^. |IC$!D>z}S}G2Ged%^#]/B0d7XmW%.?? OH_`@oM1lw-&-ubA 7Z2|} y{2M[Y0ި*|j]9x. KfbYϠ R2jϯFZb規‹6a׸ed͏U>eO_J[Kϋ8S $%t\ʦwVI895f3ģj^EF7O ,xCvZkp7>* vHlίaVtFn1h"v)X5D8ީˇrm_0rY )FckXy !~C,M]Msx@N>HptR{z ?5JbO-;u㓙2妜il_do]Vj8۟5[Q׷:4 r.KxIa+9jv8E||D*g|>m$S ?# ~w:*A_LwsϹ眻wܙ#+Q)*Rl0/C=`nXo[T(_\])]MoIdlI ʃqϬ ͔Θy3Wר.>dieEpa豩cG4O0>[Qi5O5^<_K:}9^YFA¦Dj} M D #trQ#$J Z[(lCBM: }3h4 U>9˖nYK6*͓.SK+IrAW\`Ev%G\170>*S5|k-{)soRLL9|m7[|QDw<-jNMb3$Sr'_9Ƙ|u؛^u3!z[doq/nvf[Y"YqYfյT\%?o|b%mknsMy[5Xsa\&5.*ڼ\ecPx@Pkb `oCYn( "W c2o0Yu>i!|tFm-|Byi0;_.!%|8 jmâM8eQU~؏G8,$PݰkP(Z4le ˦,C~V2K~Sf @&Sf,C>m GcI-ZPi v'Z' hݝ]}Zk/c 9oiE=-'w):b<è;bI *-GU~sF 0 B?Ep+4>0v-#fn:Q 6 BAct'D/ 'Ѡk+ )r6 F[geʜΔP:EcyŠKE6;/u^NU8+oe|\H3^3TE99ؐlՓb?}ўaϨJؗ%8$:f%NIPKDЕDXUjUg3LUUeURT{*}ѣ.[9o%C 5Srm̟?%oR,qW=K;պ?[U?^>pڤWKs\^2csM(gQg[]lC>stream H\j0 ~ Cqv1ȡXpl%3,QC~:?[>27 C 8DžBc u6{Wn7٤:gZk"ΙW8>stream hdR]@+PnJ1^is 1-1[#UWtK;KE3gΙ]g \>p=mbc )z?^b0 3x66<{k&Ymam89&/>ݯtuJZWZOkCYգ.rm)R:pQ"5YMFr)l>/ExtGState<>/Font<>/XObject<>>>/Rotate 0/StructParents 96/Tabs/S/Type/Page>> endobj 25 0 obj <>stream HWnF}W#]Q/AL <8@K&4TwU5[lvWSŏR|ŇK~8lqq+YQ-nX.s!~&{u!*#ϳĤ?fyf x\ypnrMLrJ&t.dۦstM:WDZ&ߥ }^4s֌6_od>EާeҾ:i&Nz0ߕ*k{"/VioJVVEVR]e|^vߠ}n6]],V˥:$n, σvYtp"/t((NCI.wG З%0@k,G}t15Zòu4Jx @0` wڄ PrA=di+>?5iX)7o$0|/ Hfq8`6)\rxRjض33#.D,9l"}$cS*'$۪K:[M$7#(m?8\(Wp7& #zChff I5?[tWߢCkw! A40Cb&+JuNi&?9wOP;) 8L5q.Oȕp 00ۜpQE φA qwOϮo㙤pPXL=l;>663uڳn|?[I chcO+?J6>H)p"ݍz`Bb<ʤ ea3 !wxl^0-vt0j_ÂSG]䐈\( s6a6ǭcN2Y-y\VVW ] F)u˦Y_co!Q-.XF`4M0?ŐZǺD AQGү<@5X@xRkỪ lP{ Cf5Mxblv1'a9L?vdr;- FВaLVppEG{Zܡp@}wd9rғ`ϬrL2M+*.۳%|_cILQQ0$Wgo֛?Ci#%z9}23xY.d̿Q]bTS!&w>1NXILA"tUh>7^x:6ح9=A{ <."0Vc9Z@0mm}`qa{b e\(0;pW [beVT&L+ӹyT.&:k}0\Av<&f1i4BqԌ> ri cRC84+a0C\]PDMtK+Ʋ \y<mW0]agBxn!leUU^"^>[4EɋnRi:0ۇ$f}U2£ad fS<&6mW;-|{ք ~\ L-jZ,y<{n#47 k52bPړH焫&᪴,]2NPbŋ endstream endobj 26 0 obj <>/Filter/FlateDecode/Height 745/Length 25291/Name/X/Subtype/Image/Type/XObject/Width 960>>stream H{PTTt1UA0.,Py#<ACDƆщLu8Mh툖˾Pap˕Wg{޳?ʐ\š F8(ۉH]$Db $Dqb,!r!41cahL(S2cF&]e [/o۽~{)T B2ɏ'BH|{?`U<-.$4>_GsUyJ yJN[=RJ_h9'B!rUF~2e&,}%[ 1wȊz`oI"e'QpIqv\Ik1I6`8D!^4.9B~Y:e\jli.IIءF+:fn9u#DI%ֲ}m9RE96"@RL–$i!B9Yj7lqI6O7k 1]T˜QuPvh%!_`{<L Kh2#Ɍy#ɄB Ga<& y%,A@3 fq w k%f`=G!B/-|]p.25ZKY95=}AԶM]1Ti0{&N~{t~֍R3˲@ ?f(BE9!Ĥ3 Ť:!_Wƭ­ʽ]Hȧ؀Wm&}2ڛk{"NjShږdȏRWRڸ3z jW,h]zvK3$4gϳr{dqzyZG? y(3p.BY],=;vCb×}OEGBzX'$5r;N9P-ζΉzS=dQX~zXc/6暫5tSy4X`,V rz;MAs7K=/g|sls!LN^d.Pi 5E_Q|WLor[P; ~u k]t}2@?~6U`[wu-)0l6UkiЦmƒxc+/BK]ݡmYŒtgEZƢ(۟K|/ϭDA/߃3ܭ;u_a~-*}w<<$KW78e!rPTw?)uƝBd\¯,x|6ۼm2mܢLLgޑ-~p?we),wdIs.q%sg4-+yQG?VϑZ"s@% ${0fp=hW󭩊O7؅}~v/'!aӫ8p{j;Ɲ wWwľq$]:.2O+B$DP)voڇb.w;eRʯ.󹥹dsodr 2震̴z^ Vx^cvOٕWI &ٍpnlW쭱,0;űťE.+7vqMUDK5u`ϰqPɿB!sU`S]zWe\Vί)<9ܜ,~V&?[ùgZS^ NmEtEы(Fr["$޸%PS6ц*fwlpO/33$i0u chbL(4TJ 4A<"(`c;NfNtl֩Ʃ5IK8|L3ADy]X,{]g9\]fw?w`4 c3Ah^ӓQOR O?8z8k܀K'3M9Eֶ{_&ܾցbvhlc9-%1vGtgmK nboa!t .+~^=]Io7W;&JMtgI]L,][-PiGѤhk_֨jT>] ͱz e!4ߙ9ͻ$?QYV~10YH}"< ][!0ܢ'qVo/E_'n=dG{y2ag+I|`?軴~y#NL#3.5p}BOYH>"ɱ(%Dd E֪B;_ t%~ we<82fTLy$wAEEEEEE ǃ C|/CB[GV+K[&xżwY|L=V9M`͎8vg [ۙʖ&kTcS?l?M֪㽛zydńu ~uϩS20BO3ͼSy'4i"l~ 8?l6ԏ@p;X"[ 4=]xۈ15d]D&_taMq`DP $k`ek+{F'^='{Ԓs_uaN94[} ,an #|/E1%TIj~u5WV˪bo&ϩ:1ڢmq"i͏dVrLO.C=Vs>35I]L#T|nX&S`ԩ`䍀4vFw{5@ƻN6E$$M[n\ I .HL#5k;v re+'cGeZdnZ>8zecߟΣ-x-Vթqzh&Z5@Xm?; fHL~1`n B؇ G].ΗUh ~K{Of{QQQQ=br{3Ӹ0[QEV*+{?4XnUdVl\X1k"HM6XLDwWyv&-ްt2ڼڼV%\ܳa~o+83KJqs'?s ~^4 ~X:Nd=?O+s*Hcl1sݨywշ8Bq6vKE`8|8I( -bⵤ7qWp2K" Mv'[KQXV$ =HL2Vt^k}&':؜4dzPQQaf 2N͇ۤZa 4~OK]b/pN:Dߋ @ wVיԝV7)aPMvvc0KIIY7[5Cti^| ?Et~xd~5T2_*OO%n@wW/_\hXRd**XX:0NOѫSƹgT]̊/ab9g[!nE;җtuu-J^N{ibhVTֱܹqsbcgl#AkѰ[ҮqȵWJ&4-WI VRc&rV--(JcA&Fф2bLk$z  p͑.g!ۛq7o޼7;ܛ7o~\?/LsG 8uiɆB1iLDDDśkF =yf3o;z{G'WN3:SCϝ٩%b+>炓7e?O]k=8%'~@$;,&Y<{)[H; F݌9-{xW_[~9?*"""bE/?5+Gn]ï/#G yc#o.>zg7 l:*6r ըz׆Kuef+m WVC|~2g~nLw|7UtoD~Cig""bhPl;'SnʳE'9py Ş{f}?{ ϋ4[7/%\_;=gc;_U>ǁg"b0o b8 633WŮĮ坝WĎ+sѝ_sUs̊J?wxLl>~HGȁ'NGv29|#_ֳLY_Lyn9-6ϺqN=NLJ':Mt[Y~2ل+h4c<>q""4z##b1]|Z~t?c|g DDDDDTNUЏgDDDDD3""""3""""Yыuq*?׋GDDDֽBZeԦ2e. Pƻ_x}%/qJ)c~6P]S?{?*hH?+)qTJ>̼2ز$g~>W r!̺ϥ{\|F'eY^j7/,-ϙg TsɵʼM~ndJkԓ[9mB^rݫS'-b!qKle*K~7ۧm´2fZJbߴ:I?cqxd+@@2u|-fګZ^!K?\n&Ye'kf~ni-}W %|9T~F]:b ~va+3@/Y~bQ_F_^W39#jG-K/@3Y~""b]s&yLu+Q?^̙cY6xvFcN~veμe_Qʅ~w9s_?&H0%_ǍgU~!aV ?F2_&pGg/ZtO>e`=wƸWi[W(B~veYBTQ?Kχ'@{7Mmcֻr$Y]]@_̙cY6Z?M~m柌aBKL_E}c$ewYc|~8sE[coOQrqg[Ov0-rMK'(wicXH~VT,gμgZK?mdug`±[o~v|h9Xgn̙cY%\=8I~3Di-䏑"2([f6O~TDy3 P_?| N)m涵l롫O7^嗂>s|0'}xJ& eԌ #̙cY1RKd$՟NgY&_쬍|K,)enLPK9s_?(4 C&\0e݆~=j g9ssT .9dyy,gC?@yƃ}gg|48-0sL3agA~3g)WHj{}8~3דrƭ;T]>! ~6L g/_ ֛~8 ϖw> H8?KXH~(,gSB߶H?ǃӆ庴q1ʴU,_ 1lLAc,cW -Ddmw+YF(T\VqiZ-_Ml%̌-}| QRݍ7op~Xśʍ/_rRbl v~N&?l/K?g`\}χMT*7>8կP`2Sn +4~d]pLkg{c߆&cӒ3/KY_}^Н~K?ϕ)|+Y{౟ÒsgkI,_ZKOk9Mh^#xgb#ʕXΖ5.=Mh^#x簤Kɧ%L??{౟-~fk%L??{౟Òsgkwa<:e?HiNi8o?IoJ+;Tϥ{4縿7)@ƒjyg~gk}XTGoŷxf!2No67mmbh?뭻r?+U;,>o?<祑.౟ÒCY7>c|W|< {~9c֞^J+삻0~xC?_e\~vcR+*Ojgsڙ =qwh'`wH?#ߵ܌پ_,%'s1Wۼȴ##~bLm[̼f~NK=kOƝ0ϵ kxXY~.^mgP;y{d= 9#] |<~pZ?p?%ug磝ݏ#Z;`.y\q9q9bJ?Fvf{oh/(]+D{ _88KӒsF"@b?G}ˀ")sZRw `M3SgE?:~NKz p 9+x\S紤l?ok \\ )sK 4#}z Zԝ3ϯL|U3wR{3uWc Xb?G ~^-GvrN'`qԝsF?~#LmXLp{p@~v;Eݺ)EM~11#0uIc|wkn?G>uoYgR紤~~s"^(Yaovex ~ݍ`5T.S~~q[mYڭXPPiI95,um~uA?X~iI9g8s1~3F.SgE?\KӒ^u`6yo)ا:*/̢_aWs62sBkb?9-;~Z?oosMc8q{ʷ3a 9~u{F?6gƜ3gPg{"eNӒsf;GCpc 9b[wZxۣ 2[5p`?lԝ3ϳ ^Y|@۞s~{`.~_?3k=S` y Zԝsa?@E#mw&5)3E ̍mqEŹNΠiIW/ϹYݙ}*NОXb?G|]Rbel|ygsƿm:9-;~&v R"¾qqv?ǐ; =?[+c6)ʽ7;GkR紤~~}r<ڎs @b?G swEpMNb~r2~uԝ3󑼜.6yvW&Ʊ.Fq@?:~"A؉6DU{CoX 9-w##űm*>` 9b~>-g*_\uiI9]G:P0ށ{\cd7=G)s~޲۵ϵ s[јޭݰb}) \g#9-;g/wskU7v ϳ32gnȖۊOШ5a~.iI9 &ӖQI?w?-+n'7hW?' `/~NKz p[ԍl~P爯W Y"b>Wz\U~NKΡHuA?X 9-;g_) g/콆_gP쾾֩+Y4ۣ@b?%uϯm@3]ڒ+wG~u1^QwF\uwP{G?:~NK7w3bF;gP\ؼN>{7NӒslOy~u1?/{6hk+{E0 9-;g@b?Gޭf}~X3S紤~pW3SgE?:~NKz p 9+x)sZRw `M3[oǍ+gEfc\Ʉ SRaWփj6?p.g睸O+ .ב{k>j>yC;7gt~ǿzl?8Ϸw}̙=s HH=gb_vnW>V}pα՝"`H?KwnC'1<~ɕz[㕏C3@~^G_K';{.^ҟr" .g\χ28$ A?Ku3~nm$o<Ly~^>trCeUz3k[㕯 ]b?# 硫ޓGq3@~ ~HH=ޠ%3@. .בz7gt<״Y3@~^G3gt~%egne{wO '[9?tgt<~miz~?tnҭZ3@~^G_K-;{.^ҟr" .g\χ28$E?Ku3~nm$oܹ; .g;nM[)7Z6Y^տ{حg;:wwhH=yQmA ~}~?WyxG?Ku?o ~HH_=3@~kWO , ]b?# g3@~gyiL?o_lW6޸]ggg6?_ys[oqTgt4sk?>l?ݭ79\oޮu~g8I?KL _U}^3@~^G9˨Vsg Wy}||}~ 9v*ؚt4sCoUţ>S93@~ϯG%:pOD??~H3@~^Gޤ%_ӾzRgyiG?Ϥҵ <~HH=gqs`3=;Q`Q3@~q֭O%:pPB,wnbo|Z/|.g\ϝ)wNj /,癁yid?.~n4~0C?K'y`a? ˕@?KuKyi4L@+gy}ܚa? <~H3>~l7byCWw S@o4%:pϙ~~CUӣ>nf3@~ϯG3@~^GIg ~HH_=3@~kWO , ]b?# g3@~~u |@~^G9ϻo_v}~m3@~gΌXyid?W._|ە%m+ǝ'{vS)g. ]b?ϸ{W'T/mz[gt4y[>-osÇT_QݳKwZg~n:3@~^Gw+g߻~H3믕=ە*.ҿ{@%:pϙ~~H33L ]b?# g3@~ȥ%:W& .gՓ?~HH=x& .gg3@~^G9ϯC~9~r ]b?8ǓοWΜ9%:p\.6oO(Ergtl9;\^3@~^G>L>syU;6qVy?x,,yܯ{wB٥[3ߪ{gt4yG?2lVX-?2% .gmzM[5~yi~6pBW-@~H3N篝 {m03%:pϙ~>Qo( ]b??u8Faz3;r!3kaBS9`}9*!2/F~I?K2Rsϱ F?Kg\ ]b?E ]b?vgt\Fj9gt=yj܇_I?K2Rsϖ~F*'='rwxQ .{lmu='=p ]b?{]bΏiNl .{*n|'gx؞mϮgt\Fj>'<.؋@~{?/ke|*gn>_~>t%s6mC]gtcc?Oܖbڴ}A?K2Rs.|[*3z~^a G^|ݖgy~`^2Z~ZK2Rsϖ~>Sy`; .{pw |%s'o%3@. .HG" .{t;zRZ3@~.#5g3@~qT?w~ ]b?{09xQ{Nuρgtcc?~{pq ]b?{s%k?||ڶ~r<=K{_[vT%~He0vdpBǗNK?K2Rsϖ~-|Oyc ]b?Ϸonxyn];{VUGK2Rs~>N?K.K2Rsy`L?Kg\ ]b?E ]b?vgt\Fj9gtwCܳovY?m"gtC?礟%sg~/0=m?/ݖk+gt\Fj>Q=K=k+5gt\FjϷ6ϧgtc~'+_ %sg{?T78~H=N[@~.#5&3@~ȥ%s^%snGO \~He ~H=>3WOݽ꓏租%sg{??gqj煶aw3@~qH?ϟT.Vv~ܳwdX,.I&-^Z[\hm e ]b?@?7/49IŏJ^%sx~k^h'cgtcK?3B!~He枍wgt)\X7z} #;dr=O?tX;_B?y܎oɶڟl.'@:pq3<χX@/)@~\ϕJ~[y~G,HdZ~+~?7O0L09S .7~~x .5t;zRZ[3@: I ݥGN?T?v@$ R\Ks~J?T?ؽs Z?\Ks~Fn{w| Rcc?ounC?T?ܳ02_8sX9w|@p.=ϕ 6^? p~ ݥgyYs3@Kss g> ݥ-|[X gtvq|D.Vneګ= ݥ\~Hw~q~v ,@Ksy/=gggtggt^: Rѓد$Gq,Mt/eڳZHZoζ<ߞDΏ T<~hmm7Z T\}=)caoL}7.K#Nיd=fL~ϧKe/1G՛g+ ]~1/˓ˏ<y׍;f/1ѥQ{.U?tDg ( ]~~.U?\ ; ]~k+Bѥ粗 J?DGgT T\3ϛ8>gǟ G?DGϛ9yd~.U?tLA^׿a3{o3 T<~޼d#6/>~.U?t__a=p7p?܏~.U?Gύ3{O1~(3@t;f7߶s>h麍GC?DGϯ1_nvz9~9?0Ke/13 ХK#3p* ]~.{3@tr T\r3@tyįaWI?D^c3p* ݺs?3@t;f {/?y#t?:| ]~1ϛq<Ke/1Kkk}1r5CYDGLs9wn<'wLѥ粗d?ǫn4scjںջN?y3@tyıwvK#&q}|[Ͽyyf kLz8@t;fOu?K#3p* ]~.{~A?D.Ke/W/N?DGvJ3@t;F?ѥgs' lѥ粗~~, :ߘ؅Оp{|{ ]~1ϛ{cFN][w~olE?DGcuficXvfo\^xT?i]~.{鎙g. ]~SgRsKw~NKѥ粗dK#~ z@H T\SgRQ'7Ke/13X8d{[nޫ}y}z߸B To,@tU?׍y1Ƚ3wОs>oo>~.U?t_'yW9yo7n]^cl>~.U?s+Y~[' 3@t;~~nv~,Cyoy+>~.U?8_r\P/m,i/7gX]Y> 7 T\3%П,Ra~.U?Ϗ/W/ V BXIe/1p T p9 ]~.{z @v TiTD{w K-3+ ]~zN~ѥggRp/g ; ]~nٯI?D{]gRs+kv+O__?R=g{?w/N 7o7yFg1 ]~zΖ~K?,Fu0?t{|D[ϋG[G.N?D{~ܣYvm=tpe T~^3KýTjЖiK-gG?D[lqsz|b )o+@ty9`~.U?3@ty9ؕ~.U?N?D{9%gRso~@H T߾w?~~z~~s{|R3@tE{Ypo~KýTϹH?wKѥ^~ @v T[_)~.U?R=G?ѥy>stream h, 0 _%G4YvriS<\(b;Fe*!'|@ $( .@eUu s|nN COcd|fdVLT@SI<{>wI+ksjq]Wv 3[? d0M endstream endobj 28 0 obj <>stream hޤ[7 Xހ$xM ?A"Bh=%q&:]#Ys-Pb P(p.pHHHBѐs %!ɡ $%P@!jVAHq}@+*v^U8j LJlK`IkFRB+@pqh%ADSh) +ABWTfCJAIA*fhMD J6%b5q f bP&]ERIj s) LmpA>aPŁyzVL &8ĸ  W1c&Y f[l%W\-r5wFĵʵڡrå$2!7L#=XM)F *lԅm슦J[X>J E2HĮBeEpZ[ւ^r^Q6F(`\"rQ$T6&*rvѰ8@3:9{FKF`V-PrFwۄ?ZWIf1}vW{ן7g7<^Gܼ;N)i6>}T^>r{ {x<+!JvPmК3Eu)vPţY>IgRvP RZsmE@B] Y닳h P:SKkg{ P2SK( ()ȥkgA P4SDQm&qע:\79y-9Ⱥ={pSvPl9MN5PsrkgA*79e-9=nr/&%gۼ)nrJZvA!˜&%gۼ)nrZrvAp䔵<\6d79e-9(m;L&%g-jNNvSגS(~`0SɩkmasrvP06<''ɩkm`nrڞ d79u-9H&%gy*MN]Kγ`ќ&%g ?Lkm)R$79ZrvAAќ&gZKn;(?LkmbwLkmEbCnr춃;Q 79ZrvAQ99MδvPTf78S] p6 {8i-7=7tc3fw_cMͼu@6~qNM743/Dw}_xBs: 2w kgQ'淯C[K,~?o_vMY5j;42NjrW44eEJ|G%C"r5(u~x]şZG>ߏ4/J!JY6D %jXTq5״jTOnӤj>ߎFiƖ+q|{'ɕ(?(953gc$ -뻛o?_?vowww߷vpw|cەܽ;<Bo-j݄tDjk5` endstream endobj 29 0 obj <>stream hެYao7 +>,Q$%Etb+046 `=wiU6O|"GRR'\SJДpAqՠ-X3ʕ`RqmB1(PrUB3PPB}C-jhrx6r萤)CepjHa 0RfMa،Wz\Udō8H7 a)բWɖ8BR +X2gXzVPA\ \anΚӧT`%I ހ5I[  Z`(aM3 aKʡ8Ir F=n7%`Y8R`|Lp+/GP vU|)`rsyB?` !ZC=x9 l_/w៛뛷!}2B.<<<ڿLޖ '7]1/k8V_m.o_yfz79Ϸ?ԜoG T KC`|RRǁH=Hni$@{ ^ ^9#/!.vqw;*@OQGd` 1B-= !kc!_1[ {d25eX;QmCH}6L2CfֱL{et5Oّt-1.%~:"P8\W,”m1F)02V_>@uCv" KRYꂤiq \ҧbC>m|H,Rz :Rf@lA9,+xfK& Κ ti@ %"#h$8 2VuR"RI C i_4KAuړ!^jq 9YXEWc3ُjY v61ǐV,R/.6눌xJw"w.qai$ME̗<- B(޵/6D:!A4!iLc!QJI'x/sXƣbO@I9\+xȞ]4qV-'m<RgUK|sAiK)a݆,6j//g\2pC i;&0b_6"@V/kt/kɳ@ة=L(C:B#\^9ȇ@l[5 E|6!YZujq),Rc6V~wn\Ͽ_O/7n]l_o~8X~]n<>>stream hބYr8<q4<֐M l ڶ (F{h$"Ao$3FI7aAE\)̴!@%=KyˀĄlI 4`ِ~X<)LLVUpF!r 3mM rY%hhz#(4MRhY YCT1C֐Z`U[7@-m.@.AOoxy,u;F0ͦS޴:"l2ƕ2"؇uSWݼ)5+ WȪgּ[څUv_ǯm%8lfC|1{,Ved>^) ׿!s{xGTʸ0&Ʀɋ .HX׻Mn &y`#!Z o{=;`^.K®&dW]ުS[u" TMXSƧy >)-OSUJ^׷m9/x5yZvk#䶩ږr=W[ɄaJQtsT)Č-^▕k?E;+X"ʃ0V¨^Q!2_eKCmyˣQT$tL,#ע~!`޼h9sC$Hj@OU_vKwF1/OD9i pbk@u\ky+We_02!{f_'&!+FSi) 3AcOl24DGz}iԠn ~hPl#Q#Fh*|Q7Q?(n-dO,sGCP?PPMe*O~jL?aLfLvr昿ZSG G3GQy 侜tK(L1Q>0g9~_s҃#ZgkRH& #Js1ovuLS iɀia)/L/ wEo4ٍFj0n<:-ŧr,xj&3lwxW嶩' lXNYb~o>~XcjY| +Sw=pO$'#V>ƺ,v/GLTtŹ]2xL? N(䩉5˪hO =>oE!&O1.8.ykE_QBEj 1P6{CCj#a&8\ )MQ6;#T892A/J(Ǎx9!Kv]n燛fId6:Y"8^(/zC>stream hބSN@H޻w /Plĥ`ؕHM"0e39s̮T R38A7/% "!ynTOlІiC0kr$e% k(8FuTI< @$8yKrypkL NV4OHD<@ȟ.V_/:L!a)#`DEgƧUV>MӓmG80W4ӎRHXā3?gk\]ҫ`揫U;xR&,}6M;ԗE^7_<=tLʕEGa{;C_?nx mf1/~*alm2g"9irYsOHgtݡv]U UB2b6_12Ry÷$sK"~%k endstream endobj 32 0 obj <>stream hZMo9+<G?AL;l؞h:o|V:,0Cfz,VWZ9TMTI&heM"eu"rS6rMNFVN*KErQ. Q9#G9 e^9eANE9*E9)"-C(%%Rbg@IgE(:^1,ž(Gš('QyeB8,X5e)olHyR]nAyo{/{N:))kK|d9ʺr{rr#[So :Oj!J$Vf@kDȀ֊ &1% hI߰ 䲎 S 2)_`' BY7A@NL rfQBbY *j$s)Q Sč*<$+%+B^ 9m^BDXaWKUDSJ"RDѕ2d)K15|o9z|?ūWŻoo%^ V%kIoր ԇ]z`gpѺЇ]:߅i\.u]Fuѣy|o0ft,F'talϤx x/񸏗<ǛZܿznx-, {vWMu$\ =?tHINLdeA (NJl3kw܉UK}щ4 w6GgK̐!@'F ey j#`PxdI‘A-[Rs܉>wbD;_ɟㆿY8N`Gh^?jK^7gNdz}n3F>^nFt Y<R?xDSx/dc"7B񏿱 H=pv2t}Uf?_aO*$J e^ ]w.g=?3 ݙ}Fa}ml^ n8C7cp:ؼ{Դ94 Swwq2 v29xӦ-n&h~@ 0Ha?s9ᓽtD=R4[ = eZIv4$RoOta6'6X>ԲV M$f[UFA$5}ZA=''''''lc7g|vt7fL3c&#wᚻBܒ[f_~:M~V [gǷ %Z~ ꠹\sZ endstream endobj 33 0 obj <>stream hޔW7 N<E0\ـa;"^ܹSxlNŠrȻ1gmLkX۰H +5 aƮXGBi!Xg{3wEM95 9<.m&fm >pZ5O`hA"yZ$OpN ԏ$Uh#X^6$` &H[$ T)Tv gnځ´Y23iy J@٠_ .:e 1(lOFјR*.0ejP[ {%mlPhem<&RԈ5)Y L X3B.[R dO l #)$[+ Y]^$'xEeU#;@ 2Ak0ıYQU +otq4h~7oӋCZč88E^?b( qq.C{ qvEӅ8Xy!8W*b 6@~!NOq@@m Vq?e j )n@\8$sgnzϟ?CߋS2Bܯ8²|HmJۏ-3}ǟDxoٗC1>xyFd:h_NZbkh/j]G(<VgJ^ Q +Rxn%blV+6zF%bl^+6zgE^f{.OӤpgj4*ZP1 VBlT^@&*AsZJУ%芅d%芋T+6rF~n~0 D endstream endobj 34 0 obj <>stream hޔWKo7 +:"% ) (A,=RE0@6 ^elA*X͛0>߇÷.۷'<qZjK|ZR 咋rE)9zE++&80!^S43^m;g]Ytș|a;fw볎Hڙ.)s^2/8%fl-g3JF2ZF3&%%e}j|:RvHq_(CKnXFߡ9HMΊXvh:)+ɞ^;Vim0 cgì~Yv6 =xVJ,+l<e[WZm>XˎmZviԭJI*eRRJ٪Tɩ*)UrJJFLJy>x:MI|8dO1u}4KVKWS4)a%y$z%޼.S'p])̱)^l]jܗ2&ZP䶖yo:&%vI]'NneNn e֔9)ˆ1yDi$MYvԘ̔TwΘ_7^YNJ]Әm0f#u}箳IF]1ؖ'볏>z,c}쓏mJ}?o>=wN2풺NG[O>k q endstream endobj 35 0 obj <>stream hތWM%5 +9#q"@Bpc%+čO߼ni=phʯb+I^jJF,DTB ԨP0p\㭈L{%(:޳ |Tmc6L_+&2q+CHeVf2q_\*Š!01'= ^~󧯾_?|}yĂ#G..mmP(=tRY !v$Qo5JǞ)2 9hn x3b5qP9=S e 9 }BGj-x1f#ak%o|zx4#t׽'k(|p0bdvb-~n}*-bGvx)٤d挒st%಩d&YtٔTel$^[Kd:Cl_+%2jelD2p 5T3I5Ħg|#9֚f=\֖%{=2@A .lKmd A֓sq%KؑZP9(e\ƜKf7ɢ8]r̖q_J&ǎA3rP$jNqtd"KؑW3p Ie~/Mi,L̇R2kɎ)~tk?[rpf[ .!Vrɶ>kMdk ]^lR8"e# "@b<= bx\ZzQ\/->_?g8䥤NtNtqȚNtJw:^ӵ5 Z5ފ2q endstream endobj 36 0 obj <>stream hޔXM5+>].WUK(_"Qh-H(=ϳz{=0>}I^JdAE1bV  Wӂm}f>݅k0  (`^DWiҌ\3®r ϊuoUvR 0\>IA D;̭t0[jnVQV000h8B9K'`^ro50@@ƵЌAk=mh-T$\EBRn!մ;V6E>h`nHklqD%0fG9DsOC[@fd +(;L0C`Laf!w ˻ޕV!_W^Noݫݏ~o~◟?{I!He|>|9rJgeҵAgtntNN =tPs:=K(䜮]BQ|NtWE{*$ޤSɒ) PVJ$_!_!_!_!O' |B>!OWWWɷ?cx{7|~~ToTSiL%y1Jct5~ () o9P*xY]r z)*%(7n^_r&/7'жN;#b1w3W6˙hsoYbgV;|$%,g m ֛|i9ǶOdP:A—r[b@g b 28u.yrfYmf1y}b8 !9I?1JÙ:{Íouo8x 11 g(. 3 X90x'ϽQ^ŬufqdTLɁT[x NTn9[%N7 vZL}3Wԁu 3h-ShؤN:Cݦgs=KQPx=1ۿuyb|,vrE[oԄvm=?Yи-sirC\a!^aWr&اA ]~śq=reá'gd['B&MfM&Mnǿ(e<3j>stream hޔX]7 +~lS ,~ЄMЖmh \uv3#uC'p!qr;8R%PkG~( wz_MK1l)0I#"wƀ 10@yD!1RRT`PBj+ d*u[7ft2]{S,I0`wsȱ X0ʂ}Tp' gJp%u : I\|m'Z炿<dܱ/I@%iXGc0XzIc-DYr3v[ Jv%#kYiEs d )#|-%8V/1TdR$i줖 2* 2ThKmHK@tU5cO񤡨xB G, ꭗD0@uIF]pDpQy5pBf5 O#xy,9d 9}1r;(70*XLӧ7?pt巏'o^}{2tr}Hx{ȼw^U,׷y5{>Km^y<7/eGn^z!7/{^K녽^Kz//iq׋y%E71Y'+&%75Q'zĽhRvMWLG_'VDͣfLU'ٵ҉nrX'!79Z9ރxm'1V(fZ9ØY+,btw{ IF?\7ppQNw(pK6pG*$p͂#Rljj yh6Z64L3 )>`M=[lʁ,hˁM9P;l9)J'-6Z9lA)zI6Q/%$%&D(Tت SLEUA*dLU?)٪ SuJ*Ts 2UqɄ- 2EqI zLoGcm-zoz|qevᆪ_7ӏ?|zjMo|oxL77s4G@s4G@s4G@s4G@s(}@[XBr_DEE5G5G/K^,ŢXiEyZ,ʵbH_,SŢt\8PH\8PH\8PH\8PH\8PH\8PH\8PH\8Pvn8x X7hHҿ\o =\=Lg8wrt ǻ/={c{+#<뽟6J_b_??oh~X׍>.ox..o.?) endstream endobj 38 0 obj <>stream hޔOK1ſ$P -EbPRڂP(Payy/CB&H" l(؃g8@qP0Bt#R8KX K(v%|A-FB6f6J[x6s3+]hln:%z1hwM45ѩ&D7N9W}$l{{ݞ>a:=b9.&-yhfG36oCey2ҵ>A**_?%wKLyPNU-I-I-I-I-I-Icr: bdJ͝.!QCD tK]3 endstream endobj 39 0 obj <>stream 2013-07-17T09:41:57-04:00 2013-07-17T09:41:53-04:00 2013-07-17T09:41:57-04:00 Acrobat PDFMaker 11 for Word uuid:e8928920-d144-4b39-ba7e-d63bc440a866 uuid:137566fd-185e-4b4a-8c71-5aaa76fa00b0 2 application/pdf R2M Micro-link specification Schneider Electric Adobe PDF Library 11.0 D:20130717133931 Schneider Electric English Schneider Electric Schneider Electric endstream endobj 40 0 obj <>stream h޲0U0Pw/+QL))I30 1PLXʂTb;; endstream endobj 41 0 obj <>stream htN0DŷƇb.RDʩٱɪP!!gVLJ)<bl$\>/Filter/FlateDecode/ID[<4692FDE684BCE846B0AF183FEBAC1A70><79D92D8E108C1D4585DC354B6010A51F>]/Info 986 0 R/Length 243/Root 988 0 R/Size 987/Type/XRef/W[1 3 1]>>stream hbb&FF|&F )DH`6/X6f| R@QI HAj>- &e@-"62A$'LY  "H`Y0d"A$k"Y>՟-` 6#aiKa0by$_ 䈰n>& ]h(I<8w4un QrFC{Ft5JQrMWh%G=Hw`{ >>/ endstream endobj startxref 116 %%EOF apcupsd-3.14.14/src/drivers/modbus/MPAO-99NQL2_R0_EN.pdf000066400000000000000000005615421274230402600221440ustar00rootroot00000000000000%PDF-1.5 % 889 0 obj <> endobj 907 0 obj <>/Filter/FlateDecode/ID[<8301862F873FFB4B94A1CEF16F018623>]/Index[889 35]/Info 888 0 R/Length 96/Prev 188790/Root 890 0 R/Size 924/Type/XRef/W[1 3 1]>>stream hbbd```b`` @$\ & d&HFe"At xu*#3.F*~0.B endstream endobj startxref 0 %%EOF 923 0 obj <>stream hb```f``Z A2@qK`5s-t,`XCٝ Ħ+:Z!V&6M88,:8@Lt2TfKi@ dW(131~g͸):NsN C 5@0} Vc`ZH4kg`z`Q`(2 endstream endobj 890 0 obj <>/Metadata 45 0 R/Outlines 146 0 R/PageLayout/OneColumn/Pages 885 0 R/StructTreeRoot 239 0 R/Type/Catalog>> endobj 891 0 obj <>/ExtGState<>/Font<>/XObject<>>>/Rotate 0/StructParents 0/Tabs/S/Type/Page>> endobj 892 0 obj <>stream hXn8>H*0`{m& `&BmɐHpP΍Ù#5f~&80˜f i`DR\W g5jp  >VzUVwMYM Ӳi}ހ]^>N"25Fӫ]hIɿIPʒfP Z(cs,AEAl>м IC+"94[E(!+ |䂞{΄@*p3!P1 \:JY;OCU?bh;;F"LPWG L`b3Ou 1h w<)Sl@"EmizǕt(.! N6$Sw"X&2W/-B\r6Rz̼ZD5̼'zzZ ʸ:[V_K_hSU׸e.X +`îX|q8"|G֏pw}5O6?7BȤ\kѣa|u~_Okt<7낧a5u\m|:W`_2v-Z^%#7y!]˿-| 䟤T-)sZH5fs|zDte{& OBi7UkB{}5D`ȵWZG>c3ų7`>8'm '~( ]N\~Cx"?%%ӀCzV( \zΑEh[W <φe<.ḁ%z舆?n1 p>iCB߇{J_doF@!g{||mׇvT7wK+3}z&-a|` endstream endobj 893 0 obj <>stream HTKo0 WE:X1,(<5E5PK2#q&5vL)GcқMo2!pIo|K^ UT!QZ΂Ls"@_h ECLi)U\\MlZA,gBN;4{cĊ.@+ΈiXtEYp )e I?hM\aiŢDX,uSUFor*`H˧rDɱݯ.cA6?OW9!\>#t6?tr5+} P+D3&T7CP^WxVH#VWfdmxM͊wRұz؀te(g_Rłw9orrܮTC3W oKA;,L_Eb9 onzPݙfT2U"  M 5ߗ\G?QGhGSk endstream endobj 894 0 obj <>stream HUN@+YxyBV.Pij $m"gƏ&,.ysϹ_嚧VLdrAi3{&)2k)Grfܰ՜k}YR^%ig{1i޳,:bɱz '"k +<Mz0Yy% o p2M tt4 ?t||z_B RFxYжJ:9--Xg4b+?(\Q5m&ipD= 쌧JlnKqZŕfX)FҦٽ͌q%Lgl2ovOi l)G}ܬb``zCËeqVJH_02Z<rcC{a_Ne.XO Ɠs.+{1;1q巭й!7hԅMP7>39BPMqBQ]]utַ|Q˟U +tԚh?֫jb] .:) tp|=K;n翹 _4 γm9:^رGw /h>>4$~apy5~a%MgCgl5 endstream endobj 895 0 obj <>stream HMo@#{`ͲR)uzhTLOQԐmȎٙn^Ge4Po _o܄x\j[mf 3IA[g:ϼ";H9P\3A xګ-46|N$J<"w5#EJ&_C77V$Q淶BOp; tb18̄5=/ jyߝ\!Έ$ ["(ųCD׆UG%h=Nc*0gxk< #5Y(Wwj $Yl0yZKe"HAiIL(QY R'cm;s|1wn=\]-Vo!-Ld?tbZ[+}|V>~k GmI~ $Ee !vl 2 D؉V&5ZǍ"a4xWG' ?a87dC+ў:,~c%թv7ȱd$f ӡ2hm}aSTlpPpMsKm8u;}#0W0NS>stream HUk0~_qLd˲ et-4. B2ew'N֮c{1*q9h S8;_O.  TjsF,=a@LkMѸ ) iSo2Pڂ\ч_};LAi*DUa'V =)eJG4G5PfovDܠ% UGr ΝmReC  Lv $Ne q -5&){k-?Sޕe.Ȇ!֟`H0T\3K۟;INkńRH^T$#93T9ޱ+_S^Ŧy:Q{. HY%Kl5ᖺXچ[c>oZ ?ŸS3{s`+F߂ig,jwˠ/=o= &2g#u.Vu%r烵=+#`5t!KM"mbJ},!·S 1{fSOl~ yIttoHM/|c-p=̋P;"JF򯖁]&uEݓA4 v@ endstream endobj 897 0 obj <>stream HT]o0}WG[TIZ)ZZCH)!_k_Ӡ,]5/`s9Fq"$ R;3OfRpF a:b_2p+%/!TAsEκ%|0쉻Kҽ=6ỀGI[u*BǍ]ϧMb2 pyy5X7!^s#ѳ3v 9kܘA8ǭYuuoD[:aK FDMEԄ@a=̰Olzu,{(f[ٹXu0puX,uI9vR[Dj}P}~zNJ ޸1UAwV)ziIp? 89$HZIX G*_o0Vs endstream endobj 898 0 obj <>stream HtTn0 +xZ,GaNR;h׏); Kl+##5(NTbP._^P8RkTn\i ct+26b&c[ƪ]~砌[^HIJ%s//bLN1⧌3Ĺ* 8pz6貌F7p~>M\ Gyg6e\YSG! }IbDVc@mZ(#e\t+*-vR# I.T40+X9L, aHC0~ !-L;I d&^ .ԎA?jmKr(P;GԷ*Z >h9s{igړ)#Ci2.wxm9kO\|<ّeOO̷d+V߆ =Q3z\ _Ը(੉Vov P|INvPf9;([a ɻ{e)ZPGr ɻ>ܭɻh3%A>stream HUMo0 W(kr  )A&CkIl~H%qТؖH=~9J J<ϡvO:S%qq\ V&v-ot!}a0w{Z(%pO'W[# ^u zF7:w`okR !4\axeX6F̀H'w@ե`O",q*.G'(TḰ9;˷uԾ)䘵,pwX1:1 Lp`D.٫/!D=]|6ÖcKLI[I|<"ma3"֏1}| KzԪ?FWsM~L7#Z"$kr-Q} Jc DW 0LHm72zȲ!'$~ "NL` ucKK5M}aK]+v #2+>3uIȧ,U%9t _v u.%H!1(_Cf,FRx}iJ7Y> mS'ũZKl?-4Vu擴F :P:@B]CBYdzAd34;\X*s*<2 ]B6̛6k>*4/9ޟR endstream endobj 900 0 obj <>stream H|Tn0+V) @'Ep`d ˌ"6S[jڿ4@/"G-c׷ل3 [HfKЉŧbi] O[ !_Qy%>ԷB#lnda_PR8)eI:*HEA|8G-\P\RKc!q N*`B(NJ x-5#[7J!N~$"d߇ 98b+2}MF> Fq&ЧZCh;*MW}t1*[BpEcG(m20HNEx7ct+4Hl: VE6iǞ?k{6d+m~ L5|ڞYy{,m{݉;3˿-8lN\ [p0eRUUY`蝆B1^hY~0}ڻc{l.躦 r,:|:a-<aX4΂J` &.UA~}玐17ݡv02" ~̄Fx Ȧޏr .XɵfK&yYh 3%~Ҋ It;WY endstream endobj 901 0 obj <>stream Hb``$WR~  |@T # 2 S/`M.(*(%8H8c- fԉd9@6_IjH9(3=DR1%?)U!$5X3/9 ($5j%V*'&*r"(,!!0b;CҢ2(ɘ I8/ endstream endobj 902 0 obj <>stream HyTSwoɞc [5laQIBHADED2mtFOE.c}08׎8GNg9w߽'0 ֠Jb  2y.-;!KZ ^i"L0- @8(r;q7Ly&Qq4j|9 V)gB0iW8#8wթ8_٥ʨQQj@&A)/g>'Kt;\ ӥ$պFZUn(4T%)뫔0C&Zi8bxEB;Pӓ̹A om?W= x-[0}y)7ta>jT7@tܛ`q2ʀ&6ZLĄ?_yxg)˔zçLU*uSkSeO4?׸c. R ߁-25 S>ӣVd`rn~Y&+`;A4 A9=-tl`;~p Gp| [`L`< "A YA+Cb(R,*T2B- ꇆnQt}MA0alSx k&^>0|>_',G!"F$H:R!zFQd?r 9\A&G rQ hE]a4zBgE#H *B=0HIpp0MxJ$D1D, VĭKĻYdE"EI2EBGt4MzNr!YK ?%_&#(0J:EAiQ(()ӔWT6U@P+!~mD eԴ!hӦh/']B/ҏӿ?a0nhF!X8܌kc&5S6lIa2cKMA!E#ƒdV(kel }}Cq9 N')].uJr  wG xR^[oƜchg`>b$*~ :Eb~,m,-ݖ,Y¬*6X[ݱF=3뭷Y~dó ti zf6~`{v.Ng#{}}jc1X6fm;'_9 r:8q:˜O:ϸ8uJqnv=MmR 4 n3ܣkGݯz=[==<=GTB(/S,]6*-W:#7*e^YDY}UjAyT`#D="b{ų+ʯ:!kJ4Gmt}uC%K7YVfFY .=b?SƕƩȺy چ k5%4m7lqlioZlG+Zz͹mzy]?uuw|"űNwW&e֥ﺱ*|j5kyݭǯg^ykEklD_p߶7Dmo꿻1ml{Mś nLl<9O[$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km endstream endobj 903 0 obj <>stream HyTSwoɞc [5, BHBK!aPVX=u:XKèZ\;v^N߽~w.MhaUZ>31[_& (DԬlK/jq'VOV?:OsRUzdWRab5? Ζ&VϳS7Trc3MQ]Ymc:B :Ŀ9ᝩ*UUZ<"2V[4ZLOMa?\⎽"?.KH6|zӷJ.Hǟy~Nϳ}Vdfc n~Y&+`;A4I d|(@zPZ@;=`=v0v <\$ x ^AD W P$@P>T !-dZP C; t @A/a<v}a1'X Mp'G}a|OY 48"BDH4)EH+ҍ "~rL"(*DQ)*E]a4zBgE#jB=0HIpp0MxJ$D1(%ˉ^Vq%],D"y"Hi$9@"m!#}FL&='dr%w{ȟ/_QXWJ%4R(cci+**FPvu? 6 Fs2hriStݓ.ҍu_џ0 7F4a`cfb|xn51)F]6{̤0]1̥& "rcIXrV+kuu5E4v}}Cq9JN')].uJ  wG x2^9{oƜchk`>b$eJ~ :Eb~,m,-Uݖ,Y¬*6X[ݱF=3뭷Y~dó Qti zf6~`{v.Ng#{}}c1X%6fmFN9NN8SΥ'g\\R]Z\t]\7u}&ps[6v_`) {Q5W=b _zžAe#``/VKPo !]#N}R|:|}n=/ȯo#JuW_ `$ 6+P-AܠԠUA' %8佐b8]+<q苰0C +_ XZ0nSPEUJ#JK#ʢi$aͷ**>2@ꨖОnu&kj6;k%G PApѳqM㽦5͊---SbhZKZO9uM/O\^W8i׹ĕ{̺]7Vھ]Y=&`͖5_ Ыbhו ۶^ Mw7n<< t|hӹ훩' ZL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km  endstream endobj 904 0 obj <>/Filter/FlateDecode/Height 1201/Length 3766/Name/X/Subtype/Image/Type/XObject/Width 613>>stream HcaO"R4UK'(?Jɏm;v3q"ʏցmKѶihsMs}6u?/xinqLbc]cԶLcl*ww;ѣv2zy}= sTcg~4zڳ=)=vDc??z SgD1Lٯ۹o&Ñzu8z zgmT{fd룇0Ȟ=|;yOF`bG`b"Rdn]EvLWW0W^EvL^Q99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999C^EvLUd^n^EvLUdo\OG`bl;;V-OĞ>;fdp3S2z I-i=UcO¤8[_7\1LiED<5z SzƖs]ellyp&[^=鼴Ȗ]=||mW=l\Ɩ垃g1iLel-SfƖ=)yƖ/٭: p):\ ri9P(m\ԓi|:ga|&LLqV=1qܹ11qcxαr)>w~_۝/G ~da҅Y7%Fz'?}x~>dbg&;|Dx= k*'? w{ ,W(fgWoEVgfk#}b!ˣsۻCLsfVm=}]ׯO_l.Yg|qrS`N?쮮<:8ƛjŏYw9=yhrQe+'Y#w2Of4>̫һ\d@c|WɮwV9}t >Q}]Qh^UyޟZcgYϢ<[Ze=Kώ*=]걬D9Wu/7j5mdsPodb^}2=dzidnkhIepo 嚑v^@fdТ.w7eym9DhlЪG o#kndVVzYin1.4#؇'idYOe%u={+O^BjF<;l~Ch]id< "#Zٙ#{ 15#.2¤ۅ 3"#X[`IdÛ CMdK#؆ L"C"#ȈD6<.E)/2pidw@Ȉ5u އ "#\O I,le lNDF${dFQdJ#[ AEF4M6!2%0id6 ydxȈFAVEYo]W!ʘ֌,7w,hrV ҨF6Z׭4eҌ,_Y #"#XYYn.B"#X3\ez `Idy17.2bMA١$к&g!ȌȈD{cEF4)2%߄ "#XYuLhId)2/2MB"#D 2'2L@k+kdTȮg=uYUDF412ZɋXidCd|Y.2pid!pDV C"#ZY# Id H&2%+mdmJDiF!2$AN-QDF$2D)DFfdݽEdK"(E-p ]CdDJYuuuBȈ&2¥K]dDDF8YQ "#'25#˵w@B&2‰pid&/2p"#\Y$A DF42DF8Y[∌p"#=8$/Ld% endstream endobj 905 0 obj <>stream Adobed    ' "'''''",////,7;;;7;;;;;;;;;; $2(!(2;4222;;;;;;;;;;;;;;;;;@@@@@;@@@@@@@@@@@@@@@@@@@@@ $2(!(2;4222;;;;;;;;;;;;;;;;;@@@@@;@@@@@@@@@@@@@@@@@@@@@'e"   e!15AsQqr"34RU#2BSab%Tt$C6Dd &'()*789:EFGHIJVWXYZcefghijuvwxyz 2q!4AQ1"BRabr #$%&'()*356789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?p`a qkA$@c$I1jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁>jv`胁5qm\Pk溿YNQ* GR `ւ+.Q,&Gcp *;(c/cqTy΄D@Ћb{j dvZ+F|XK_$xCZC:|о""" """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ """ ""a ֒/kA8(9p e!$4D|x" : w،[R(nL`@db1okyH5X1k#^- DDD@DDD@DDD@DDD@DXE s@kA$ (3E_[8gzX䘕s8F_5loU_5OmOQU5x_~jѽ?҂EV|գ{t>j}?҂EVb|>j=?҂EW|"}_OO (-UwQDAWߚ/U5G_ITw~tEX|D/'MDB =aSw0t57} _H,UL _IS?D =cS?D|0tEX0t5#L/ V?5#L/'H H,UH IR?EB 9cR?EB|ԏ0tEX0t53L/ V?53L//5CD/ V5W} _Kjƈ0BNf>$T*-[:Ѕj@lhG1 i i|v9"v9" z}~m1gLag5Xs]]yim7Q [dS],D0|`hy>;1~Fƛc<e۰N/盔Xe$6,1blpv]䪳{ bE; /;>w7>%iTsE3#ȭFfδ|S2f}0)$IWq3 VZWNk"DPQvTJ h__y&;$9dЬhr{DF>W:2RЄG@ G@ҖH̋"ѭ4ѣ2\ȃChF@R B^r/<7gkg5]$Kji[x\ IyX. $S0e ̒ю#c/AXȡ0'̊ю+ ?CyY pH+ ?CyXs@qfY@.ؑ1!pf2+_ ?1`VAX|!0'̂ю Ay>d0w1çi҂C1`O?cJF3 7Cɨtg g BϣCyYMs4O(R"p$?1`S)l%2@PԺ]I5i&X[AWn`݊A4x$PJՅ9 b3ඵmh}> ذ(< w!Z-4p#+qi`)i4jkvKF1Rs """ """ """ ""еg=a[.е=aAB[?t϶30Li=l>5Xs]]yim" """ """ """ ""amq0TMsG+975C꧶TuIˣMsP oYUgw(|܃ /PZ\*A W9- bEB3=6KCspʃo6 7* r-!:+4 Z>Zf簵ݰϙApuYx.sQjMtd (O)ήL[^/Uܮ9riWqLdW[%-*Y3b1$ yً:iRNP䢪 zo\4hk}0v_ %@d&9*v˱W8OQ8bU$'9iMoG?mOSm`k@p-nMMh}ZcLN*nF|<d r$-钳y䯹 4AJd,9)DHMWHZD[ k hM9Wn2 * Pe|L|L(Pe=/A9F‹(&2j6v%iHLK&TS8xoZe1ͯE3,]W|0r\ )'kI@9)eAЇ6Bh{bKEOMTҎjhD+S_Xd]zÅ(xfCgNC \DtG֊eepiAl}S0/ s!0t8~Жl, ZR pSb/5\Q`2dFҜdU)P2NEEa)@=XB {Xo._n|?E1}ѹ RD@DDD@DDD@DDDA-iXy˴-iXyP30Li=l>c[?t϶5Xqk#^- DDD@DDD@DDD@DDD@\L3<&jk~0AYK8k;C6\7ʱP>AmgderFjZ/;&sh9lԴa^ p p$sK7)#,Qٳ alBfKNz.+VV)b + g%!dqg5^D>ZMwe&|W|6cF 2Ry',Td`Cq>jfD:k 4ٙ}dcFi5ї;# @3]7+&ܓ/5NjWH*,,u՞C{7m\ާ"-%JڻIZGŲP88{0sgK Jiƶ;ሺָSr_{ܷ8d@7[2o2ɥiW?,N fZrXAdrMU"5NƍN|[ϴ塸 C9 V$9<2Z{aM،ʘiis\ NṰ| VTxfM n\o ~ ҙ|^MY(@H>E*s"gR/tXg ɖs6,1@\$JYtt,h3 DϤmDnsimaJfqQ !y9NvwVʾqt S~K'M\4"ιffdB] :%Sm*t/HǪUakIPăm9Pi3b8ʉ R>ⷄZ8)J+..ȇ*㗜4TKŃ;-4494^B˃_ *A=i+}pp}^! C^ԁuw F1 =a]͆-y:!kK۔FXhˆ$[Zi][>Ŕe(]U54["ͳ;gnims-[.hN dkAwU҈@{XoH<ˋKi8=#PiK;+͜/z 9N>E,ӕʀ@Zl+>)]v>%sN!&H"?'Jك1ʘns3 adC9j@FȖl@d`.:8sZ8s& *ݵit-ε͖S&Z Ѳ䌢W>P^O.$/H.g0ʳ v`Z;kz6|8%kh3hיwݬ5@$|fZG ǽdhĶׄ)aVqJt@U2K}U@a9pX  Z8?r\>;B՜m;B՜ =l>c[?t϶30Lh5X1k#^- DDD@DDD@DDD@DDD@\<5<`ڞgߌV;XRN ;@ ^K7ʟ?T#hG$J G44jnʳ hlu#lLN1xS#h fЂG!Bid@SXv([_4(B> 8fhAA/y/4C7> vvC7>aS <Hb<<L: hW_B_BJ0TRsm!J>J8Ր($-¦' >w/hxb`5h(+,nC|_{3 Fj(8aOho} 7Z 1o} لOhq(Wڠ`hwȾ^hwȣyU\k:טÒ.E=PO^'.m.ifK+PG*vì!y-~\CshPKhx2@Dž(L:TDǥG}[%'پ̂ h3 L&rԑƝ!6i ܓ%yLIŸR>uW)K=aQR. $>7:ӅjØj׊ȃ>c[;t϶3]]yymWw ǖn"" """ """ """ .ꉞk~0]mQ3o+8*k]r.Tp@@*;fiC?~&bR3q/D&AfKCEA:髠x"$JAV@+UgA XUd0VUڼ꾃T^`: Yҫ Wh++μKuzT»=Σ,qgR /fu4Le8dA1TA#H]boբ$7ֶ*FҸKoHF<Dz*2&Jb$x6l|S;"=WK٣(ǁeEkJrgl# |vفڽhEw9 3v uZ *ǰӋgt!!/5Fŝe9fl] ׯ?^a gjn6`ct n?t(C9=:NxqKHp.k{PhI4(R{+ÏS hpƒ=Ns$fСverMc1WKEKa& qkcs`|R^4@DDD@DDD@DDD@DDB՜m;B՜ =l>c[?t϶30Lhm]yymWw ǖn"" """ """ """ .jF`g `p3?@ 6kHXAâsS^]sBT /͊SJ *Bhυ ɉsƃ%'m9XC=ڮBU*i5PY" """ """ """ $V^f}Y|П;|] n{$VݡZsxHѠ t5=Bͮ9ȺmΙ͂Gt-B&Y,CMaePRi0҆]T|DЧKV\kvDqtpXTJlCfW]]kWZ8 ˲_]k:^eܔ3pFP^B!`e- ZDk:ug֎ ÑHpցLVC!`sY$NCH`ge, ΝD ?8~4zV LI2v\u :ai,\2f`A9F@>ڄ.jޗ{gE- i!5qɭ4WKKI6kJZufnݎlD;%&LPLƢ7kT4͖,'9҄pJa+he8J.vvaƫi l\]Z3Rv0N$(VTԺͥat9&0oHKۥ6 jWf^͝(Ța# P ,nlTF0.Ifd33IFf9b Vs֞E VsD.0Li=l>c[?t϶35X1k#^- DDD@DDD@DDD@DDD@\,78AUʰhWm9*Ñ r"[N+i0 I$"8l~s}G BC bp|ĔIx3h*:v/rYhoڇMhvhD`3O 0 h$-;>Ɠdw){[PME\{fXvuԂi(AA Z4)VE frkMHΩU&d/}( 8|@:!}%Y^'8"PFn\_& +Z JJ$QTEH((7LnyQVxԧ1e7Ml`*>f鷕>UэS:W|5cykğaĽazlwI4άh @n̷*D ;p_hAP͞ēC iZ{IOʜA4}IMWɓOpl5?5^a5%51奱k|V|@% 篩xqﹾ:Cڃo4B`GD7{\;RʙnPᝮAZKfCiuD\{f%XqHewRG#j#̑ś1ZNb+h ům[`A6t9ǻ$hx-Lp?3?ÖM ߶Lc~HAdn,)NwaS ıd#i*h>;B՜m;B՜ =l>c[?t϶30Lh5Xqk#^- DDD@DDD@DDD@DDD@\88AT4w=Xr6sEʺw=Xrl拔^`Ba:ZP|ڽ]0kI'6!C@0K]Dp]Zd WtL<nȫqv-0LIڍ1` "iCX}v(}lMċV 8CvDHvcGi_A cqZeG$tV::?j>Ֆ.ذ:P4e7h XU ?7td. ӯQ׵+1EX x9Z@4ud+*ӵ|66ܫ|*D^Ah)N/੍/*)Z)N/੍/(7p˿mz RB {훦W0lX{_WF5LE] jc`ZKBl: t+/PVĜiC K>Rȭ@:xiYQ'"5-)7Ivfv/ fO`)jG>jMK09! r `@'qXA8Y0m0Qx_S:s|ua=fĒ59ZһBf=ғ sH^sK"zfcEn 3+By'4ز-q3Q1"H^r\Y ݵҳ-C`@i,|XM{c;A|0hJ h-YXyӴ-YXyP30Li=l>c[?t϶5Xqk#^-" """ """ """ ""ag XmyI^`X|r =dM!.SHD'&szE'B wÐpg˅UdM] Xҽvl|Eyc ZQ: ̈c"$7;tU$04UH:nhN|A i==Х-q TgTC&as}QZ(A#2ȶa-c6L:.p~z>;B՜m;BԜ =l>c[?t϶30Lh5Xqk#^- DDD@DDD@DDD@DDD@\,78APz‘#g4\Uw=X2.SE`u!l_&m9y/u sp5=ɗ9ŢNjZq_H~{;yiZg&t̢T3F^5W0T^4+$̉p#9Nh7᠊-i8n%m||xpm ;9Awsó#pp@ Q=+*X֋(=R+2:xR<;5u8zCࡀ0ytƘ6P}XBlCFi(\i.p gDR_w헕n1e7ٺmg  {雡yYcSBWF5LE]opx:V-9cDlFJr`/_jb5H#c tٲZ4ފ{Gr%w"܅c`^q: KIJL;A+ů *rzׇ3XM!,\-4!c[?t϶3]]yimW8w Ɩ؃yp0S3\ 9<:ǞN؅_zJ5L7ǂ׵-k+v/XoXĴK>+ZjFqJR|i 9pLEcKNM@i<^纺$AfnIEkJg%b5\Z٨9\$iu:h r@riPn֫4^YY֔Cڥ|.*Z"Pl9ug :֗4VX)u@.86p 9@BA}'j>R?f9` 1eG {雱yL`jx{W/Vk4ؼ?:!!\u碮a np9PPnȾv{WS}E U* )*&A8Trc/R1x #.gh' J!Wzx0e!sZ]!Gé'9&*!<{p|la{K IK68-p"w=}LÎ}Rd2}61&VaO@i =yC腬h$V$ }ZN AYs?u3ru hZ20YG 7z?(AgbF@j~=mhZ-hZ gLagz}~m]]yiaWXw ǖn""" """ """ """ .jyw,y6yu*{VysScڷ)ԄihHF2'Bxŵ ڹ-g nq\({Ð 4 ﺽ$#pZI\ə1f"FM4JC,BKkPvT%$2 8nz46/g@Zk\**9s.|K-2C&4st a9D VT^5yeU]W2Bp<-ٽG{ Mfn>IN0E8rt AЃWگDT?1x^:XTk4ؼpȇr,݋l{W.(Ʃy諾XBr/ÑgI4 , Fhs^z SҰkA}+Q1=c Y`Ɨ0dXUmr!k֞B8,ƺ.YiBspa冤q--ř\A:3(gԵ+uk'"~!".s,9Y8Wpg+M3b^ r6׏$U|Xjm>|JYsê(f+F֛N˩C5l6Z V1jF*e+9Y,Uػ?mX YK @""" """ """ "" ]j-hZ qgLagz}~m5Xqk#^- DDD@DDD@DDD@DDD@Q>4pJ7K/>)W;8u3l R9)5 &9&SfErFu f:Pl6z2Zv|z4}4/&H+6eZP=^!_u7 {zY{zBRcZԕA!IpU}-1((*)CU(8Ǵ(5MYzٔǏj@a1wb7v/+ <5!\u碮a nȾZsE=ј/]]h6`Isg+b ݙj<=p뚛A ~efl1KjFmk֞BLһ^O!^61[ JvRl0I4TqsƩxqﹾ;|.Q[KlBf3eNw]XLj@\# dƓ-4p-אPj*gȭVpH12Kf 9Es"n~3#,U+ʰwKCX|v9"v9" z}~m1gLag5Xs]]yim7QkfDM/1SK!,/rc<pT|^=R h#=T.V v.|IW@i$ 9wET֏s6rC3l^\*YӲ+2#4 ͮ;npLmZy6ayְ$ @v.#ά>aqD0^׀ g0޸\]lDq$ƒX֭m **`9xޣjEFg-L7/+[. Óʺ1fz*E҃nŅ  T59깃8/}#c\JTAWbTAUsEdf߲x=/e'yXX˵cB Ţ+Q9g"۝yX8c]8\Qxqﹾ:)fd33lp: ķiۗWCۓR*t:JE\9%>ҴlkLڒpf(^Hv^ I JM#[wܷ[)>I5TXH[*mQTVpnsN’-UJc*)Ϧf+!@""" """ """ ""еg=a[Nеg=aAB[?t϶30Li=l>5Xs]]yim7QoMʱcvp0eX\`vi SgS;r?T-מ'ϴ2:y]M6/(Lzx0ɯW~͇qAШڳk8נ'MP{OkǺh#q;WʀVYYE0e϶29fUis]A3.e/A}|?A>U7TrCh XqGgգsZJCsZ^zgV̇Hw/[l3yy rjMLZ,Az5:I f]˙}^cÌBoK{v2B~fyWӒAMAف^W~Kzqy }/A>ſkY.kж'I޾@S6s|u5S`ƄN뇑|lW ?7%M #¬4}Zpa˽ A4k4)ިaKOtwMN`K k@ /)INacZlB &"6REH(6uH$s >.V͸?G .(D[/*PșOϜ%Ė nj}w/9 " 2AH"3 CE*:d,E#(ٝy=EB (E o3Y]," FR8Zدas)yu)R[:W7jj%dEq4p "%5џNA[A 'C+@R ѹQH^ٯ ;ŮksB"z;tcTͼU,lA" EԇgF8pp:kKT]vEOoiCc\ {e‚G$# +_WWдpJ9seg۝rS<^4e-{4 e, `{#G-sYlRBS6s|vE|&UhY{3 bnU-?nVͱ^_kr!$JJk)'0t5M?M\Ц |v9"v9" zۦ}vm1gLagn]_yimŮxV4Ȉ ʲKQh[ϚcKD}IA³prَ!r9s$i恰Bdy 3S@Sm.p4~l(9EMuiL'-Η44ڦ6"DtG8PFr36* /P"pkI 2^R6É^%KLNA?7, oJ x@ PN@&]DZ !;ސ-wTд Zh#|,r<6tbxpB>T(}!F jҾT>S‡Yr>%J'^ANOkٹVP ko4-L0!aܽov'h@fu1 B ](pnƕBUJ;Olbiu,-E8ҡJ أ˿*|?˩aj,Va!jMF X^^?bDlVQXK ^֯~yXF6[qtkgOʙ`a%}`Y {3~Ο:7lS5Ql4{,kgOʝqt~N,kgOʝqtЉҁNCb?K:U7ߵ_ 4E 6tL۟nG)3MQ06~A|l?Bp~}3F;zg[;OCоV) x= N'zoovy !Ut= [7_CЦ4O58hCjfv0V, )ʊ!nS'zd?[䠸Nv:nt9^3Tf`ʶ7lS3~ΟuME1f~\hQK@}_ .\f?*uoTmÃ1U& L\YF=)L7lS3~Ο3U~8P;SѱiWfţȹ@SkhO+&MkgOʝqth  1ִkkgOʝqth:ȹ=qtkgOʙ`aCkgOʝqth:ȹ=qtkgOʙ`aCkgOʝqth:ȹBћ/ʲ 81L_4m 4Z x~VTUĤDE#hZӃu)_rS`d$K!Nڹ5vEtd&U?R+K.kXPZTYHLĵ,I9`B#g,=Upq Pֹ4Χm$Kݚ|n ĉ4@= v/Y{Rr^3`OB 4s;ARp,ę#p%-#'4+L*6ۏ2f46@Lę#y-s^*Ƈ8m\C `Y"G=Z@ݾ|Y8$q.!¹XQb1- NKZj ϕl#2Gۑ%eW@-&+ػ=I;Nm3pd9$A`d$KM.cSٔѴ5ϝm|J5b>8fU@$K&H3QZ"nC qc1a Q ͫKH M8$q-nɉa5ƒ \NkQ}m(s358"+_r`I8.ηZO;[kI-p/IF3# iHm,%mh  `d$K/kGn07;p!nN\6 F|W%6rGd%v4|۠ҀP+tM$&:J")LKHLĹ]Տ3\ &p6vјጴ6#Xh:+@I'KK$q&H\yvD3b0B#n#|8I !Jw,I8+nN<&Ed@Z1(i8<)^VLbLkߘkKHLĴ%-)/iqC( t,eS$5s"T{,ę#kD֐$?ul>d$K(̑ę#}D̑ę#}D̑ę#}D̑ļ- L/TI$sOC}+^k<%+ʻ+bYƁZtTWpiS(g#c49^)#do4Wdg]nqƼv9"v9"*z}~m1gLag5Xqk#^-" / Oۮ"o X4Lu,z48=:UkH5ܢT\)h5"+R"՝%r^OUweäצSM.sET$\޽7ڟНzo?3ET$\mg0ж&9-R3Q\[tDV%Fg,ȵJê왌pIeT{N8VTļbp}$[>֖&aIHAhtq'ҤhLjͱН (ꌘD׵cN5ށeg\j^8y9ak!dōYX֖Cg'0$ ƫвlc,gDD2 3EDG#`%F2bqhYDЊĮ+gf=-.s8"L!N b? nzvK@u}%.#0kVPvW iűC%?dLd֓] eR hGsbk`(82=շbDײZD6$Uxݭ&ٖ\s4#+%5%s "Dk#DF<$?YzX @!$d*);BT6]~Fs_>жl9f48lɃ .p {6rHJsf"89.lA7A`Eą.QvEWDIB"s[2Zqf |6q&rYYycb8|7;"h{8}A7k!b5øGeyX"6r&D6D aOċSAдR$lF3AvVx@ЦHtyY#<8bZ[RVrRs1&Xؼ#.5nshUDQ5UgEkRIEӚum "j 9]AbFlYΙAi S$+anQ~D=]KaDErDDAҁ,Ǹ=W^|#V3ɡѡnQ8MWJlΛ,:+MC5^/ȆG $G8WJk&=DEz\RXEiG:k/YO/Z6%Z+;F{7Mc[?t϶30Lh5Xs]]yim7Qs-ฮ[śqTNcZ{}QTjrJ4DW$DDD@DDD@DDD@DDD@DDD@DDD@DDD@DDD@DD+aw7+aw7Ң::M&i ]5 䱽Gq&-R#G!123t+ҷb469Y .\~@jČDDWDDEaY{=խvaEA ks Lڷ$gv窢e Ev\Xa5;*еez% ݙ&:c픺іwbu"/ y[xZV?ug;miXcjmW3tjz"v9":P30Li=l>c[?t϶5Xq]]yym4rؔ+=kqS8Q kpف.-͜Y( e!7.E,-&#r]=+jŒ(ƈ0hW*\{x.*sD|+¶Kn9We[AJzs[+L&e[AJv]$.BŒ(}A*]nv]$.eݠsQUsk;Qu1Xe 5H.난Bt;y,sh׌Wyhs[@Jg̼Y0E|&y,uFIhu~EjXx'fl{{Xp X3NL w]88. ])>1ʠ'ݢųìd-k2¶A;. Qb%:19j}EU3XQ S|o)+R S|o) S|o) S|o) S|o)Z֯Z"[V*3j(9/LRu S,潏k ]@CE Q#pkE.Nljl^a`|7 `1e@ kKl.'ah99DQhy`5s^zΙLTӟ1̠s alIЛ 1eI5ʤƫi+kŞ/xEUE::-]%}uεV6(h`MB{.ZsmujJϳ0 8Aus':ò- wlm󡩺_; ph;]Zu@lfseDe]JȪb.TiJq:i9XBN,(Xh `n6lQZW$/Crڍ[k;.̂hse;^pr >HmgB(h@k؊i+ iP ֚*i+Tma*_-)_ ".p.RK&c Ru|~U6Sag#zqI׬/LtJ׬/LtzqJh#yى-Lk+3-<ფ4x\={6`B.kHdU(Hm5Mp=AEew/+!ꗀ5,&MMWlUxNw#ұ?핻9܏+o JW;Sj{ VsyӴ-YXy҆~m1gLagz}]]yimŮxV4Ȉqf\WMs-สo9Tͩ/Zw ekIzs[+,"".]ݠsQiZ/,sZw菭/ȧ[UgtnM\l>!8ZcC[V|H9̸*UbtH yF1Nԭ*+z YK4{ghhh6v@8B\v[zzӗ|6G2іӷ u"#]eff5gj]v;WJ#A րݥԖ mL6qz .QfM9,[#A9ˀ̐ïp8нm ;43 te6+h{ \*q)nL^q;{Z0Z c q̳'#o\MWJ*&bmC=XE kU͔̦Z|v;: h26TkZ3EwBu@ 8ڍg: ׸N[&@ uQL i hNp&o ]UDۥ6" ח(dӐ.9$tt= -BVR|#p ؒka9aJ'L,jV:u!6^o{4WOZBkV3?U4ڻ@0lCDrڝmQu"-Dq-ZƲ é䡥6}&In}ZnָDSQw{guy2rnjb9$`ēg"6 %캸FFe֨DSQwlv-he r8 KFålwj&12Y/dV|b쓴|t=Xs6ˤDD#Am=\21ƙM: iyh/XH!C\QCT^[,씨l&i VlF3ܗ9‚@WI^vW|Ge.e؝|:KsVf9ly[xZV?uڟU'hZ-hZ5X1k#^- DD̷7kow&oS|ʤUmIzs[+ZKֻ]`iޯ^l W/^{DqrlѦ|7ٟi9M3iӜO 5Q4N=>1p"mwjl;}ðrʴ^U,H$CIpÈ2b J{"LÈg/hq*+K6%3 {6ǃ5kCco]@ ma$>>k,K+ј]-$kTl?KyMc׉ u4UH2=*U0-xPZؑs["| ^"M(QLmȍsc /3B_jȍxW{툶fK~v5^݉-/q.KMsp }"cT8Hm46](E_-Gw'~} T-do a&utsV~}ªLUQ rQJ'D|Ep5k[QyWK?8Z 9Qwڹ`fks;~CPiq xq 3ZKr,,VC@VĝHkSd&a*I ]Tsm,xNw#ұ?핻9܏+o JW;Sj{ VsE ZsEtqgLagz}~m5Xq]]yim7Qs-ฮ[śqT_SsA/x/sEjKCrI184P԰9#`YŃi|㰚V(DA +N=*,"cٙ#򮢢sr:ùL3ur"#6Us|Qm.o_ /S||s-I7||> >T=RtszGʽ%hS16xE3eDEjDDAz b:W]$iJ֜Z~\*l'PA>g*+UUVY6"ey_lгhpcR}¼"…w(g5}nUmh02t 1ma""%9܏+o JVr<-+s^zOu-iXy˴-iXy҅~m1gLagz}5Xs]]yim7Qs-ฮ[śqT/"MiUix, Q,=$-=Qutq.X)ؖ#t̖4Ɗ!8|]೤*vݡ%vb6SK\ɳ%JKB' 049TZTS,iLBacVDiGiDޜ(ٙxthOct+jba.D;BYk(=н2/!tU ")Ef]3&]೤.&S,s2/!29 wK9I4cFTq./wsd>X'NBҙ3p>MUDYdKD9yu-ipA,[Ov˭qsK[O(P `u_ҘwM,Rb8WQjIH2HēmM™$r:ùL3urRO曖eodVr4ܵl^⨫iGL/0V|Hѡ$9v ĵtKB֌K+JA2G_Q,2G\y⺫Y7.*jhDH93Z kb,'$6P@ppε浄.Aף[–y.s3*n:4ٲ㖵H^C.++և5j^ɤa;a⨻]舯KsVf9ly[xZV?uڟU'hZӞȶ]kNzȽ.0Li=l>c[;t϶35Xq]]yym7Qs-ฮ[śqT[[Saeaau3`JҮsA #$ %Xkj[혁9 oᡭm$RB j+xq-(O6c!7CAOsQKw#⩔v?'T]ʉB*{ h0Pp 41λs\#B0I1VMsie5^ߍlAِ`y'\Zy`Ż$Aj yq&Rv.P:Cf\aɾb;srkvض9xf΃$RGخ-hLj4_8Fm$Faզ ]]'2֜¨12RRP9qoҥKHA˶cZa:σn[b86zZ-Iyxp;S ʮ5~!i rA1['+*!ǃs8JӉjd tiǸj6]^ 4; ƴl8pDLThIΥAiAe+"Sr`ŷB$4 yUq$bLI|252}U@DDD@DDD@DD 8, [4MH=+#:4;YgaBm.T?Sq͑ tR'Vhh,x&76KJ顦oZG" ٨QQ#B1Z!<= Z-e.k]G OPI;n der.Xƶ V18 . $9sU$ [ZU.! =5ڱ1qs �.-#Ľ݉m=5e0j41г)_ E W24/;.N0B Ab5ܟ7-:7Sɗҹ%ƊF܍7.gDꉌLH/?Ә) W|(mc^@$ FLQ 4lֻ0vCJZZ kj>s|@袦^TFcCGԯk&{Ɗ5NP9'FeMvC_WsA."+GcY+vsVf9l=ӎڮg^;B֛E Voy҆vm1gLagnzۦ}m]yimŶxV4Ȉqf\WMs-สo9Tͩ/Zw ekIzs[+,""-+c_.V;?JumNnHKLKk#2QM>thDqkebÃ37 G<BE3)Wf'>.Wa-4?9#?ҭִjl:o#K]?#bҖ XұLCkk^3&k0[h~s)F } 5[F%s}2>*Zx?ă$F(nuti[<`1a5pƦz荋95}Mֺj'L'S2ql,xp1 8"jKsK\iEs,K<|Fҵ;+zRS˜cL$ps[l+ E\"D/p4J99Em rhHu h^׾+\ƽi0ܜ:Frx8b 4D\0^Ƕ,-uG0b "(d ^0l ׹'$6Tl;aC>0 ÆEูƑ*ݴlXb!9-#Oϛ}+ھA;ZCP5pjȳFl2rW;(qfٷp~S]]3V^ZDTp9j݋[m=T얀$iNHf-Hg+{R4?OI"N–{` ѭsh ʖˋhjr$yJ-4ИxZ3 ֺT!̓1,x\>_09O0~̰ԉ];eG^35111tӱt$-{5t/'jǗwC5"iк%q TV$@DDDA5ܟ7.lWAojHW9EԌh\2dV]xT]-UdXױulF > îqZ P4tl> gnoGȝOh{sz>Eֶ%sƙÀ2 AӤɡkZ+KXB_$Pg)}Sޏ:|lkZVg -. k(k&E}2bA/|:g'"UU "&kXBmnGhؐèU44Ӛ[1ExqDa*n:4ƒ&r4:)U؂57A`fgZC@;MtBm0h K';miXcݜGcY+t?׺Nеg=a[Nеfa^JZۦ}vm1gLakgnm]yimŨyia DDͷ[X ʛjӟ(|jFi])a%@r|ȋjzȶ^hlEjTV0Li=l>jUݣ;M.g]"#Nm[I)cWX W+o[`ég}IN%nXN NԳRΒz'U̴ɂYySg}I[VfZudiu,)Գޫ a3-:`wtYyVU같Y0Z]K;:Ju,+wuXLN-.%:wta:&eVLRΒK;:J객V2ӫ& Kg}IN%nXN iՓԳRΒz'U̴ɂYySgxVU같Y0Z]K;ΒK;Βz'UY0Z]K;:Ju,+wuXSiՓԳRΒz'U̴ɂYySg}I[VfZudiu,)ԳL+wuXLN-.gIN%nXN 3-:`wtYyVU갧2ӫ& Kg}IN%nXN iՓԳRΒz'U̴ɂYySgxVU같Y0Z]K;ΒK;:J객VfZudiu,)Գޫ aNeVLRΒK;:J객V2ӫ& Kg}IZ1@yc+ay<@K .+fͣ;M.7]";B4W*MWtiCh#UK0eԳ7h>ɶd>(h`객V{QS`@9Dea:+i"Ȅ_+Ef9xG0le:O>A{6%K3£:_- MFp5Gl|h"៙8 q @៙8 q @Ԫ͟iLYQixZ x/3S6ra5DGhէi-t\c|J˜¶bp/s\*0e40Bp ұb93ATj;Н~>wIoڢy'_DRDAc QwIoڢy'_DRDAc QwIoڢy'_DRDAc QwIoڢy'_DRDAc QwIoڢy'_DRDAc QwIoڢy'_DRDAc QwIoڢy'_DRDAc QwIoڢy'_DRDAc QwIoڢy'_DRDA6`?PB[XN1̴( N1a; "4=K\|2 *(l P^^A OjVKN[x(W< vlULܜiρaB"$D@կ0vsФf5s5;8fYr49YVdÆ(v;Jz%ϼg onrA.*@Ͱҽk1N3.S4cƹ<<<1)uS5|$|$1&Ǎ:O;';&iI0nںm*  "l8Øh&ZϮRz;OhWVJIм3u9׵,vvk%ntЛ@ؙ#}E_2Gd%|I8A$q&H_Q̑ę#}D2Gd%|I8A$q&H_Q̑ę#}D2Gd%|I8A$q&H_Q̑ę#}D2Gd%|I8A$q&H_Q̑ę#}D2Gd%|I8A$q&H_Q̑ę#}D2Gd%|I8A$q&H_Q̑ę#}D2Gd%|I8A$q&H_Q̑ę#}D2Gߥz"Κvh2<{)5sk!HԫfgةNta&½TvGYQ4#HZں]0kdf[3ʵJt'Ă;ۜ^K:ZfrAcEOz酽 p>;ך`Nں9W3T2cj7HA Vҏ[K&7*`24 4sҾUKffr4޽Wh{[Skju0i@9=n\k63iκ3olU ju]m^o/dadh{+7*kRX@mN)kJ`1ZV3(j&..3:NtHDAŜh 8lwRxk|nL6|Ln:` xϘ^Pbp[tÒ#V8Bַ@ .W,"-kGP,>o=aHܫ_is:N`UUf=okCO 1|w8 cXasOUm<&4[rњ`ީJ[M]6iьՉgҽK [p]8A =͜\!pr6lX_V.[,""- o]\|!wcJ[}"}-{,ʹ"#)QSvHCBˉl8fLpCȺvSli+[*?lbvʕ3#`9"zWCpz*ߕ*c_;8H pbBdS-U"NхhF{șSvƣ*'I(a UaR#^vY]~9P<'=+\>dm@n†,cǯ.y`/ҏ#K{PCTdO\yEV"Z0flA^5ڷ ڑe v2 -6te`9!G\ΈOLÊ5)p"A,cCy HL(-X%) Ƶ~R܁FbHy9E Pwz-h^RxHY]"ӴaZ0ĜfٲEZxtg8`B- ^V~K<ĄaWKqlKGsL m]Gp#r]U!iA'gbCaWD DvN(9ؙ_9B3A~T0+AU֬'QNHLKF(.Cm  Њׂ\cM+~j4F:".]U/QjDU yW@f) sڰL1Dp-p4lD:g -+NjZ{2 gῇ (J{=+B˃9IPوXk-L d"2,6 %UU<5ۑkfN`0VvS8aӲNq 2t+Ҷ1Z\Եf~!Nn%c+RR 3։h:#FQ{!jx'BZ;$H# ص&}BN~ Bx3Q+O]L꫾~TJEBNBNjRQNav k~E!$gE,&}<ӣJlR(P^TC,#h9F 'kEbl@a4UWn h]X%DErZ֏qflS 0.~&KUSf^($[t!;|͸_bX$Z ij)Qt[d-97$+yqs1ʛSUNkS6Pז8)/ iZpiZVFq2#M^Gj3P7W'9Ol±8VxC8VxC]l%3Džg:Sg:R.4MdEY{&7T,"]DWDDI[B Yk8ւXfa^x]`O`Blh49v-L(Ŭ "N 0ցwnǍaʉhPZN8iD.jgtZ6U*x i:mк({,oέ_E*QҪT͹Q uj/I]LcX wFvs.\Wmpܢr؋0sPZZ6EК /8m~PXf#ivQ\R'm O>[Z/3WzJYU1B*oyB̔K>Ѵ Ŋb9㤫 BB{9SUrDDAȷdk Em!@qZh3)* = R+8^VҎ eHquvhRdBQx} uߊb@ᲃ8>ڕi]A2ApZҲ`A.i ҥ腮 ~`Gue2ۜ* 6шA-nH;=e0bHў3lCaI^]~໡W76Z^-5iA"Ҥ{}໡lIZP狃JnU6DmkZϰnUд{ awHJ'^ʵ**01}#Sb% ~\)(cDՖ`9"]G(vͼ]rD@\"P묹8D+ U9EZ͖jrHnKqusłD]ϴ'9kkUճו}^*爪f,s/g}WNO^ִ'cC4xT\s4 P.[jSiճ֛,͘mj2V`6XͥNmJ,s_hNCisڳgL<)zOgZx>)-O|WM"b]."/CyR](5-w*|6K9 u&Jͳ|VКiW=6qqhsMvƺ3mm\+T~\S+fN=HҾOYRN4h/&A6`ZDYĶu +FPo `hdيK>sҴ f(@9ɦvN= b5XVb[Jk3uFRtDWhAtbdXQW݆O?НO?кJQmWʻ!Uֆ (-6iJfη ŸCUséL&qX@\Ÿ8/]Wb`Bh,fB*y*Yf^NH'ʭLׅ91WNBLȰ,W5tkec6c4cr|Go#[hUAQ  Ix\tVՏFdфSjY6&: aZܣz N܍5+5ބB)(_XpP|z8W(>k&}a¿A]N_ " ew:Å~2Ђhֵ7CMx9+5ބB0r[xחb% ֠ ew:Å~2Ж,(bD.uNzSmVԟ[٘a@BEyeB>aL7Cuiv)cSg*Fd%XJ3)A Z> @0V(^5:-a:-amYQ' \Е쾢"",!>ʧ*gE5_; ŸCH+`4ƃ\E|, œ[ZJ˱0@:f^qr ۵UU17Jei,Se>3ZÉyy4q>+<ر2]lBÒƭM)mx99E<;i +6|1e8]?*~2wFbυ1ܥ/`B#553,-.\~ge+;ea'Uk Tm1g$Pge)|,񌿘~\?Y0u }mL[dl3f}"+""" """ """ """ """ """ """ """ "" bzreŠg>8T.e(FEx"T Tڈ>mD۸5%oC"< \p\긲e0Ĵ!|`CvE kfzV+ŎhuHH h0ӤЙ&D4ڼQEfc]z""$?m“|f4ach8Y `'LZ[n1\]bkZsl$yj91E3:<'dT?)4ʵSYl4\A)9JQ[jٰ-o""j;&>-,lpk7YKNp^t\UGUUw'N60*DEvq?$ {aI)7E6 '$A :I^XˌE<3?a\f)6 ?\ Ю"fX,..-cEH mvmnxc]\TA»ҝ[1WzWv6ޕE#ٵw;6ޕE]WSl9l_G|+)ٍ|»Ҹ3ܶl ]m>ޔ>c]\tLr1v;1WzW᥶AhLʮ2.\b"'nv6ޕEͭ|+)ٵwqQkks3 Jvmnxc]\TA»ҝ[1WzWv6ޕDͭ|+)ٵwqQkks3 Jvmnxc]\TA»ҝ[1WzWv6ޕDͭ|+)ٵwqQkks3 Jvmnxc]\TA»ҝ[1WzWv6ޕDͭ|+)ٵwqQkks3 Jvmnxc]\TA»ҝ[1WzWv6ޕDͭ|+)ٵwqQkks3 Ja4Z J)bf-L|+)ٝ wq5Zgmc]NL|++Ԃg;o JvemֽpޕEʉ҂kks3 Jvmnxc]\T]ff>ޔ»ҸٝZb|++ff>ޕELFv6ޕaИ:J"&bGkks3 Jvmnxc]\TR=fthsW9Ʈ'SQgb4wyWI^HѪҪӪԪժ֪תЪѪҪӪԪժ֪תЪѪҪӪԪժ֪תЪѪҪ endstream endobj 906 0 obj <>/Filter/FlateDecode/Height 101/Length 10809/Name/X/Subtype/Image/Type/XObject/Width 213>>stream HWyp|[9ZJRK!Yq\lp'xH LBH9BH*$4#J`Bbs@߷,:{W}+ P]i}}~/hsE' b=[+%X>H=n:k>> MFZ]'Y<8qV>rsF>|yq9p%N{}|ry2^XQmlQ3>_'UY*c IH筲,zϺbu6-sJ?XS[g^cRWMADb.J,ע"{(]R$N- Gl*kmo{y쌿[:Htum?d\EȔ |~C0Z 8AAآXbITDYWxTlzy}^o}c.6D,t[d,} ` '45r`1`|?%0ę:cnDr. GJbj?nݡ=CG\xi%#We!B˄$sX9;4B 04w޸@x׾aT̠^'/$D.@^3ͺ_f.*r7\iA]SqJXjun4@>!Ng.]V|,}Wx TOQe g*% }}N]ҫW,;bXyW{hHvX*9S1>w1`[wg>#H˒5(.GŒd*O1π%HQψN8 aSa<+ i3D Kδ(]CkOG(ŠQ(%QIyA'45^0C،cf9X);N9#JX E XPH#b4ZM;NW>{ѱ~d6kA B>~&f?ڲd-I+@)01ZZa :kO2S{:A")j5nF!Av½N9˱oŭuTag"A"D 8!Sȟ3 k8X2P8]x,fVg<)Ɂzq,;t^9Y?%F#|HPg,./) yJ8jXw;rX؀"E8?Rfk Z<.W͓ T Qv̺zks#;8Ύ} ǡ]'%MMts_( u4~dYj.[Wq5ؠ-U:74w x׏=~^i_]` @ǍÏyPo$G1K7;c4s(4h%jۿqJS D`-흭OE@T=5g~N~KXKjȑeyB%4qsM=__ =ysrB0 { EHSg\AKP(SFCiQel25[/"|q6KZ"?6ZrSMԏCT W;><^ @b d y,E$({k9MQ?qiYF8}hٞ*M;z7s:GTBTt*7uw|DC'6w9ctX+QNlJcjU3O_J0-BP}]vx پ轧V3.Sa۰.<;\vD"{},J7 Γ`D1|>H -V) ߎ[kQj4_4PRv^k=cŪiUug'۲ݦ&dZ)i(B`B4)ӡ`2 06 e &BVuA'ɲ6k_sߓTлř0swl4Ba^gU^CT!vLTvypL}$fVb0aX 6Α\9ިzBDI$Zj0}%e$\*. P_gPCDv]5c"-z B&G1_Jd5 t7TB!Mrt4 @}@q1I<UJ"H9y^ 'GbE􅶥k)\bT MXeW&Nzw+ݟ~9ƽ*B=;NDZP$p[CFPw)LG'oI ca -0yY~&A `^$*SLLPvU3 Kg.rѮERAz; ȉ` %a^@uH8bF= Hः7-2T<?`8 8 P1IG5)TOn %r%|r850tK[ 9- ݛw$i7H9հ/SI4rArniҋ/[>qAe,hƠ%n4w =| g$_,9@rGu0TNtSygduPgW`;_ΐ}N',vwAz8t 9@K'\L,p(r:Âqi5<%Q:zuxsdUg%+{&^TK{ &\pO_'LdӸK"eϿ_k_)d'{Bc v#Je>hè Iw[D ,_lr )ݻ5K&[8*H|Hs1#Ұ5zԨs(̲".84 t׾lQ=+F?:(!MTV рlsO=/h'_3<^6BX&/J>8at<(iU~I$;[0&곥(_ʼn{!bYˢ(GAt.ܜ5b\?'c# a[^&~XMdы-N)P"knSm';Xow9bow^DrV cÀ~o҅T,an^["(rX.G"R4V`AY-T^)@{2*Z$RPJfX㳳/5;Z?p:9wvϹv=GwZ_[9mA1H G@B!ˢ_c?WoZ0(i!g\>3κ]%e0HD( ?A< 2tp4)/{rs~*QohlcO=m_?0r|5*8s8ʮ'R(8Eּ.o< < QTJuRSF!]R?*P([J[|c= j\LgOXM~=0?b3qɣRPwľꏏŌ凾_PQ^Yx#tAX"0XnTLLbk,أkW5BXkURFtf,e.~qP;0{>H3*, R uj҃gܝg7VV>sYE?0˩Ku(ƛЉQFM)^GO^rC>u#c)ϷUjICVv*"WO+BsHL?yOE/Yl9(*~XV-̞aEN|[50ПoiӀb!^%F ƗM)Pz{]jB&IWȵ>E$ D-8|!K|/G'yؘr^H_J+durQC]7(_=6) q7٠Tn|tr:P>y#M5ʹtB@@@@@@@@@@@@@@@@@@@@@@@@@%lvNNNŒd''cd8hpuuu+ُ<.% ] ٳgRTgu}nJBVZJ'4)TWW'J^6%ؔ br9޹~TVVH'}ᩈ2btprΞ8hp}>4xȼ_dfdZxACC޽v#+3+O=%˗ F_u4R~te%JJ)E$mn/tiajfgecmn426764cvN=LTeS3<*pwkT4kvM'Xm`v?w\3MO'0L̘]ܫ*֬:d+Niǹ>=k:J2iL@~7߂{NNv:irHP;kc}ĄV)((@l;88޼qUCry5D^^c#YRҒd| v~}۲v<ܞrr؈5}{mݸC?ߺSO~ۖcٛ}Ѹ8GQ=>:LrJEEEKf"#=ys~b˗~nK%]E"QK>222 Q;hkNtH86q:6hS#cz˗.[8oҎ   &FX[D]G)8 zuhs`  \Rү8׮^3WZ6ofd4L&Wq(SG;ҦM k9|H9R,-^bom[EKRSq 4tP+B|Kv0E|YoݺݑVSĈ?`nqvr_Ld$ c$܌z%X͈6Hȩ.Un3C b]fƊX>R"ի;Cu ?...% wg{ΖVnO#ÂArW.+]݃fc$^sРI'"3æyڵ`|Âv̮;̉[E O^ DSIIN>|X'^I'OBm" gI;[Z@=.,Dx~trܿjky,V,c>۾u_eM=χD##fUS9 krs]a]yUUrF|#1 ʈ>D> o5xN?7!JY>!xz_q#4ͦxxuKruDp0&9:ό?s`>Eѷw 2d.DigMAoE ;*}ߝw`P4Au`]|;9%GWXX.[l-@6ML8z"O9%˖,3YYKyIS]ٯQ"̘6瞵ƘoJQ圙nI=zrwQ\˪i*N:5z] t)%_ޫ,NҐ((# ;(hQM"APHb *ը141m|[MTA6ٱ",K 0a4o>>}w=9™qP:ۇX,*ʞӝW@ >Րv.hS@PN&V҂c?sG59DMP쬭Q6#2z*iGu95!WC_ ~3R -[o:oOߐw…sllH!gT1'/92=MzB8pAz,@%r/\8v|33>|XYQA쬬3Ǐ3IO֖ؐT;bcbkn>u;ScY5ŅE.̃_A⋔dkט#4s]%+8DmMMZH*]9Y \а0G@do4cq]ZCxUr'{Unk_ A {nn&@?<G *çʬ@W˥z4UQop =I.GK/ ql}CάYa֐(3ت3|SyDh^e S]~C456Zc (U7k:;#U|Aq+O݂;11QQgss60Cλt Z ymx+y@ }%};9TAaZpIDBJ,}roPܑxlwSw^e! rwɘ0@UR\bg`Jukу{4QJ٘ÑR M(QKM3?~^k)Lr/]ezfDٙYY;81ki%/>.ZYKH؏rz7 //C(+ge]E./+C5ys</IG/XmWȜcNTɆ{EGA;:˥:о1gݞݻF"?hZ/&j&YRXl<;JTu,XIi+a_N`%:M(āUQ Wu!Xr CGFfs!a%+v7dLT4Js[l,liiwe~d' A/,Ȧ#?/'Rr[[Z2֣J+]@buu;mhBUA-}Gt~dD$Kٕ+0tm? ֖I܎䧍LV/F(=?)ҒR=ml㋚0Ty"NΛF'emcR_gp, 6 Zc< &߷Ij#zZio.9԰|VUCv?tp=u58 `%(~b#jՊxBԘ^uㆄa=(96cw@8_ [lO:bH,b{0#+ X zꋆq{i)m[ uQz f150WWKL,/-)P n <_UU0;v*C8lcQUV")?١(23}C@ V;+~%$n>s䡻邏XI죴Dbv:-Be ԆAOO9AK0Ju  d xhV bf*^MLPe4fI%6Ty,)*C!8qlfstAN#ϹufDB!!| 49 <7{"/_hkҀq [qSȋii`a?l´4okkk^㩮 eocZ`UUnZl˖Y-\ lFl='zt' CPWSȷ;;!ޚfokb>=^fn[ŶoE5v׼ ['eL~} jL |Dnb䙈(P%?n+"LTDd_PSSC)HǎjdmmmrROOKAOA~>?%\WWGAmPDTLz<ؽӡ1n]뤦Sj)eaA!G%9475 RS!$@>/F N}7BΆl;zlŌIё&Pwwu+OݪnTAa#|~)<x Ll 'P 9;3V.#p18d:ߟ墎)ނUT* TܜȈ䴨IE=(7}9B &v J^7TX_hm*y/>/Font<>>>/Rotate 0/StructParents 2/Tabs/S/Type/Page>> endobj 2 0 obj <>stream H[o8)`F"0 Ig$ڃyHDZS6JƱÛRdqI;"uy~<כr6ߠ;:9]1* χ:eYogq9YճF~8tt~x?.,o $X V"Ui3A0偹8' 2evya]wac` #eSv.~ _anp"?LQB1+>nX[&Rb}>Yh1HE{ :hPCV0D>"F%1}e- İyal/tIg *'%Dl3ωU1d {qm.u-R0O\;*@6r snrUeo<ֹAE=Fy}nvӖmN`O6ȭJ27~_5*6:B>2UKdxQ|FO& $MyWݗlL='2t5I4;hrU tUPw]VOݎai4Mx^X޹wta35\8&5ͣ;skNs{^9we hzqѦ-/)QDc,]7v=E%q@ ߮>];޲v ^ƛYv^eí9Y~."H`Wf({i/5Ȗ^?>FrYg.YİlWqȺPIJR%%BSu η@z^JuH>J xe%xLZ(ͻ:zIȯ B{`"@u 8'"DTz*Ҧhr>[jt%;ɶOzk-$Ϭ*:w@ci.ދhï ,(U)zNd*W}eS/)l"c[IhKO6Y<ҴR>iD[QҺwAUHR_K>lE<,DvHI*eٞ$K$0pnv(M|t,k f.o"\J#(h)yي dJ@) N'J"%HĔKD)p&,&75uRK||r2m񠏱ִy"uyסeQ֠ڹoBam^o4lcwH,:A- =HJv%䯣E ١J4MmwFR[ +nL2V-s. aG_e|(a+A֢Tp!7Qz}ڞ qh;LbSillHh\}sHyK1Nm&֮VB{ QR VG duw4@Gbs!iӑ005i ysNJp̩Wj3m pu•*EY4V og,\e zNTiVc$Yln<y8 dv$+I/`;_ g8cygb#řH:U1e$ĽKU7A_7NɮT8sҝaW!:W9~nRW0ޒWT_N40ܹ'hУtҔi"&d/GSclx24\촨]^c7'Mș.HݮE\A00 򯃰Uv!6DGABL07$pEΉbn y<5g:!K¿q!it: JVkXrk%tg  >A}y)Td VH "ࣸuR$2%low )@W (,rMq :{.dpyU5|h!I9Cpn޸9Af"(A9"e+\Pk Wp^W(I+på-g+۸"*LAZF!l'}B!%7d7[}ymt2XM6MwGJՋ/ܕ!Uzē zvH H S W;՝TC7!pKj㶂ZїW}>}-b7l^w/^5x!Wݽ[~nK~,Gn#{Tآ[KiMbIQ]UXH{/Lkv[unOVWd]ɴ98yk?&K s ҧAVn\e>mLb*j̇Ri?`|/4Fc6{s}bM1g`ͿŃPsDVdFsd6؜4͐8k*0MWZ>Tf R*2Wq >ȹ#˵u\;  +k-Yˁq{ɣ,Qh9?tVd^\ SI%nNCo |&C'XEm6ᇀG+7c6D([N*1 _c=S}USD_:jz}\|AfICdk}§4`JFC h@0 iԀEי>I:*<vUi3},aLh^:t;}49>e@k.5[eس1\BQk=\PQj}oBg9vCbnsW$wwgzQq~.j@YQ&뻰rAD+d& {YVf_Xt6GiԧqEf(I*h.̱\vӅ6|1*~#gQS4CWh:7ĪƷ' WGUIG_3>an˘Wه}d/<݇BFKw:tjۧVR*KPD3Kmt4|$dY@)y-E<W[ ^B]Z4/?ь~+66sxέI|fd7ڜφxVNHcXY!~R1;Mɍy \ܬmn63@4 ;.kk{#GKW>P9%)ګe6mWVeY~,skn W!C}1!JyW˼h#2-?5B) DB%cSsZDwuw0FmeH#c(Bb&;zM%tZc2W u:``RWU#g<87@R]=Ke<Ȍ(ϰ:5ֲ1'I&тiurڤ-p䌉eb;;jQ($,7vm0|c_hG_ڵ,R#+@,PeF%q^OݛꂛۄrºhJ3VUVq[}Hǭ9ctw=P 9?Dg]b ȿ,M+1<ʸvcQ:w\Ot^(;}"i'Z~b܌ O',)zkFQeGpu {ˠڱ)9pTF`{D4Ӹ3OY9 *;HHnl,-MSzqzdVϗ7eKKN_&@Z?@z`@5P͉r{hNpsG~e!<<"NXe3<]zn>hE .݃/6\qVtYKJS'?L-y1F{-cnY8 <)u&]DR4ѫxOZNWگZT8q9rQJc\z;c%4Ɓe/8BmޮZA|f"-*KEV[~k8^0$T:er"|Ϫklvrk[>z0=:&\Jk+cȞu,beYOJ*2öu&JZqӶuV2( 񤃅e1($ .}=}rbr$%,.K{8l\w"RvRn:UsþtB0QzRBnr!"P8+ qa`"1/*wv.d݈CR]EI+8`:δW TJ`[ɨ}RiFxգ@'rfe 3VW !_1:NJKNˊꀲ'"aUNGȾ'zʚ endstream endobj 3 0 obj <>stream HԔ{\UU"@@Qι.> ei,|+J J2E435DS-fY:3{he;e) |960}>9{^w `"}wv=~SSr @ԉUN22gTvee7<*kȄu=SFzJc1:cz|?]#;̞Rݝ_565f1)s"]:ErNȝP0X3zQq:B(S+ԣzEa89UaHas0;bK mtUkHFm<{Fب4FM~jg S!vMX.b(Ob,UqM\7MmqG iEĉUh4F" hvh] 0C4d`r1S1C1S,SK~LaԜi( LʢMUO VOA:D"_R~Ox#axd$A<>5$,rP8%Q"%B3h:Q>ͤ]v^PlH(rQ$֊TaxNE-n*8 e:Fe?2i#z//x!2}J6/"WL"I dG9>t\-D:nPL#DlX`8? m8 {yF&"a- ˈ_ $b][#U60}^sTO}V g5B.V5b [/YۭI[u۪limvSvg;gK^C9AtD:Z9b}IَMNN_3i9[8ݝ)p#/1! .sֻq.5=U*vLcǩbVS똜 thVSdjlVw+NMgZVUijZ۱v[Vhعv]dS!5qY_4j8$;jտSuF\&h}Uv4[{Ubu֕W畗/n5(ݻp$X\}u]ɶǁQ!>qJz,鬳ݺ$}|i^7Gˆ%+S֫, \vDZxoƧW.e[=Bu}ُn?@zy^!C⏸1&cnʟpCRi)FjCOɟq8]\̑7#ܜr >-9Os4?g+n_s\]_Wɹw{$ Nqw'!BA[Z*@K[juݺ`%F?H|fP+ Aa(h4 ƒi4 -A *h ڮn{؞mؾ>ʷ@;CP;#H;*췰?hv1vxgmMI6٦ߔMi6Nvʹll"$CY"rI0TS *I4a?;D@I N*C9DJsi)QFIa.YHW@K).Tz@@$e a2\FH%CPDKX'qPV([+*%A$YR$U%C2eRhdIL#3d̒92OY$DIJY%kdF,[e쐝[~J)Ji6h۠'t'$DDJ4xK4P&%`BCg>pNi89p. {`/p18g\p57w<x ÇbUaUDPTYUNWTUMP5UmUWW T#D5UjZV*JVmT[^uPUQUTCUQURUuUKuRU[*\5rx~#|?ׯJ?߯ jЯZs:دK|_7e~| ?gHΣ;`*c]ûx,Xx8| '!NÜG8r*4>|'ISSOgCz>#z>cz>z>S:W֋DK9Ly^/|}IЗJ}E}]7:}S׷t7;z7{zz~X('ޮ~G?vi8 9KrZLy]yWѽ* }調Z㪻ڮK8tN1:Zk\;u{O!=u=\ou=]zF zI7 sC7 wCHҍw.%8\ 5}E7s\UWw\w\vi.q%\1Wu%]qWZOhmEƮ w] teHW]UqJr$f .\Be/ICfFJ06x1&\B >NN?TQ @88)yݳ+$WvvfׯU!kڇڿhiM'PF^ZD=NYmWi,==mV9Վi/jWӞ&BHhi=j.j<=<4ErI[iM.eO?xZ=-F>H7t{}oUO=JY)+c嬂Uv/c%u-WMlR;ej7v+VԇqRjfV~2u?갚%@ *!%$.&hadH&l b,YkdY9a B-fͬ6֮RܵM=dE*lRIf9tO &YJ,EVet夝Ԫ[b-%afy";~識~;ͫ{$"Kg!bgث5:{e؛Ouv smwqWvwWpqr׹CJR+UJ1f<= ;P:GMfd#x:'b#LL֗::?tMMe~^w -c'^9ᗇA jA',$1qφ_jV \hZJ75xZ$a <'mFlE7Nzzd$Jtz'XK(/rSeF4K t:2Ao\X&c\A5HqLˀa_ b=n|Ŵ,#!4O,fdxV_˰?u'S}MѨ]v(\c+>$V2Xça ]`U))TnEE\z, _F9323u0,fJ>-R7|aZK\rF9 sg7zF>lT7YrB4*F+`n?3 F!1=-CE@%z7:*1Ns>>NEnbQ ِWArsI.u5,PZ6M-vnAFG`ԟoqƼZOMmi9 LUܘ]5i&~q݌x}z<t3PzM,W-|=iͬX[m-bIФ4p g eWK&j0|vCqDa+s! $Y`).Ԋ@BRK$!qjP9R9rB?lRQۘ#ڳK',qTl%FmFq<\3zÜa ]wP*X'SL+RTK}0m7X\jxw~gp>Ջ;t=H%EcƔ6My!z(y@##Jaor>`qTLjrqh0OgJO2&~ Zpxblfڌ!NfEr{0򔁪TBjHRRo3%^ykDZj2VC VOt[D;s8S PV{' (<|D*1jFƘ (b biMИd'6[4$&{a'2잻ݻܪzN.H yYML\>Wo gwK戡ה;cX8j_D4m6-uZ2!q55.O˿J\^{_'Sͥ%VD!vLpN+|Ok0NO.Ҵ@=:VQy-ZL1{1ʍI7گ{zRJ'i(bd3͑'~7~JJJrKK`ʗ:ejOId|דd_zJyavx2董G:  JL^$6]fYџ +("$8mU躩tg:nX_s1a-a 3.qAa9K{5ƒz 1Pjmq,0g;_?}sWwW!Yt1>ZvwuҡcD'"D{c]Rj9T~W:p Huj}С3?A0Zz@ϢqLP3x`2 Oq Ւj"_xtڏSXN'X;.a^ mBD㷀mf;5 M+H鋈IX+r +Rs!&Nld ߉;q/0f9&>~F:IJ``q`(wP1X˰?bmǮ9qomdX~Aj76Xg5-~ 7оMgcS8_lXK= 8A^22h/MpfmԇȻFHz?s"ocW`HrMb(F58t }pV}pw }Ś[)ԋTȶ:˴Glm -&P#"_VCr H`kzX%*{jPvN m `Q G#6(O`z?IQH.(Jl7|_ gxֱ{Avu P/|rR#E>Z`*;6rZū͔IlvgUjT~l!^Sy} ;fiW#=4Eh^˦,6l ݋R:[8؇#^5K? Vw ? v85nk"8|_j !8@;jU}E!E@ΞRvfU-k^ }M5D復BRzgVQWm B6 ˾ #S9}-uz5Qj!V2VGiZmaWzNn}_KlK(_ܭIɼ>/Z,ɈǃоI b? |]WN=8OzUFĮM~9:[{a6- uYs lMhfLJӅFwDVo:ꤑq80WAw"Qk88 d6Ip*&99".oрm@͝}"ŜE \h K2Ɗ 7)?_djC^ouhd%ubc Wfk&k, ` 1R wj2HP:F~R/QX/R?z9χC]{i(:6Cz_\qn7*-(C'Ș ~=&xf׊0|axGMx]=I􇢟Ȟރzth u:έ=`;ی=mR-, y5 9t `[)zLD=CL4گCthn5N|Iz3`Mʃ?Ev*Am0bxNV7}ߏ׈:-\)=Wnu?=緻[B@ `@$XR `KH@-gA)X [LPyCɏ#3{w{9)V ~LG~-n. h0hf]0%KWzj~܏UrKUZǤ*gL".XR0R2ˋgׯK09x! catn%RB>ww%~>TOhwwaꂘ:.봬]bw6*y$k"BDRϻ7sf'{YKd!g`|ś,%7S/(՗j%y^9/I05/$1L;`N:2o*uqǓzБUGՍaˠ',f:8hɺRaW@%^7C>7h}FvϢ=o)Cn%@HQ 8KZ-w{/t<{NLJ>&u$Yu8L|G=b.hl/L=: ~+}Y-$.]r{VƢ ǙS_C\?F坰`OA4eof.?gb :-NO|@O9=ɽ?`Kg1 U?9R68~讕|yƞJ\WҶ577l,cY|[Lc} 6%;.J? 累r싲 0r8GL+RhHML;[Z),:{T)R,N%ȏF~罘wr$g1skeArc*!{8Q0R+>/2Pa~LgeXCAN\#sh]% Ybi=6!_.h_ K9<, u̥t 0)JrhϬ>,fU :.{vklSeߧ?r!L m=iP.46W;_R샜a؜9G3GSO`{c苽\mg=0oE>, |_,D|o>o~|/6? $!}}}k[C:OqWCO{Y:?ϛ&eݦETHǝ^aP~ΫyWMY T_Iv$s3~,9;;oXGd)Ys4&SF<\h"QƗ'o3v ڸ>Xlr{Ocf6/uFx'IbTY# 6:%q^+,3/GtL1v v!-wb3>$YCQ\L_4rYɌE2H{9%#CGߴ㛓MIRL $ՙ5͒}:ךoHM5i4f5:ZXIs?ϟhΡER&Rq)`kRm$,ߎ+ ޻> HF1юPb  ?IEm@BR:V*ZE 8@JS)Nm2ҊV{^~Hf9{;w g/ó2ȫ|UPs^Ju):A=gio=<}'|ߟ1\dQjb8M W! Oќcrǩy^-w S]IwY}f< <(^.Ga;,bgBB~wg=5fr7~-}!wxϽ|c$aA}7*n7=Lzx af\ֲ6⮒ =R 2'upA6PJdƝ S hSm=MZh,Jl&dn̄k18 㽑`vW܁m_lkG^lE ۢvυVt`8d[d٪Ԙ\.e!%M~"6FF5+7D>zQc⪎9E17P_e \6fPhio,RڮnWWՙdCCC8IItWS½Zzϒk'UOH+={LVJn x6~^n=ڀ+c!P5yRr gMHoԢ}}=z䯪1zE5@%xڴr:TɅAUJP>^6ΰpmo 9<Rk[RT<)ampIb=vinN'Znq^@}pw 0Rr}US^۹>ɳ0On+lo / jd#rZdx?.4bݹ2YU0xzA~wDsmRr[X$ Iy}!j )U\/1Α~aL iލLsm|ԉlײg y1r΃zI95ۥ(9.C+4 OZ uwH+\ S2tQ5f^t^L _֊vIl"o1v YdȹA)vR}l]%ضXqy:f!J">ި00;zHg2cȗ$ Twj!0}DΛ*2oP{R6_M>K,ua_3|gk?EˣPI] ҏA~^3Ƒj(/+6ggLO!MtϬP!r;MjTi2Iu׮E|| .^CSN*O%'%6⓷a+1*Ƚ29mae+F?O ||V #V=\.AW|j?#[ўh2-(&xw$gITT K+s_rL]zq#mQI: BC{;=~*'Pg4HZXw;H_|.)]ÏA: bϘxMo7ܸoϮ<cl0?BmgN-ݐ9YZ^do :3ޛ aN}7CbNF1z[Y+!o,˝N["e1͍|[~a[t1r>?ȅmg;2st8ɻI4o1>wXK_o~&fL<:^myreiLɘ\ݗHQY,z&}cfbV,-_ELlDrXYul:ɝ1xwcofFz;5:JȀӉWT uEATa 0 '{5Mbz17SL=^a^뮻|\{3"nU~WSU"~666666666666666666666666666666666666666666666666666666666666V*v[E0aOUʱCjWIk#UWpR7yxBw yNS/VIzOd|}#TRXbk6Y"*H\)~y&.V#Okxm^‿_ZO_ήpkko[^PX|ո=ڀ[ ,rKݵ{˲Iup_Yyk'x*|.?n&_&*ܽ+켝Q:Od#ee=ee-e e5ee%ee9ee)RK,TS*J%⣔S(/RL)x( ()(s)s()(3)3(i)d$DxJ>e%22KMEIɡdS()(C)C()()()(})}() J/JOJ:;%ҍҕ҅ҙ҉ґҁҞҎҖ⦤RR(ɔ$J"%҆OR\'5ADSZRZPSQR(M(ƔFJ8%)*$rrrrrrrrrrrrrr7/ʟ?(S~J3'ʏ(S|K5+ʗ/({)S>|J1#ʇ(SޣKy6-ʛ7(S^Jy2e7%ʋ(Sʽ{(wSlIr;6ʭ[(7SnHr=:ʵk(WS\Ir92ʥK(S.\Hr>GhڣY{4kfѬ=GhڣY{4kfѬ=GGh4f?Gh4f?Gh4f?Gh4f?GhͶv4ێfl;mGhͶsvEZI*٤0ZoR aXcR Vc X l2#X KVQ b03cc1&1O 6Lb`$Z6eqn0A8>}qY7n2^'s=@ t:N@Ghm7Υ)@2$ &a o& XL'&[bhLZͱ h Da  46m& 6@8&0Ҁj6lg0: NbFǁcQ*8lat8> [~G~{;[}|ɯ//9FB'&n`1&?>>ǖw16&׀WWF//c9YL>< << '0zx 0< << l7Zo-bn.`+p'pp;p.܌q:UJ m....΋1 l2.|*l4R`qM3.eW?`5¹ *,eRX5:㋁j*qYvV"`!ùr OV^;",Mœf㛞gfxxie*0(&g`qaq'Fx!ǖq@qJ/c1brq2͂ƹVc#Lтl  3w=!1S0d7~1Kk}]zGfO {iu::qg;qK*s@$mL\A'31 pV8LF-@slM14";#0PYE.N=]zZc#2HrPxd߿&8TĦihڒ_@P8 +-P*eH0((p0eSQNP ETܣ/r~r\Oq ߱-Nro5Xr:WW٫f<8z?>|cB}!0U{Q=\ݎjw|vUo9J՛{_6lūIC+I!%LmN M؈ \{k{>R* ,2,7UKyYĸ>@-`>g=dzfY L4xz pv&"VDEyDL#dElIaeVH.P,p{,T2$nپ.x{Q=x &x ۱ [*^l&lx "* X5X +˰KcbcblLtLóxO)LL$<'8&1Lxu!B /_ȿ!B /_ȿ! tB tB tB tB tB tB tB tB/_Ⱦ}!B /d_Ⱦ Qx_"?z+bB endstream endobj 4 0 obj <>stream H\j >wٜ%PrNReby6l*s)do݀@q;@ڂ.]bqi"w8=8YWȁf8}ކ3aK txg^삠+v!a{Bhk 5YliFe̓T?}YV-ަxBm̒N(}H)&,#o0 endstream endobj 5 0 obj <>stream h4]K0ʹTd=iҴHaL'EN5l~Q#o)z$H\d c2A*{eP>Cib(E4R$$@y'20 ԁY `z5IhR\WJ=Wa&%v/$GJ;gB(Sȸ~^?IssWmz<%{ORPe!X:~nޮV~!K0uU;vd(a ֵ`XZӽbofÄoa$%K|)8Y;^#:?Q3 endstream endobj 6 0 obj <>/Font<>>>/Rotate 0/StructParents 34/Tabs/S/Type/Page>> endobj 7 0 obj <>stream HWn}W#YT4J( $=J8E_ T(AkύIbÙ>yO?|_z/u.gc⤮sY}-Wf*w<"a3z_Y An>].ҥxBK7R&}Qi:DR/"Ya, 23Urv..zFy0sgq0;3+%8Y_^AֿOʊKZe/9~`G\Yd2i7mv[k]rm kBvvSγQc#ѕկ;ަWxשgV56:J>*~xw IהaB"1 i7kяn/ wgR n 9%&9%!k !t6[;LGX㚠 6AO^bG rjx+_2T̔.CyF(ԙ,ثuZ-b(W-MG*D9f}3q*3Z0_Fe0+:O :+bB@L#0W8*iA7Mynር,L>Vv[2&4?$gdE>b*u><ГN4-떝IW,;׾D[ cN6n J8ğ \̳p~SӖ~W@嗶w_zeP0=bEǵ`9+CGMgDFL)2BT6 *PtJ",T&DMY,ml9ť I}OjLl3}YxI0tȞNĠSr<@ΓYu/rCɩ Df N!ʅG|G C"fBw_fb[6u,#I^gGTZwy˶s=ԭn t&DcNXǧs!m¸Jβ.K3Wu9%9@#Ϧ0dINb+5U湥d*狻G ă+`-C$v^\39Fdv=Y A ]U !kq@% 0b/3R$&(; iB)+C2qk,"\Ľn][3aS0.Ӗn^xe(I< FK1x(wjҿ]6"D~E?lG?nSeSM]%/ H9[}H,弰xHg < uRA3-M7̖4RF0'q vZ4t| GHov`v@K?bU9ޒUHykdx4CqPd0:Jblˆ><غסI.Ϯ֝ҏ"  U v4߼, ixsPQښ2`Zf1tGLr&5,q16}y k>"Kv3Un7F]ctkcDz]*mBg.WjqzRw6Q) T}Qv~HWy38gCa@ћpww6 H?1P@* 6_!"~kWGQ[ e~3'R%&Eי<[,}Lf'^TCGP倇uJ؀vcnRtW{-wPedE'c?7̆6"&醢\+ Ɇ>Hs rL벬ĆA0I46 uWos 0kRC&UoLz*P?P#%rjy)/Qo!.`k/=ȲYa/>(fja x`2*z\kWeE]wkWhԯ)W=x^񞥶{ !z6%U$yثama5l-zJƘjҰu|хRnj~(/cղer,,tkfYv}L\wmgokm $?zmC^C*YnIwED9ی'{n4}EhDOU.v/QQUY|hlÏE<[N[Ϛfkn iY|H< 83m>0#y|XŞ񝮐!ZXьGî@EܭGbg.ZۿAD借c跴' wy{f`GYɍ w]E'߬ IqkJGbgM;ϗ&sЙW2< fR '\X*P=*a7J!ܠ{ͅ&rKnGz&tnsfn-T@cy kCP_R=1B\=yUEoD'x@#cL^fİ%؈"juիNj?1쪙g_&Wi1߀=d{&a|Yg _3 M@X-NH8k\uGIߟ c`|C ({&fRYؒ[u6T6:drTe'S~5D9B["Za3(GSQKVϰr&c7YC\x1xUZ |8|0afYh3˙d~@K%6пȏF?|obb^.ýz\f@GN %F?mUqJN} _iaAAZר;rٟPż_[݌`cFF)5Q Gn_Bu7. \6fx$Gr'6?j(ya:ƨ%4ty[ 3 wT"J|3oCʥJ6i%"h-U3!A l'մCdeΌ2U^t'#1{Zuio4i$d%w%:ߺV=̦BԽwj"dȢ5F4î*%e-9clLvVߚ} /G3ah+>v=_`6LʵVJjf*hngG )k `A7} -6A _R/F^v:S.6{9e߼Ư&ŷ`LTƖCLal(-]bXd1PH{ǵzXt@̦s-St+åY`0N.7}v_l_Mv]KM`vw0U~ _wAqGw~I>cx,ym ]U NG#flB۱QcBU\C挜­>X?Ŋr`W tǼ  ?D~trTB_]8,°:n DYB:4=֒-+wj%ī \2585C^.(.: M\?YDm^zA1|M?oy5sgAQn`G]e+J9e -rߙR ;HҭA`e!a"lyVp&1kg}TAuI{P.)v`"<]Q:[vv$6SD&L=5FX1駲fmy7;r5&vqy+t:S:]^oX93q*WqTH&OJ+=BHqvzЭUֈLyS5uAPQ"XG%KIoЯSS|v Ckc=|w&a|a* a.%GMЏ /xJj@{,n*[Ԧc)1u<h97QkmemvB'C^Y pd\ 7QJNY K ]qX_ދuzdwޘ3HgkT1X'h5s$~zʸ[?9/C^ozWCN5`T %x"ž *$BaO(oBי(Btw&ܥЃe *+^B !# uĝײ*˵QSqS2'߅a{lqJX/Z8/=Æ?z <bS;]C}OYq+eKG7g6N9u{zRk0Vo?^ˍRUͪKv9`?+TYg_9S=(Kxy+FjMUMÔɷIUIzeMR| KDJb=Q%״Ձښ~Jc3!͋enFo'B [L>op|b.fd,U9NdiPX۟_`2 endstream endobj 8 0 obj <>stream h,O]k0+}ЛhQ(-l}:2L]-!pG9a1`+Xc@#C (GXm6y͘\oe $M$G*eDȁ'!DsH0fVX~Y~0h>Zk|NBB9Y ᶓǭl2`44.ݿ&q+/2n91ٻ@][&FmzMy_5NA@#,?@DsoM;ZmћQ1} vrZLv" endstream endobj 9 0 obj <>/Font<>>>/Rotate 0/StructParents 35/Tabs/S/Type/Page>> endobj 10 0 obj <>stream HWKoW4LlMw,`N֋2؃`cq$j# e\>UU=!My\rv׻檽܊<{|oqatUG/8vwÿҾx^fӋ~z\^ϗPų\w+qq܃DYJWR0J:ܵᰲE&.?Lϗl̄˫bkD%y!X.eb*6g UBN/Qh"lE|zMTA#MCBm/,:"ɓG&U%dl{J:%IVA,}WSbT gtd4.(mEmE oΏԖYL>TxKu{=]nW]\mj;CPKa#i| ZjgFGƍ[( w*"LL= YFkw9[M6ZNKG,P/^ "sG,@ܪB8w*ZPw~"h/s߱%xB'}T WԒj~u"g)S%D֎P({ա ^w2Bk6bI sI=ĿZ"__piU 31~v1:wڐǴ 8?_ļǂ#ˉX S'n`&\[&1gSMZĊFv"t\:6WN4^f~D(7;VGhyD:xb^/0*r_ЉPpK;'[UQR. gv2쪅-.5k;{epV^ JP@[#Ŋajm^*X焻hMno۸1[z?9zo0uJŨbHu4 fM5Ԙj#:6m:eܸZ76o77G,F;~  Ec=/cA8;ajiP\=+Жl7Q GFqS:0*{z !8I'uW 6@eϯB|Mϣ93q{ElڹgGY 'Pv׾D߼]\'7c0U ׻}c`ކe/C)ZT0U 8[#茲2qHquINWO$TF~!xyD{穓j?ppJ\oHj̘r0AvхIYjcU0::[(f}u]0ZM&%l\ 4X0C^6naR{KͩY)~%8XsGۓ듟R#(F1ޥIccPȢ aBl(9b[k e `sd [iJeĵEd;G`4g^j,H&PZ?XmtrĔ#_Ӣ} 9͹It@Ca=6,h(E`> JhǎP?}0GMt=沱Ff%y%y%1Q-*"\m\[ )atT{j̆+4ıkP_%m$G#06QUFhb"|&\ iʥnH_HK1 k/}Os@ V uxNS!ӊĿH27j"ELAU) ?$Ã:R c'1ƫdUI%Γq)eptrLSu<bY97TYeebEuqUZ򎋚ū!wQCz"\: } {-[9;S$Aēu, -bwH|M1  |c5? fRg-B[yAۇ3qo-ihr^[B Ϛ ҅msy_yy_c~yi^<]䱧)aY-\.]~&oMUlAoYM=7I2lՐwPiLьA` (8wƻ&2B@:t˜fhqWu5[9oEm'Oj9ឬ(0nxu(frlTT!墴&SHeȅ)<雦j-3,bul&>b]>iF3Ǫ͑t([ ,`I59Ys,:M}*Er-ϯEit,znx7'srF_ud85cU$ߕ۴2脵,A;7+=ۙs +7 [91`8K$Fu-c en_(s_tO>U|O ϖGRUx(pM6+ x(?I;# ,{]5S(JsY,Aco3#N\|z]x|lޝ_GάH%hJ%_=~  :_TzRPo7d!h7sBpkY똸Qu ]Oph:ƏZ`TIwNZe._l.jp2{@X2n i?WD 2A( C.GvV "0gSOmxI噫 qt 'y7ο1DIuI.':yQ 7q!(%?5ư^ k"++ ] Di¶XʕuqaseI#(ACBBQg!)M4M_ȣ/Im.iuer=\Vi1_TY%.nU#][͙bAẁU(E뇭V]TB(SxfV} 2>4%"wG`741Do|I'aAe&{J"`cYC_2ڢ5m8gYS"|]dW,+00R({m3b0N3\ PzK5B8\ 9a%g%6W%0d@.P&\2T=pyU/)Mb<|2ܗU6i|N(q&"Gs'ФTd?ߝتr'xƃ'+Vpb}%ۢ\z{cj&.q!u]/+G*V9f"%bz"+-HhHk:^0$T:er"|՝X6ixk[v`L 9ϥd@2&[YCc/vR"~-drYBޯURD\K?B|,aфKhxssҢƶاn%h'Xޣ(8VrkF_鏁-@̋POdtwdtPG{.ד|6 endstream endobj 11 0 obj <>stream h, 0DeznRɂDPzжi(ߛ eF@ (%d. Edo?a3/H?t=h!tL9S%1I(Rڣ}]Cj:Y;73'ӦB;u]l#u 0 endstream endobj 12 0 obj <>/Font<>>>/Rotate 0/StructParents 36/Tabs/S/Type/Page>> endobj 13 0 obj <>stream HWn6} /REx&A<y0ָ%{&-ś.Vy%Q*VÓӧfK~͛/r"/ ~>\?6z<=O%'+C}{ۻ%?,^7ʼnv[l5:Yu`I9*R"a%f'g)JRB޴*%>/(#ï܄""EJ4a>,NgDdp+X1/ &$oKB9KlΓS dzKCL MI1bu< JŹZ|<ܦUI4I*9,,$V7D^ddTIkc*=sWiLE%I}-^~YBx*x'Iʭ5 <"U[/x^BկPY(eISy2h64ϒ T^ `:~+9<;eGvR -jlce ã ]Ls&ERF6}V7DeU]Mň /ccاv1T,.tnKbxUu՝QX@UxCܵkxw.{yOlcB2kإnpx507nK^._2MfʱQAyFpOl:ڔrh_kИ2`/5.j<{|'%߯*D/ɂ%QUIInda!hK0Xd$_aO@jTSD -#  Qsh/<1/0n#敜?v [,w@f<ȡ7x\X̍XǛ0}xF:["V 粱1 ;祇jPU_I~Cw}W2qP6r ZTrd71GK`ۉ-LqsI]2'IpLͣ;X F߫8>Pjپ&D[80CUQk2 EVepO`?n,I\ Uq !/PxK $l',:Y5LT&Ϣδ )}jk{ LRpJ1 s.<`>̫ҶEVC&#=3N]oLk7If !c#ihZZ25Ixg8]NM=^TT_1"5ѯz?BjY~hʘk8+꿥BĔܼW7'-yl[,r&ҩj*n-ᯌ|S8"BzkPsS'%HH6p\Ɲg:A4{ܾv&mUI^L<@9@ hύf4)0izO8 f\YYaRI]zoji ,GwZ%f=bC55e\-79b:菥T$pXq{ ihw0? T^TV:=xr( P9 &DQD i{ʞ | D^yUB<(%c*x3n=&Ԃ #<^.j͂ʱ?ނI~ocbely6/p prsy!nj¸U LwEַYS3qSϝ3$Y7hK5Q*JvgOL'R)w/R]*[pڕ0Z5f\1o&%WMibUe-n|9=8lO։0  (piZVAsj+3Pqq\BHrwB"c=S8*D&}h)|Bm!TwTcrݓerT-Rt)JU5^_ƅyTγtgqLkZx\vI+Zi손9Q6rRM>m/qѹG#!,*'E@gHC!7([Q khv3n#f/( jy8̝"/6.m\[*m"Lv91g5=ꅳh{.Xqr5E"g4Kcj413azSz+Sl<:CσeVl%9@CRd3Ls5ua2 m;=qvk ҽ1D,} XēÚ69#vU{6_vͽ9\KL6nx=(J,WlBZ%`!zl ;`*C7jOLLH7Roᧁ:v{$6̄󬮧N+sYmRNg-3v'GYlGbc u^oY8OsYWK-ң5M&]#'S ;ۜ n[#eSV_-SQqOp{!i892h1A&?P؞crj v#^b^mvh'?(׆m,G OC|tm* 28q %EIf?!O:9@gq'i#۹W{<ź^KfMNQɅL Y14  znDyWST Ԯ/@icf쎎2xaAaS+4QzL|ٶUx=gp{n]m(p(z|Y]Ih|$>ۘ4:(#4>zɲaNYلt xxY/f̾.Q7sףRόPL5NhTLR_^_CnMtt+e$8TA$vuÿT ( OD[`Y zeeѴn-zBgWwr_AԻU=shg|Vv =^OLmN hgRN9i s|Hha Q27* %kǽtJt Yg,MO)e%!2T2BzaG4bN-2Ni7]gXL Ԫ 1\1Nkf^7Ss[᲻~eeX= \G`j(n'vkfJ]PA 3dn z9z{L)ںKf>77/ܾke~&!bFWB'xף6RM+g3q%{}9M&^A,5Xa Kw|G v}Wn0\jMi@ezS/KsHI\nG(S8G..ߔn%^U\2S+RbVTߦvJVʆ6\:gڨX rU,-(sQv@2.]^HS~HGrt~YzC+eQJ+rV {~䮰qW#ǻaZv:%y#-e57«!}ۡ&uB1*LU>|~u?ZG~ݕ.uRJ7N̊3LWPӲTVuԽb6ωTÿT:``"aܳwC攣W?98;2\E؆1rT6J 8k\ m\ܟT dԃ5E8ڈM0C-+;2ZwKxWViqP-5~A^KIT%or %ef~Aˤ㠷ҡTոmq.x~e"x4 pL<5pLXn*avWN 0.m" .X~,m2[Ȋh i9S'Qj mFW{6!SX팦v⧍>dLIViHTeN ?@6ҍ& (NZ/c /bD < 9FXRu+UzAby&INmcfm')E"gv"v7fwk-x[hA nHtE%kHg'*[mQ!5ry*q#(%QX5rrb#L g2DK%/ƒb:p,ٲ(b>RNq129(pH(aw6$eW+̶f:2S@5(A]Q_deeΠ2oz8 G;Cy.$~wE.Sfd8rѓߌ9gWβ5*gjF&L*'!Aԛ%ri+Ǿ%8|׺uN a*͌GNY; Y BS Ry0T OI8ڬ.mVܓ`%祒 wc{"vϴF/[zEY@Ul]P6x y7l[]!KJN: ,@2eo'"w3 IEud OZY9NZ? EiښjsMSast [C+O{(dQ@F |ѡ^"q _Z jcBQg3TXitP'a;A$G+ pw^^Dj=FlJq"`)DrFshSU1Uj}CxGH؇ɛ ٜ endstream endobj 14 0 obj <>stream h, 0 _%G4Yj'xjEʨ V% C+ klsnL"#v|g<)-p=q,9dM5(lrм.1w9[裡Է[a, ; J}a/ endstream endobj 15 0 obj <>/Font<>>>/Rotate 0/StructParents 37/Tabs/S/Type/Page>> endobj 16 0 obj <>stream HWnH}W4/ job;3I5ȃblĤHouwUy3$v.NU=޾ %dr|wiz{pV_߶kO?ųx8xW7͚] h;sVȂ"gb),u|Mn_vtr,cU8Z2&BH1|Kᒭ KW,2\:g,7x3r? 4?,Y Lh!Z}xZǓs]̸d\4+]3Z jp}eŋ<ȕ{WUjs_[}br}SKH29KB"9-]$KEr.e2Jp@^™W_Kͫ'< xAKկk5THraV&![Ky@|F╜Ru8@F5 }G2Rp9< 7)HPcF7R [IIuG' T䐱U* ^&7)\4`.K̘*|JL}=UK&پO-и-K*>uPY?cjyڿ3uݻ]$w6u0Z!sT(_-7Cٸp*F dRf9ƨ|}j-o9.I}p#sk#O^@ >=_0K_ z%N >/Ayg=?6V4ޥH\.2MbQywxvv|+['WjD/ܦ-܁5Ķ:;1]$Tc|J f0n^(;' eR!SZ >TݮQ('֥dnZ3h@P3䩴rd x"ST-0rI d܃[ܹ0¢n*/@ I'뾽@ G4D쳏7btטx=m;y$nӭ4J*kM6a4ln02JSķk" evܵ O=Eto0K+LBڹd=(qiJ|nhm{NsuY#\#Fߎ&ŋc+OHlS14==<;0+c;> x(ț3'#|>PqCzfDM KxJE$0yD\[śeຍh+ u07QhCۃ] fU3_mD87lFJ/}'O)$Tj/ؔ3W鲀{A'#0G#-AGGqmI`8Hbߎ跖<ӅU`MKg3),3ƎQ?iovqU;!,K ZG*X=9C1/}ީBtoslms4^ qbH7}GYh_YFSɴ1.fߨ1 q`g6vf:f2GǞI_Ӌz/C k߻SadM_Ѻ8Vn\LGP?o|^orW'6ǰ"o2(4z\݀==ڋJqc<F<`4SI:rU=[=ܫI]K#* ė3er'@Uio~X@M-Hv2xqax<:~ď=YUZ;W2:&gceXh|r.>PF~3pS.hWkdj+˃!eQTCpNG`Q>R|  >%>%~qF?ޫemXRɈf7=IrXYY"8nHF"zܺu+ם3>wZ<2/cˑ|w,j,N~^Utov.wrduk=xzcDH`Vx-+d1RmO8pܣ>O1@y)5UTc fa$g"K.c1?ؘMr 'HJ[Z*dSMۏ Zn*]xزHLJOv5!~uz]:ۍ*賹,繁צfarby}zm·WGP 81riМ ?8wC#YZ4ϐE: $@p+QR*aP b/ʮt :k< 0.3Q㣥 YۋQl N7L};.,šf:X8d^Gďqp;5,}ʼn9 % o,xh!z5@-//O^?]8LLpʆ/@/}咿g B`E,L>UtAjqcBR9. Y9-G|59npf =Rafp6LfOb F"fq],W' 3zdD:ئ6,C C?Y[?&j ѪwfMS #tvLa,>P4'5^nCrGi~D;MFrWc8s z%ʭ\)2t\g?sowcKzyhT;HQ08)s44 i+yLF`m{઩*Lxބj%V>vÅ ~Lɉ-ak1rTCR]B9Vl.0`le<6M_rz_^ FT^"2yP:$$|ۦ91U/131ߙ38y: ݂QRzB %6]W/; (W# #*6h?|"X;6!ȏi.qga6nգxFtĢ>?M^B@?~a#Z3 .S"G,+cZm6y._uo G;' ^55Sb&OX(w=RJo8"Z 5DHA= QK>njXs [ds[XnsIe$Ym  -|O5,hu77t7Q$%bK E]\3{[_6B\U6p>5~WYF2±%e.oHQRQ'^L 2A( y_ = "0)(1\!1W+uqtғ}<[zeb%X|\sO˜7Bk.a<@0"`x?bCY˶z<<]6)jY )^7zW=34$$t IY&}aHjokwIycϠ0"7Efz*9Q]Yepeo՗K> IO 9P61Y@`߈MATT,e^-nh:-k)N;E(D ?h€UE^wg]TJ$SmǥGD>!kCSbrSNXIhd)߅$zK"ȌhP?BU2Ʌ˒{~|V/k_LjCJ\_]\}E_E]պx)\_x@ 00Q(q UL9Em)b(Np3 P{ }ODGs'Ф˅Vd{x>賛rV=KV9+G51G'VFx0FCΩ w&c ؽ51Y \UNm=.@L2mŽK|Dێ﹍Qn$t& y.MvW`0aw#>ӷ{-7 H]*ӎ,B&fwmJz?1G-҂bRZqFkƘJàM2hRw}̱lF{̢Ce@{"m`;. c)_?'ɐoE<5 pʍT y]R ]GԛgTk%A?_{_#ƚH'Ab2‚'7!_zژe<AK=䑽IW+{ endstream endobj 17 0 obj <>stream h, 0DeznRɂVPr5m(ߛ e%2`I @И2fcjog櫝 : dp56v𝔩P 8YN9Ȍ' ۘl_Mu8y3yv˲0=qGk/ endstream endobj 18 0 obj <>/Font<>>>/Rotate 0/StructParents 38/Tabs/S/Type/Page>> endobj 19 0 obj <>stream HWo6_A^Yo(d@n\!7V&/!ERc.pK739;~[nW_]\ta7ʚsog׻ۿ6-;emOznyy~/\+b1;UoOݜ- H$%DTdYêJDmi\un/b2w3."jFCKVވTZs +?$&3i,|9&T~ut $F}R;6 ·v$l_#jYE }F!9S3QO5QhM+ZjHP3|D+sKr"']:d`YМ*y԰ SE.n @GE60BB7Θ$˥}TlC?Z)`d=v oT8kGwtJ~-eE ;[_eS܃qqecEJ^h.#"š|/"‰IQUI]qnkE֤96KE4>ļis5m eP';Hs,T?Xy>Ul4׸ ތ*bZ4qb9RPE7,D&ҫB(Lmڜ@ 0o7ܶ&-4+nF\Q7<#\fFk99NEœ@x3N$kƁwE}Y)Rj?Jmү$2iC>uO6ҙE~~j^G+^˂]Sw mI$$xal[irwijU`uIHʺk=WpkZ4 ׽di\{!rW6[-vnw[`Efpw+}_ZܹtvrN\B[JO&;ȬYX:SnڣIQ.x2d #^V%,"Z-nz?!r[Y"'JlT:490SB8 ͆s IoK,lGNH᝕vN;u}wS =9TgJ &7' p@X'!0@|ga>ijQ> ~j[CđSڋǼV|Ju!׵FXOI?%_PrrMyTPP0h\ov+r6ߤv#`8Rh0m45)ք{DWJ":^x'\68U*+\aQRĩT,[a(Vh`Kڵo~rA+ `zݿw ;.GR%te0U^zN FND6/Kvw?&B%7J -Ł%{2/9M^ٟe$DO=K{ؒ=?n3AvXdT|x [KOw0 2x_;+5LJksؚ~Y] ^5du .m^,ߺ%\`* 6TXL[pJuh=m;[hٖB%2Ɯ% )SM95;&$`TlDG&]P[~_E"r;ZxɃA7/ͬ5 i)fyִ^i][۳-F:pd?lwϺ(Yn w[l 2[jϑtI9S6֚\,-$Gb_%QBbeFĄJHϋ n_Upv1%㞖{bqݲc'HtKKkKͺN4 D6S[K-vyVFԣFullԨ̐'AY]ah=RONwu&GDj Mn@ LŀlOAPgAKD:JB )/&-kjAIGk܂< жmMH}kxЀj_W@_gAo|1SZJ-X+Ew0v.O{VӮw`#z+u8Q$UIFZ֮ۡum+G\.T){{&>,i)/63|>tqeɇj ^UppbPQ񣥠MJTCWq -&VPL瓢ސ2-p7 b"f3+)Gxm&b܏J25@ÄaPa {Xak7{ʢC&5Taѩ .K|J4}O; ^XpK<~xH \u֝w+oteKWUx}bv¬x; !(e-AB 3Lb5LzFɫ%y='+Hl$ DH^՗'=ɓHn"$_rGINK y$_d1; b$%!LZJK͑ܜ"E`IN2$B5s#jL>*$rkyK#\7Xc_;Un-^ fs؝~`vwsIhL fG}N( S}En Fq6@5E n1,+r5 $V>uꞢc_-(tWxk.6i],\]#KcY{<}#U},_9~~yKr>Y  t\pyN0[3@Qlyl-F"4v8͐kI$F?u7A;OQ1f~3hچ^;3ANӶVpd N`"Y!bSk ? !,ۡHR_qu+G rNN囿K>͏"̄'h0mYZ6ցg dVPkAw!MEBD Ԗg/5 #=)WL4e[;l{zj$9/%bPT ; dh3;Hť=\|I 筧׃Z +ij| . D439'H, .PbG(PtiuޛD=Bhӌ=3%Pk.JV-8ܾP0UPStSjaC*CºLȃ+~Pdn|tȶ+;;lu^IrcyPGo@&WĜGx\_y|wbc셎ɊJL6&a$8&tr+3ىCNШaA2ֻvWf_&'-֛H bzIU?ᬙq#~@qvV\e4ߺǕ%R;vJv+Vn\S>[pp,\i>JJE&~ v»/+NK~iؾ{SCq(S=x| yk]TvpR?r+#woeWS{'Ot]AWA7I81$ GiɆ0V,NW{*SwF$ % G4瘗L:u9^a]fƞ=0;| jyh]Y)tH%܅LBv]hNApd[i6ik4@svS,Mn7"\KGwʍ%-v,'8fwQΫفc{raPݒ}Ɵ'd0q.=`<@b[80d~| sГ@S3<T{- "UF E_cy=;!YbEqw,[eCaۂn[P48.qܘ {kU7t~hˑ⍋]}++y%`u HI'L, !v/yj8ԯ/^nLި VeQJs0}x{ԋ}V/鿷ۻ~{R{{q][H|0Ѧ.|U ?4eYW H8 nUM5Uc٨~o*/3GRٮÞ.xޥ;lpK ^pу4ũ7f:>f_+/ݐ`^̿ '@-:HGxp*l^Ql"lkqgom+^Sozm~e"7雳 pJvAH!4ߧ_CJ 3===UՔ_#m(7灜R)9GMוy,7XdA ,֞Cܶ,\U%+oDh_zAև ۉBƕ oKiD} rG 14|VHWtK0A!+ޘV p B%W5ٴ: 6TQV7voѼGS`֨s[VLF\DpN~vզT,'*`.?P"y[&mU^#+ nnF/y1uɡpn: wz6EcmD.MVTI'A[I(,+ k$ ȩ@' Ɵ\% BcMT:OV&M¥JHI_29 endstream endobj 20 0 obj <>stream h, 0DeznMړOmAR"ſ7Q 3p XAf h*fcm{v8-x?q ;)SeP  Nh^WwuV:w667⺮2bpOj`u%0 endstream endobj 21 0 obj <>/ExtGState<>/Font<>/XObject<>>>/Rotate 0/StructParents 39/Tabs/S/Type/Page>> endobj 22 0 obj <>stream HW[s6~ׯ̾;,t:8IN{+u恶]T)i*e^@\;gۭᇳ/?ŵyV; }8nmjq[}pU7mď?xy.&.br?v[ݮꥸ>[ؑDsLRi.u{SWag,fB|m&gL(8QZLg!I*X}OYFW)x.X4Tii2K_+{! J,ݏχ#CeFz/ d%ppm~+؊4Q<'HPN7dֽlc$ *moc"ZpHT6KOj,1UCz9e2hȸ2Rkҝ|7Y9NE<}޸wtw׹Gu57vhF N)  p^N293bfdWW [6駜ڗ4&e|Z* q?/dAw$RTaso ۗ c^*:3Y!y2֑P- /K-IYAw§Sq w[Yû_RG950K1vr`e"CFa;!SĈ=R3Dcz5m#Z \U{4W%h84lbuGeD mڏr # []?2r9v7ڛ,$ayIOmc# {gw'}ǖ2<_2&>T8d3tck9RKuewP_MUZ$6~SOVHloS,%EK,r 1arYr[1h$I ~88;w2,8tmrķi8K,#@Ϫ`+of6 ; k^U:GL./ 6Z}X`v=go][]=T-= l͠Pt.{nK!$Ն'X#c s+>jIpT8" ڲ'VHC0 H ҉ ,mvd hs'8-i!_q^P=PLRgYEtaEހ۩F j۩*`y. n ˗ ]wf9}2k |Sِ9nAXt|#5c;HKKO{J h|bX#k7 !@ ,(:oǝƭ7f/{iט9(jo,}+Z˧2jLJ*t ! >kSQWq l /_(Gq?9h!YlдXxؑ9\5A?p mؘ]ۺp+lrT۝쪐,nFpY55= 9bW901M^bIpiB6QI(dhvs/&.| ڡ-Ni̸Kf غYfQw0!cA}u>S5eg%2Ո(>8yh1%tL:Z݃GwIFZ)r}Xh\l<YRa#ceAt1_|"Re\G2LC"MyK}ʀDCSFRRS0BsYdOXJ8~Cqb}mB̊\Te, P:|z։1<罘o7| 8P\%̣X%1 ƺLxbXPM=2|LrOZd)R'<ȿ1~ gQ9.5kX`[e7A̡|c]7{yrN۟P÷ݰu:VznjZ[ *CZTn %L4mv$k1(r(:Vs|ؗCIZDMY8btSLqhqFw컀7ՙ/VIpWw^+Gb \njEM:`%H0ɓxԎ#O -ݚs]Xx76O0 \ezaYram!љ ~\o=ƲO<35۟&[w9jX#vD+v }o #g< UT,d d7^o\,  iKAa)ge6ʉQLQ2Dhi|F]pYxܬ9 ;dr}30=?p2l$`_нr8PmXW|^8N8u`/UD=ͤJ~$^J堤(%JȊ&v}`$g$Kڃ!A=4: 4 'p~3MxGʐD&h&ځ/Z6[h@ᅪj'Ll<6'()-WNk?X#z v:#eeȖυu\p;oґA Q~]O3?E,R/"|Z঴  ܛd"t:#bDI86-t\Q\6z9`Z-[*9 {8Mk z΃DJ3= La,!Yvʧgy]rK"AQFwb&}J-8`}VD9E OEjz}|UpH-~[`qׇҍ3AOLIP5) voѐEAq[FZGl(-tDnIpr"%IKܮ?DpSt狫:ߗtA(7/%픸sAW_]%V_i;_>-~Z L\'-ۋ?tO?6U˿6lxRGOR#2[]WI򙻤QO&fؑUi([ f0_] Ĕ-lQ!  &4ʧ804+`QJWp9ǔ P?anǐ8U8 WoBf(9Buޑrk>@(̾GOg:LTX͂5م`dR=C+7H*{{xdR3TH,UD }K?:R,L*"f"GJ䙑ڭtn"9*~I8~v]S*Uz)POǤ4glIY?݌$\DO]4+bc86L+ 'd~f\L P=*(j dAYE@B?jKUF8 B3$I`[MIMt(;5XKAhcҶ #V)ƌPaj -XjxDe4›863IkcS-ȦNS dpX9rԩ5MM9Wnw[-&se(`o5|,մ8u1\9\=3%|OVٚ#i qRVєygϷhJf%]q2#yQ2U2l+5 .PX3XC)125p<)ȥ*6d l."@z nO :ţ$ݏc`yYuo1is}YQOzSh?ho([-RM[:xtni_Yv* ;N=;`lFn#zfHjoIE*w5麲@Uݙq.7bP\Y%ֶzWz?f|~EwO%K/ud` :U&"=efU3伖>S=2"^͢DXmi+^3m۞soQšBIL:X7"3aovwRzd$0",k{WT:NMYZPLJIKۖ\c ad.]h0(=cW%7E (Ke@{6_hVP$w YzqȪCd[HP4'ƠROb/> DȀ&=Ӊzآ rbaSqojԁ:ˊ_/DP!mɩy$_Q endstream endobj 23 0 obj <>stream H$‡r`{D+%,Z{}x(z\.t:wvl6G^Wr\5ͦd2_*YG'Pp8 ~ד$+uAiۭVl^( :xQ 98,[ckZV*aLJ%ts\6(*Ce I2MA)"$H8q,0 (Ţh$ áP( >x>/Filter/FlateDecode/Height 46/Length 670/Name/X/Subtype/Image/Type/XObject/Width 48>>stream Hb`` .Z LĪNM=+E+ypgVUK8ϛz`% 6b07j" =z `5A!$ ̎b> (!CHaWdZ?%Ve d:YV dڃYDx4Į^`& OV(K@VoI@&S0!ɪg*9H`I> `5+Q/ I`%$Zpu8!,N*nrAU=W<`X.b[@DG' i+\VDFWɻH)Z}+@SΞ"I?F5PX{g+Yr˷?|>{Om]7XƇle_qVŎ`XUs%]P}= jXIuAxTK^8M%ޞ endstream endobj 25 0 obj <>stream Ha[P2-ӐTb$5 iaADSJֆ%)M's^=lygCȵaVD1,XBx aOQZ(bwvZ?s>J>٭Uy]'SV[D@#xwR6= 9Yꞓo%{.]L"|#uo:={Є2riI]m,˲xg\_$<ںv^O_>gBv~#:6|a.eYЈϏ` rӍ7q,WYqw+J sDn8pRd,;v~GZÑ{qBuSY9 >stream h, 0DeznRɂFPz6m(ߛ vF@ Pd<>A7T)Db] CΎ<YQR &3 *է}~:y^ߙSצܼw;Zh3/ endstream endobj 27 0 obj <>/Font<>>>/Rotate 0/StructParents 40/Tabs/S/Type/Page>> endobj 28 0 obj <>stream HWs6_=9QϙNgǗ$NNL=Rli. @Q=X4 `?c؊￟={S\hUix?;]nlZ1{lۻ?b6Κ^;Ϟ+y6|Ofjb6_o@",Dʤе(2QUmaeT,E*TH18JLS O$%淓H'Db>XOfIiReZ亶9;4 H1/oJ%E{>z3rp2]IJLhŗ}6Kjj|ZAOb@Fmob.2n+b8PG/ЏBm[wy)8TW<]nm,a_6!(ZQHj߀ `clXUaxX>j1jp2+ -GZZ, D}rn$R;5ĭgQW w 0ewӨ[㴸Rfrmכ40l$&%X32ɕtHml`5@1G <8Ш̾ɬJfN`0&=nɬ4RG׆.g,P6p ]^Y'umN"Q_HTۆXLbYU)`x܀2_>bު29Our .- ٵhVJ(N0pFYy鵩NoDJ|<̴S˝p6[^$ Q -:GdRUFW0,@{HW,9{z!Jx=[TC;*L6|Cȱa qZԕgeޙ/&;Z%@;8*J3H0fSdvbKҡz`.̆; < -ef^y2DKWsHkfEGExخ#A2 ZqHcRg_v^ Bٔb//͜9K@fȠ3{ʐm?C!- t M1hGQpÝ%A |j }.2/8(ҵZo46T"w{nY*b:}'k(\7=C '\apwp1- ䷖Ր]%Ԋt%.xNW-?yH=deiKI+݆`\VC2hר"L}85,YA'wHBS4:=f~CCq8*ԹzU(K1(EoE9f7KWW aȢ 0B- vLZ+¬)2ynL ٓN;;PT7a+fOC7Ky#O;XʇSulWm\H:OȄU&LtR-;R;(?vte[,ۉX.IXY{V ,XSyUT`Tٛ03R[#Į]~(JkDFd]!SXx;@DVLԄ: 3ʸՆV|#dp{idGDNN֣Y !}#Rc,L- TRTrCm?QJ~RLQJLJ\> hA'C /Σuz /{@EN8HO Wr8-0 tUcL 7(`wC'æKY,;RiK ̛{CGoPteYi^p  P)%+Ț,^%#gp.a~_#04o81A6Gbˠ96PFbE罉%-m.\_w[#kpscw0[RUǓ .z:ԍ(4i݆ JX9Z@qKrS\ tc[юcJ:XV i6$`s9V<eacVH1^ 4"V^T?"":wfdbDsp

u|foEx8u`+m"r>ʰwfI6=:5*lIko|ҬtZ3"_| Di%c! yTIIH#^ex5^ $f49W~ ԗSgîH'1%|`3qUyU5b}z?w\`3= 48zSU }ǫL ~hGVkh8/1NbIbH2;ds(J?}!1.n )&`FF6%7D٢ܴU{uQ5;)l7Z̛ 7D 1> OA´zmS<^f͏:맱MWvmSYrF\1C.3+QF7 jϢ2˽'R/3~Ps}YEό6=Q6JW8#Ji{qI:25iC[uLbN[Il$p3:U~}ɨ92à,R4HeA *T T,T"eBX␲x͜ƊXs!VS[pcrRI=TnmXX&)1(Spa=H:ϸRw҉ O_sm4a9yup6?ݢuc#^kgK\ip6MˮpF(Gxi12|#va'ʢoG^gcldyVBQՙ_.ߡRC>FTBV;ribvP{ /i\ЙukTVsC w@dB>U*pk.V+4e".˺2Z?l {bnpyq)37q$MG."G "hN+NfU=*TM' Z*^<瀼 &%`亇e]6 2]O({?gڍ[ދnѽ\KЦM)L5n&5znEi((5٪B >EAn̓XdU=13MeӁnÈ߃!+۬!:+tfb3X3R$DmlNV9+BP8j#.ڪM=NM.ظPOr$9;Em۰2i6uv4u|Y3\$Y%D61#7$C1#H ;qO!,a,4UH)#]GhX-> #HŅ"Y*K6-jXQ)h,-4L}3-o{EWĈQAʜbGǘXґb`h]3f͈Ww_&*jg6M.zP# 4VQd L"IdTܤ^e۳/z3?3bWǐ >< izC!͒7գh$RƟ>. J$K 7&8&N- @xjH t7N!yoFFLZT/G4٫ֽ<q%Y CѶsL̦-l5Yg6Dld! @/$u-|&Ћ6_WO`/qͺfgY\4"\e@Y оtF(`qiJ0*gBJ2+R}#enT2B~ HJH1e>8ҍyew\^=eT*5mR8j{U..g- d珼x"1JIsWE u>.kҹ+QLH ٬ɇ%z^5z ˕cfCRQ%&Em1-ˊ^E,zp3 lJ6|ϜC H!Uc CB ^/75W\Y0Ma>t`MW4ԓȑױWx7BSV\d0UA!:.4ps(D ?ht/:ފ>jm~!F$Yt,载ؑj((|~)>$?R7"64htH3"|;GQt)!/~qv=[ӦDQNJgf4X/&oqL6,v)DN%?ʲYbͺ))zz}O>~{ʫ dE*^R%G4@mo1eJѺu 85t\E+SgkMMe 5kPӗ/id]lO˶q5;1t% uvr#XљI8LM: GJt#wӎ';܌9gWg-4FVDN ,SWGƟJ$'!o9fqYU za0]qCOHOO_ko endstream endobj 29 0 obj <>stream h, 0DeznӴRɂVPzPĦHMTy28( d\ EM:g[v(ш;lBp&%% byJS>=~49wصV7-bgÌ{Zk/ endstream endobj 30 0 obj <>/Font<>>>/Rotate 0/StructParents 41/Tabs/S/Type/Page>> endobj 31 0 obj <>stream HWmoF_}!+P\I|~pmђ{6:ovgfKRsȥ= 1<3<'v7N|ioqU΃Ǔm#N~w}Oqw]+ř| N]}iVdmaG:3*BBWȊDMjvrvןBOd\)73|4Y~xl!2Xk˧٬te`")S-2] ^3U|T,JQHX[ IYT⡙"Zdz W\$xgHוt4YtcyߟgBU%EnL]+Sgw/XϢJ7NTmw=esh2hwpq;Â*zx-:oK}3@xsw[FoEtK%ie م#.ށߊL|x  @W|.h4*)eRnvN}n۳/J)r*VL';qAY Y\2i,ݬhY ?6vAe۶q>WiWaAAtP[`Bn5XS\xHvaiP[{'sASh;2e/N+}#j;)9iN44_H5^¤M0:HX+|!2eJ3銧;\p-بbo/K]Si9qWö~H+P;rg(ZkXَ٦$MXS lCCXaxk̑m0}Q(+ƊCuFŵkLLM8a; h3:4Q쭱ĥ7kg*e!LB/Mr!wwƒ ll_9&q[%!ΒBgJ,>5>" BK oN l( 7&-m-L.m#9gbӗtdG"툣ϢlDJ Vl6͊J+N {/방Na㲝\z@xQtܾlKŕ zcO3nɵeYUXVO$0\+ҶqF)sWNez=l{/CT%Ze 'uʔUe/RN ʉiU >f_B HgFNR_+$Gi0GXRpeDMΧ #M0ca 5QG !*FLjG1jCL l~3 U)0{P2O^8v1znHA=G #$-Er @LX%2ȽL8BRL5@-0ruHi9GTN iAdCtaWx C& 6 e4i̅iT0ďn|+"sP)S=V.YzT?2qyFVF1`C+x'U^Ց# S`, "e.h7n#gVhτa2c2 (hRqO) {ρFAke-YMVr~Iv|kA#yώ R "FY+e Pw&*HT9:289OGvjF>*&10 qk,2o,6ro‡d~9ܩ]eQozTtRn^tj9tS?WIwWH&&@yKƼ9x[ˋ-[= MJ4$PZj vv@ͲQ|&A 7mP,$}*$V8;_5y>`il{iD]dgͶyјș槜?ǽ6-4-D#/dbZ'Qf?%zEفIB|MV! {~oƔ lR"{P{vE!T.*BrRr_w1Yd\Rz̈p %6ƶ3;u{{?>]iuwౄ  l(p9p@A7 &߃nqPTg`Ok(v {YOCj oOBnH0@b(JMYM%>{YWXLs W B7(_/'ªnكP=a e|]):"UuPE!4'Nk/Gz(I,W,?c6I/6iG>)EWC)_+g=$51a-USFUfv|"b _3@~ ê&()574yZv2dp0`˓PU< \Q>=T ~ L5"KuEC}RM T-Tǡ~YKb ܋v8 3|&t2 ,.\X">f#LK'@Ǐ w9֞`M(EQlrT>~lY]' Jf燓9)ҭ5%ZΧjҽ* u'^>("/_i,.m!b, -d(yE7 RJW{ɎO=B6 au ^[2Uo66ժVҲ¡ 0xO˿Ө|`\Q٧|`)D媨% +`ظTuGa'Ӱ:‹G- Sx}F4;x]3B)%rGZCMH;ꑡG;qWt71Ae/=C4u򻊄]n+Ou_ڋHM~i4+i`1"w>J>+QzONè~&P:m>'kO&\i.'ӳr<0| &ks*Vq rƲ#NJCzJ".v83_vB̻n7~0|9a9XX`zd?}q2gcwu3tq8:6H2\9,m|"Rͺ.gGü le0_C~g0nc =LEeO3S5=LJ7WZĩb2ar\ɗ _$])/da~zHÏ۞~o{-A!J,r-kC<@5/Ag/Wp"&u ΁!=}E@Roٶ] ?/C? 5 AlܪG?WQCw*˦|?@>u7gH+ݛ\D\'|VRYhW58 ɨ^D%/Ț)1oIP{%]J/8"BIVn9ClԚ)MM'2>p &-FIVrGa1jOب쮾_ɒX~_֪ {FbcLU+Ue@'6`>ۢ|WpVXZda7j k* ^Psb,)S[` -v1,bBiaըNRRzE>.Wx/ݖ~.<HJҼdn>Oۚp{.)U.I#? ŰZj#F \+bZĚx3jz8{ é#`3!3ېU5/.Imm4 @0h3h [Hb>ɹ/A1Y6'f?y(@}cr i cMBVd,*5&ʒHCz"<(QCt:>kAi,vԦ٫~PiI= M4Enm{nmCb] 4[FMCAJ&U##MvI7Dem&4SJi7K k֍kŠCJ<^ɧ.^n%5z6W 9D Qeӎ`Q냶b(Np0w<0T“ʇm\aY)צ^KI 2%Ф'&2IyY/3MbZBeXq]MӛpBf.ߚtЎ`.{<3Yl; ^ٸkbTbDŽS^J @ (1fh*C:|>tg$H 9zp,XVJF8xk]w]]{Kw|e;n#at6 )[]p6ڥDx۝OF5`rO;k6qep6Eƺ64QsƶS)K݊%Ie,GWN\A۲їfz7n1v"3txG b z;\twPJkkHSTy^ `me~3zPYny&d~@RikxS<ד;,ߎYD]$X ٘*xc"JDKB} 2J2?P3XMl8N6V?A"A!tԦ%u* z C#籉=>"" endstream endobj 32 0 obj <>stream h, 0DeznRɂVPzжI(ߛ eF P P \ EM:݂]e3(ш{l[&?p3!@(^է<~1k9um{C !d#u*0 endstream endobj 33 0 obj <>/Font<>>>/Rotate 0/StructParents 42/Tabs/S/Type/Page>> endobj 34 0 obj <>stream HWKs6ϯ@^EJʖ\X^ZCKJ$D t_3#>AC 4}8z\]n؏?~]Hge|i}͎>Tz;ZgMSmnچcxs ?WWMuy]Ѫtfr'9Ϙ,YD*{Tٔrh_:mИYvP{;?k v _U_M*]Bs 9(wـ/' *Ga9XD HϙWÝUؤ F!S7zYif(W{¨1c2(ܔξw `Z!0ECS,Щ<Qk3_mULtJLŚ6AOhƔO(5:lob߰Ujzk擒uIyf"7^.+jgRr0>~VDf#}" mDK%^%_y4! `2H`ӛt1=:w;tRCӐl著ϼ/%:)5ֳf>HhƏM :3HSKPd"UQ9Ә!μ 3V! L?x' ')/Ӫ6Qu 7)zDAn'-EFWL  ~Ӌe 2˸,$ܻJNv7iޤ [l;3>yJWJlPo.`GYt]7VFd~utb\CqMUU[}YcԮ538=~o|Xzl7vSzg_6#AP{ϳ7hP}AS%KIXxq( wqCD`~/s3_h\T/`߃$W(GD[gE0iuNמyT "5k";rHqERo٩ZOa'Yl^ƑRom69kt;#N\B8\ Cf2m]ՎTZMgz{BՏzFca? qB %,9sé <.ԍ#4r?%H;$PCO40+r_9Ǝ GtkL[| cn&LE" o X<k6[$o\bH@ZLMq{Ǵ3.zq(2ڢ?}mQ=ڢmVUP5goQ@mVbѣ3LTvޑŤwNsK P8gIXƍ$zWԑlv&i;:,P(thuZ @Rrry北;kO.$ )ĘCe Dgs܈aLbw[R^E !Br,@M0-($ish]A`FaDRHtO~ ׊y6|#?}|w=gwW1ٔ&afIs=~{̻pͻ;z}s܃xÒ8ZC.c|) ot0[1|V뼄>l1'"SNߍgQ '$fd3UJuKf@E#YhpE\ɨrEA&)l;zX?OoP#WkYǏ!|t5WFa VtR\D2ZCtHG/Dk>ޜGzV.= ua >zFnF+Kސ/Gyx/˚l:eJ$qt,lTӮ"$cQwƃ/Ț)1'wIPr%vjΔ&*`i[5?bJBפ0]OzгjNjӖ?#V.e[59I-fj(6R>ݘо,8~狁NK^F/\mSDu0`J#MA4&fP'2w _niY6YhvaϛnſݱMg@r/Q76}uA *KdA sA K9 tr6:~M3&4YvچĻN$[xRbpRS]^Τjd !Dz%dh^/ n;pJU 6%'IcպJг?W$|WnhUPJ?ĀMBij 8&E4큼_iGvAk;] ӛU9 SM%MmKEv굔! R/VUS)6s8'e]Lw"Ss,#OEC#p.}$/#}ћ{r'LwlܵQbTbÄCVXO~HNǪi3.q{:ʮiC'}UUenEdM_0pĽ_nQ +ĩO"ŮJ5r Pɘ{|dfML\6լE XDa(/TF3-32M(q;#VS A/1#]]aPMp?gAi &W5A7yd.iqw쫂F{T(se@{mB {Y†c-.C,=;:dWG&z!֩ZaUPzxE)78*1X$ٟF=щ⺗آ 49`Ije7K{Oܘ// endstream endobj 35 0 obj <>stream h, 0Dezn[$RɂDPrдi)ߛ e ,/@m]c5L=N0.xR}#{P.E*gBB xJ-5?~SP;s]-y+̎[> s0 endstream endobj 36 0 obj <>stream hęmo7 ǿE($u!ɐmA^+qϓ,;ՋPQO$]")"+2VEGTtW'ڨUHC4iE DP QV* ƨE=)*))9,V ,vI9UFXN0P1&ADe=I`21@˃ +Kd 2  D5PD˭(kxbhCr ][졕ú89>14/.(& 4G1ڄuKl@hN iKp8`r2bq2b w!WV \^?_~_)}rR.5n{,L95sӥ 3Mf~|rY09q+?,Wez{r)op$fM3-&̱o(8(!_D|,Hh]DB&R.sE6[)ܥcli)K"2k;s:593TKѭ< u'ANn(4N\zxM,R]}rwJ]Rt+;z]E~koys]^ Ӓm[wQ+瀧2Le q}!B@q{G]k(Q){1|W5 ʐL>(H%y"S1=!(1'mziߗɈ=DkBq4c{jgGĤ5Kۇj;?:û^~^~,?՟toOy%owz\{]a|]Lurj ] ODp~zf7N7߿˗'d1;wE 8ĩ'_bLAD>7h,wvszGoNF@n2&-X m&Rz4>`4ye|!4TP8}a@6z?P}錄!}RdBȒu: WB3I>ו!P9gl[]\΄Gcƻ@[itA;$2med< YѦ8樍^QW*T㦃a~sW8 endstream endobj 37 0 obj <>stream hބXio7+|@I @R HQ`\i6o=]jWZ7! 4 W*O))|*=wlic'=+O'B݋@ _cVi \$ oeqC[~rx<$f8€vZh3 <PPbh5LPPed[^@v ;o1Cz /9@2 }+ ɀ0`X`0D2 ğ 1'% [ V$@v%ca0LAb @e $şT% €ZhrZ3h0`EX-L) sL\ҎqrH) {!bЌ0TA W兑qYQ%bEN 0#qvx E ___|m,J|>>\x/Vaԇ7o02Zǿn::L~kcIf_7 }z޶ )>5~w{ieG;RBh!.^bZu+횻qa*vN/L\իꏋnpݍ~qH3 |JJF6?z8FTL*G8R#>6mޠB%J$X/ȚFf^kպSR Rʄ.eGHĿYW/!4Bg" Ìj48\>+mu^NJߴz{l*uAJ&VQ2JR(r-Ұ)n7 ~PW¬+VfFO5>C8_>ŌċfbXZO7m[]h@KŚ$֦(DU|_W6o%.r7TJFdsL(t8v6̈́}Lt} o@^'k|fHO!SqPH :1%1 5~wS6ɒNS =Lh[>d*u7yu%4_MF_tiPgf7u|6_!̙06mviMt݌^֡nnPSz@? OiX%[`6Lgx_zGe#Y.T:?i^S$kn׎ʔv6^M`Km 4#TbmptjtI|tX!yo5ےƽYaܹɒ-;ZKbw4۵ `e_ @&?f֧v3ydYvild.Ɯ?HutzcڗGQ^OpR‚@ g6qdO8Jy]*>)cXcarΫ4y˴%VNWjDmhiq N}yϡ:{ =$M2n;@mϭTrTd8p ?~Ohshv}Sސ onyLWkJry&vBK WP~["_:tI&@*'X oq"zpbg3jK_?H endstream endobj 38 0 obj <>stream hZo7WВ3@aiS$'J&@ߐ(bV^Yq8v88͓y1.(a'(AxnvJ#ODi7q"oA83QQN3M<[xb3Ndc(MIQSy}KĢ Z{"+!((r&P%%$frN]“Q<9wUȁt u}*5fZ.ɻ@I>`"76iH7xNsI_!N!$CʂU.iH9 1ȤD-ڤP@RD(!N11F"K=ԣ.مӾHR"KH=}D2&ŊE3E*cTK!Q#bӘOOA)_JY](ļ>HMğj^)YV)i LMk8N.k(!LRFRQZo`I065BrJk/\}r.Woֻvvdc׫7MVwIo?=lVW<~qCɓrԧK+U!g6|)W[}Ge= ֣e=~}0h -^NNNNNNh+sxN,-'xO><<<|+@."@>#@>EEXa:u@K <WYG;--m@[8 +uh>g쟱=3 A=@ ZN vJ;N ~F>_aww8}J <3 Lg=byyx77-&Z]mޗx߮j&99ȢF6od3 GvqSDŜsd9g49Ȥ͙G&)}d2'ի~ڎOn7W׏WO/=~wpx|ڎ}q{~tqq}9K_ʓ/N\ oB&L`jZ@Z@Zr[|ˁo9-C0 RvQyJ[v+nۭٖxm^wJY~W_xw XyCJ)lx!npeQ$4HF9iҽ)Ϟ5-~]I'sBC֧ܡETJS8/Nd./5s7-O6dYlfy2=g2?g&Mɧ:!'nr\kpY۶Ӡ]֠4h5h; NAiН`Asf<s3&S&Guvxt|4ρ@ojP)үJ}Yg#K#diWETFFҰMéjOfJeY! #gf?{6T!ggcH',f#)W^ >?~yiНsvqz!(@{ Ldi0<2aA:7˃HѲ&b?h>;ۊ endstream endobj 39 0 obj <>stream hޔXMo7 +:xIZF>N!n|IQ3vWftؕFzzHH 1 h8cA'Gg-g\2h\rHuIB* ))}] IJ :H |BFˡ~d (sF%@!Դ @B,/ظOY]5)%s `sv +h`.ٜl4;Q%su+#vSql,TH7 LXE@p-+];aaBG>w5?T0;9;9]zst`.=ii6J# 6V r4PU`#G /¢JP@ U?P¶Y}ZzL)p"쫰AQ(y!R&܂ #6yli {J)'"]K(5sH؍ B F.CۈPnTq ,}k;f1= Md;vû# 3츢o7p6\F[[ǦgOfJ;smv[C0uFr%擯x&7 o b N{ipQ&T34)ьiʃ4BJSy?q^c^O 1nJv!kn.VvŚ_C0u4WC̀ufy|![`s>%-jC}J2CSi:OQ8's#^ںYг[lӆ~?ه R*uI^^uٔݟ+U*Wx ֕;>}/VqXC+ZV/ה%-~Jd/M{2yAObOKdRSH܁e NG,J>stream hޔX]oT7#<$k{<VTڈ)b"HTgT\%zs/(H2$OISqe\=7;X"~-~0 {#cHSǘdICeMGb ةDt4S_AcyHE(DS_ "UK>E ϟB%u :M"'"4tD} d)s3G%"9w0HUr`ss;rfL9ss/IBt0*!KDJI5H" *dISTG0Y"`.0T[k vj3J%.9,Cay@b}2"R3AHI I*z XRԐ2$&RG`?q(_lNP rs\xILpSfwLAL68*pIm01>`y'㌓Г̓܏̽vݥ|pݹۺzܵa"p p]"_8wW@ Dp5WF };;?G#I}Imї@}Yݹi~ f<ܵzQs3!ӧ/9X njs/':nxw1޽7?d{vtO>fǫgYK.fiAXмxeiY<V_l/@mSLj*i5:h6z|/j5ƧdZ}d[+L46)|x4. wa͊e\4ª-Vxs&6N68*0tέU6*pM V6۔lI9ز VV[uNADr:kW[gujWFq]Y9Xm5]u֙ծ:ub(.Τ\9H9XVtVŮ,Y9XlrUl뜕l뜵ve :g drmY9ȶάdX9mY;hAVr. l;5pQip{]iA$k3r:E_\׿T/=[ MNv*|4˓/O<˓/O<_YT*V44ۼJm0Qqì>S^Vr_&Oc ݦmZ*zۦa˦i{[{^ru* endstream endobj 41 0 obj <>stream hޔ17 ʤ0V$E W6`Fp8;!E*we;$tzOH3;*QjVK3 T1p!qRVXҥ{ڬyi>#%U_[`Z1X^:cF`)gTg\\7L>xX>stream hޔWM5+>=ݶғ@)H(?R=ӳA۱=g\32K-]kц$ \H:F)df w؋T_"?=L_EX!4k.vnŜb^kVl(Cz1pkyC_e9Hv_BD0i qD}e`2}eb{*&.ԨRTQsb &2l p50O}4!Z Z>zaup1Md"gz;b!&%)\!&OyvObfs& Z 8R1.y"x}A/oߟ`}=NG=m 7zޱ|xU.Yyk_yWX Lk0%0|f[% <nk%: 9%k9%Ȳi3i3])AZ)AZ)AZwisJ6>iuk%'Yr뮓`],)YRuul`0''%xn9`π0?~ -P#z3)j{z>stream hޔXM\7 +^,ɶd~ABKU"iR(tߣp]-#٣;*Ԣ0Tp1BBv^5 7iauv GfΥ/3ö҇2Ϗ2eLxN<֠I-ð֑=0Cwl0 =j~1k߽ŋ[?)rLJOwTf__|Xbea_I۟z ;vv;~3Ӈs}!^{Yxl#B輋RMб?]CW[{ן9qV0y?ǡzjOC_J`gBߚD63Ē nN#;KOx4^rюЏCvpڹ+}88jK وę|P"!3#A e >;G=+m[o? Ge),-l;jX |||||||||||||||||||||| b={}kʺ-.FI լ#҄,zce_LOnd/gYgKjeeuuYuӺ:i]V.c2lguY-8ޝ~^4˸]YҺzi]V̴.^fZjVᘾaV)}*cVp̊jٲYo1rauRů7?N~?K-m 1 ݻ'-e:KJNEgӢYm:ӗ=}ێc<6 endstream endobj 44 0 obj <>stream hޔOk@ſC73 ԗ)`1iRyKJH?ٷZQZDj ( kJ( *]WbunT5‚#q:73I/3iZHJ5E(z j1cD!ML0 fK ,0Bb;TIJs XŒ+ W3[3qU8K0Ypb0 W8 ¹eB[C)E[XV[3I7>}=^~T,jp9/.&ZyZ-? ;{g\<0{`ꁫnؾ?Lgz}Ef}N_N_]Vdvy#u?1Z]t9])+ev,ŕRWJɮJɮJɎ/xip§yurD58nG)mvau~܎WOw?vS LCNsҕJWZjiOv?~:}9~_l5p ikcN˽9ܛsoǚ`b endstream endobj 45 0 obj <>stream 2013-07-17T10:35:37-04:00 2013-07-17T10:35:33-04:00 2013-07-17T10:35:37-04:00 Acrobat PDFMaker 11 for Word uuid:e54473a1-b17b-474f-a848-800dadbd2e0b uuid:6e245e25-cb0e-4439-a065-337cb012ad0a 4 application/pdf R2M Micro-link specification Schneider Electric Adobe PDF Library 11.0 D:20130717143515 Schneider Electric English Schneider Electric Schneider Electric endstream endobj 46 0 obj <>stream h޲0U0P0S01R F 66y% ޙ) y  RYZlgWm UliV !!-!"FE@`f1LA4BB4 :j endstream endobj 47 0 obj <>stream htj0DEXTRcSB)),K[ՆDW)gu$lDT; F'pLZhWRiYJI]j녔W77Μ3H)vBbH C20L:rѡW.,6{7->lHY֥*xquձ竖gv~ 0o endstream endobj 48 0 obj <>/Filter/FlateDecode/ID[<8301862F873FFB4B94A1CEF16F018623>]/Info 888 0 R/Length 233/Root 890 0 R/Size 889/Type/XRef/W[1 3 1]>>stream hbb&FFo L@0U+A$:X,-"OE" Rr" LrHY/0'BDH22F! ,;@$K%ؖe&HHIa3k@$O5d=EL3Hf0[0؄`>Al dK8?rDQ9Jғd<0$ѩeh84HWsGaMWh%G(9JQr4] =2H@p7$ endstream endobj startxref 116 %%EOF apcupsd-3.14.14/src/drivers/modbus/Makefile000066400000000000000000000004231274230402600205200ustar00rootroot00000000000000topdir:=../../.. include $(topdir)/autoconf/targets.mak SRCS = mapping.cpp modbus.cpp ModbusComm.cpp ModbusRs232Comm.cpp \ $(if $(MODBUSUSB),ModbusUsbComm.cpp) all-targets: libmodbusdrv.a libmodbusdrv.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/modbus/ModbusComm.cpp000066400000000000000000000132441274230402600216360ustar00rootroot00000000000000/* * modbus.cpp * * Driver for APC MODBUS protocol */ /* * Copyright (C) 2013 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * Thanks go to APC/Schneider for providing the Apcupsd team with early access * to MODBUS protocol information to facilitate an Apcupsd driver. * * APC/Schneider has published the following relevant application notes: * * AN176: Modbus Implementation in APC Smart-UPS * * AN177: Software interface for Switched Outlet and UPS Management in Smart-UPS * * AN178: USB HID Implementation in Smart-UPS * */ #include "apc.h" #include "ModbusComm.h" uint8_t *ModbusComm::ReadRegister(uint16_t reg, unsigned int nregs) { ModbusPdu txpdu; ModbusPdu rxpdu; const unsigned int nbytes = nregs * sizeof(uint16_t); Dmsg(50, "%s: reg=%u, nregs=%u\n", __func__, reg, nregs); if (!_open) { Dmsg(0, "%s: Device not open\n", __func__); return NULL; } txpdu[0] = reg >> 8; txpdu[1] = reg; txpdu[2] = nregs >> 8; txpdu[3] = nregs; if (!SendAndWait(MODBUS_FC_READ_HOLDING_REGS, &txpdu, 4, &rxpdu, nbytes+1)) { return NULL; } if (rxpdu[0] != nbytes) { // Invalid size Dmsg(0, "%s: Wrong number of data bytes received (exp=%u, rx=%u)\n", __func__, nbytes, rxpdu[0]); } uint8_t *ret = new uint8_t[nbytes]; memcpy(ret, rxpdu+1, nbytes); return ret; } bool ModbusComm::WriteRegister(uint16_t reg, unsigned int nregs, const uint8_t *data) { ModbusPdu txpdu; ModbusPdu rxpdu; const unsigned int nbytes = nregs * sizeof(uint16_t); Dmsg(50, "%s: reg=%u, nregs=%u\n", __func__, reg, nregs); if (!_open) { Dmsg(0, "%s: Device not open\n", __func__); return false; } txpdu[0] = reg >> 8; txpdu[1] = reg; txpdu[2] = nregs >> 8; txpdu[3] = nregs; txpdu[4] = nbytes; memcpy(txpdu+5, data, nbytes); if (!SendAndWait(MODBUS_FC_WRITE_MULTIPLE_REGS, &txpdu, nbytes+5, &rxpdu, 4)) { return false; } // Response should match first 4 bytes of command (reg and nregs) if (memcmp(rxpdu, txpdu, 4)) { // Did not write expected number of registers Dmsg(0, "%s: Write failed reg=%u, nregs=%u, writereg=%u, writenregs=%u\n", __func__, reg, nregs, (rxpdu[0] << 8) | rxpdu[1], (rxpdu[2] << 8) | rxpdu[3]); return false; } return true; } bool ModbusComm::SendAndWait( uint8_t fc, const ModbusPdu *txpdu, unsigned int txsz, ModbusPdu *rxpdu, unsigned int rxsz) { ModbusFrame txfrm; ModbusFrame rxfrm; unsigned int sz; // Ensure caller isn't trying to send an oversized PDU if (txsz > MODBUS_MAX_PDU_SZ || rxsz > MODBUS_MAX_PDU_SZ) return false; // Prepend slave address and function code txfrm[0] = _slaveaddr; txfrm[1] = fc; // Add PDU memcpy(txfrm+2, txpdu, txsz); // Calculate crc uint16_t crc = ModbusCrc(txfrm, txsz+2); // CRC goes out LSB first, unlike other MODBUS fields txfrm[txsz+2] = crc; txfrm[txsz+3] = crc >> 8; int retries = 2; do { if (!ModbusTx(&txfrm, txsz+4)) { // Failure to send is immediately fatal return false; } if (!ModbusRx(&rxfrm, &sz)) { // Rx timeout: Retry continue; } if (sz < 4) { // Runt frame: Retry Dmsg(0, "%s: runt frame (%u)\n", __func__, sz); continue; } crc = ModbusCrc(rxfrm, sz-2); if (rxfrm[sz-2] != (crc & 0xff) || rxfrm[sz-1] != (crc >> 8)) { // CRC error: Retry Dmsg(0, "%s: CRC error\n", __func__); continue; } if (rxfrm[0] != _slaveaddr) { // Not from expected slave: Retry Dmsg(0, "%s: Bad address (exp=%u, rx=%u)\n", __func__, _slaveaddr, rxfrm[0]); continue; } if (rxfrm[1] == (fc | MODBUS_FC_ERROR)) { // Exception response: Immediately fatal Dmsg(0, "%s: Exception (code=%u)\n", __func__, rxfrm[2]); return false; } if (rxfrm[1] != fc) { // Unknown response: Retry Dmsg(0, "%s: Unexpected response 0x%02x\n", __func__, rxfrm[1]); continue; } if (sz != rxsz+4) { // Wrong size: Retry Dmsg(0, "%s: Wrong size (exp=%u, rx=%u)\n", __func__, rxsz+4, sz); continue; } // Everything is ok memcpy(rxpdu, rxfrm+2, rxsz); return true; } while (retries--); // Retries exhausted Dmsg(0, "%s: Retries exhausted\n", __func__); return false; } uint16_t ModbusComm::ModbusCrc(const uint8_t *data, unsigned int sz) { // 1 + x^2 + x^15 + x^16 static const uint16_t MODBUS_CRC_POLY = 0xA001; uint16_t crc = 0xffff; while (sz--) { crc ^= *data++; for (unsigned int i = 0; i < 8; ++i) { if (crc & 0x1) crc = (crc >> 1) ^ MODBUS_CRC_POLY; else crc >>= 1; } } return crc; } apcupsd-3.14.14/src/drivers/modbus/ModbusComm.h000066400000000000000000000051651274230402600213060ustar00rootroot00000000000000/* * ModbusComm.h * * Public header file for the modbus communications base class. */ /* * Copyright (C) 2014 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _MODBUSCOMM_H #define _MODBUSCOMM_H #include class ModbusComm { public: ModbusComm(uint8_t slaveaddr = DEFAULT_SLAVE_ADDR) : _slaveaddr(slaveaddr), _open(false) {} virtual ~ModbusComm() {} virtual bool Open(const char *dev) = 0; virtual bool Close() = 0; virtual uint8_t *ReadRegister(uint16_t addr, unsigned int nregs); virtual bool WriteRegister(uint16_t reg, unsigned int nregs, const uint8_t *data); protected: uint16_t ModbusCrc(const uint8_t *data, unsigned int sz); // MODBUS constants static const uint8_t DEFAULT_SLAVE_ADDR = 1; // MODBUS timeouts static const unsigned int MODBUS_INTERCHAR_TIMEOUT_MS = 25; // Spec is 15, increase for compatibility with USB serial dongles static const unsigned int MODBUS_INTERFRAME_TIMEOUT_MS = 45; // Spec is 35, increase due to UPS missing messages occasionally static const unsigned int MODBUS_IDLE_WAIT_TIMEOUT_MS = 100; static const unsigned int MODBUS_RESPONSE_TIMEOUT_MS = 500; // MODBUS function codes static const uint8_t MODBUS_FC_ERROR = 0x80; static const uint8_t MODBUS_FC_READ_HOLDING_REGS = 0x03; static const uint8_t MODBUS_FC_WRITE_REG = 0x06; static const uint8_t MODBUS_FC_WRITE_MULTIPLE_REGS = 0x10; // MODBUS message sizes static const unsigned int MODBUS_MAX_FRAME_SZ = 256; static const unsigned int MODBUS_MAX_PDU_SZ = MODBUS_MAX_FRAME_SZ - 4; typedef uint8_t ModbusFrame[MODBUS_MAX_FRAME_SZ]; typedef uint8_t ModbusPdu[MODBUS_MAX_PDU_SZ]; virtual bool ModbusTx(const ModbusFrame *frm, unsigned int sz) = 0; virtual bool ModbusRx(ModbusFrame *frm, unsigned int *sz) = 0; uint8_t _slaveaddr; bool _open; private: virtual bool SendAndWait( uint8_t fc, const ModbusPdu *txpdu, unsigned int txsz, ModbusPdu *rxpdu, unsigned int rxsz); }; #endif /* _MODBUSCOMM_H */ apcupsd-3.14.14/src/drivers/modbus/ModbusRs232Comm.cpp000066400000000000000000000214321274230402600223700ustar00rootroot00000000000000/* * modbus.cpp * * Driver for APC MODBUS protocol */ /* * Copyright (C) 2013 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * Thanks go to APC/Schneider for providing the Apcupsd team with early access * to MODBUS protocol information to facilitate an Apcupsd driver. * * APC/Schneider has published the following relevant application notes: * * AN176: Modbus Implementation in APC Smart-UPS * * AN177: Software interface for Switched Outlet and UPS Management in Smart-UPS * * AN178: USB HID Implementation in Smart-UPS * */ #include "apc.h" #include "ModbusRs232Comm.h" /* Win32 needs O_BINARY; sane platforms have never heard of it */ #ifndef O_BINARY #define O_BINARY 0 #endif ModbusRs232Comm::ModbusRs232Comm(uint8_t slaveaddr) : ModbusComm(slaveaddr), _fd(-1) { } bool ModbusRs232Comm::Open(const char *path) { // Close if we're already open Close(); #ifdef HAVE_MINGW // On Win32 add \\.\ UNC prefix to COMx in order to correctly address // ports >= COM10. char device[MAXSTRING]; if (!strnicmp(path, "COM", 3)) { snprintf(device, sizeof(device), "\\\\.\\%s", path); path = device; } #endif if ((_fd = open(path, O_RDWR | O_NOCTTY | O_NDELAY | O_BINARY | O_CLOEXEC)) < 0) { Dmsg(0, "%s: open(\"%s\") fails: %s\n", __func__, path, strerror(errno)); return false; } /* Cancel the no delay we just set */ int cmd = fcntl(_fd, F_GETFL, 0); if (cmd != -1) (void)fcntl(_fd, F_SETFL, cmd & ~O_NDELAY); struct termios newtio; newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD; newtio.c_iflag = IGNPAR; /* Ignore errors, raw input */ newtio.c_oflag = 0; /* Raw output */ newtio.c_lflag = 0; /* No local echo */ #if defined(HAVE_OPENBSD_OS) || \ defined(HAVE_FREEBSD_OS) || \ defined(HAVE_NETBSD_OS) || \ defined(HAVE_QNX_OS) newtio.c_ispeed = B9600; /* Set input speed */ newtio.c_ospeed = B9600; /* Set output speed */ #endif /* __openbsd__ || __freebsd__ || __netbsd__ */ /* read() blocks until at least 1 char is received or 100ms btw chars */ newtio.c_cc[VMIN] = 0; newtio.c_cc[VTIME] = 0; #if defined(HAVE_OSF1_OS) || \ defined(HAVE_LINUX_OS) || defined(HAVE_DARWIN_OS) (void)cfsetospeed(&newtio, B9600); (void)cfsetispeed(&newtio, B9600); #endif /* do it the POSIX way */ tcflush(_fd, TCIFLUSH); tcsetattr(_fd, TCSANOW, &newtio); tcflush(_fd, TCIFLUSH); _open = true; return true; } bool ModbusRs232Comm::Close() { _open = false; close(_fd); _fd = -1; return true; } bool ModbusRs232Comm::ModbusTx(const ModbusFrame *frm, unsigned int sz) { // Wait for line to become idle if (!ModbusWaitIdle()) return false; Dmsg(100, "%s: Sending frame\n", __func__); hex_dump(100, frm, sz); // Write frame int rc = write(_fd, frm, sz); if (rc == -1) { Dmsg(0, "%s: write() fails: %s\n", __func__, strerror(errno)); return false; } else if ((unsigned int)rc != sz) { Dmsg(0, "%s: write() short (%d of %u)\n", __func__, rc, sz); return false; } return true; } bool ModbusRs232Comm::ModbusRx(ModbusFrame *frm, unsigned int *sz) { #ifdef HAVE_MINGW // Set read timeout since we have no select() support COMMTIMEOUTS ct; HANDLE h = (HANDLE)_get_osfhandle(_fd); ct.ReadIntervalTimeout = MODBUS_INTERCHAR_TIMEOUT_MS; ct.ReadTotalTimeoutMultiplier = 0; ct.ReadTotalTimeoutConstant = MODBUS_RESPONSE_TIMEOUT_MS; ct.WriteTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; SetCommTimeouts(h, &ct); int rc = read(_fd, frm, MODBUS_MAX_FRAME_SZ); if (rc == -1) { // Fatal read error Dmsg(0, "%s: read() fails: %s\n", __func__, strerror(errno)); return false; } else if (rc == 0) { // Timeout Dmsg(0, "%s: timeout\n", __func__); return false; } Dmsg(100, "%s: Received frame\n", __func__); hex_dump(100, frm, rc); // Received a message ok *sz = rc; return true; #else unsigned int nread = 0; unsigned int timeout = MODBUS_RESPONSE_TIMEOUT_MS; struct timeval tv; fd_set fds; int rc; while(1) { // Wait for character(s) to be available for reading do { FD_ZERO(&fds); FD_SET(_fd, &fds); tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; rc = select(_fd+1, &fds, NULL, NULL, &tv); } while (rc == -1 && (errno == EAGAIN || errno == EINTR)); if (rc == -1) { // fatal select() error Dmsg(0, "%s: select() failed: %s\n", __func__, strerror(errno)); return false; } else if (rc == 0) { // If we've received some characters, this is simply the inter-char // timeout signalling the end of the frame...i.e. the success case if (nread) { Dmsg(100, "%s: Received frame\n", __func__); hex_dump(100, frm, nread); *sz = nread; return true; } // No chars read yet so this is a fatal timeout Dmsg(0, "%s: -------------------TIMEOUT\n", __func__); return false; } // Received at least 1 character so switch to inter-char timeout timeout = MODBUS_INTERCHAR_TIMEOUT_MS; // Read characters int rc = read(_fd, *frm+nread, MODBUS_MAX_FRAME_SZ-nread); if (rc == -1) { // Fatal read error Dmsg(0, "%s: read() fails: %s\n", __func__, strerror(errno)); return false; } nread += rc; if (rc == 0) { Dmsg(0, "%s: 0-length read\n", __func__); } // Check for max message size if (nread == MODBUS_MAX_FRAME_SZ) { *sz = nread; return true; } } #endif } bool ModbusRs232Comm::ModbusWaitIdle() { // Determine when we need to exit by struct timeval exittime, now; gettimeofday(&exittime, NULL); exittime.tv_sec += MODBUS_IDLE_WAIT_TIMEOUT_MS / 1000; exittime.tv_usec += (MODBUS_IDLE_WAIT_TIMEOUT_MS % 1000) * 1000; if (exittime.tv_usec >= 1000000) { exittime.tv_sec++; exittime.tv_usec -= 1000000; } #ifdef HAVE_MINGW // Set read timeout since we have no select() support COMMTIMEOUTS ct; HANDLE h = (HANDLE)_get_osfhandle(_fd); ct.ReadIntervalTimeout = MAXDWORD; ct.ReadTotalTimeoutMultiplier = MAXDWORD; ct.ReadTotalTimeoutConstant = MODBUS_INTERFRAME_TIMEOUT_MS; ct.WriteTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; SetCommTimeouts(h, &ct); #endif while (1) { unsigned char tmp; #ifdef HAVE_MINGW int rc = read(_fd, &tmp, 1); if (rc == 0) { // timeout: line is now idle return true; } else if (rc == -1) { // fatal read error Dmsg(0, "%s: read() failed: %s\n", __func__, strerror(errno)); return false; } // char received: unexpected... Dmsg(100, "%s: Discarding unexpected character 0x%x\n", __func__, tmp); #else fd_set fds; FD_ZERO(&fds); FD_SET(_fd, &fds); struct timeval timeout; timeout.tv_sec = MODBUS_INTERFRAME_TIMEOUT_MS / 1000; timeout.tv_usec = (MODBUS_INTERFRAME_TIMEOUT_MS % 1000) * 1000; int rc = select(_fd+1, &fds, NULL, NULL, &timeout); if (rc == 0) { // timeout: line is now idle return true; } else if (rc == -1 && errno != EINTR && errno != EAGAIN) { // fatal select() error Dmsg(0, "%s: select() failed: %s\n", __func__, strerror(errno)); return false; } else if (rc == 1) { // char received: unexpected... read(_fd, &tmp, 1); Dmsg(100, "%s: Discarding unexpected character 0x%x\n", __func__, tmp); } #endif gettimeofday(&now, NULL); if (now.tv_sec > exittime.tv_sec || (now.tv_sec == exittime.tv_sec && now.tv_usec >= exittime.tv_usec)) { // Line did not become idle soon enough Dmsg(0, "%s: Timeout\n", __func__); return false; } } } apcupsd-3.14.14/src/drivers/modbus/ModbusRs232Comm.h000066400000000000000000000024111274230402600220310ustar00rootroot00000000000000/* * ModbusRs232Comm.h * * Public header file for the modbus driver. */ /* * Copyright (C) 2014 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _MODBUSRS232COMM_H #define _MODBUSRS232COMM_H #include "ModbusComm.h" class ModbusRs232Comm: public ModbusComm { public: ModbusRs232Comm(uint8_t slaveaddr = DEFAULT_SLAVE_ADDR); virtual ~ModbusRs232Comm() {} virtual bool Open(const char *dev); virtual bool Close(); private: virtual bool ModbusTx(const ModbusFrame *frm, unsigned int sz); virtual bool ModbusRx(ModbusFrame *frm, unsigned int *sz); bool ModbusWaitIdle(); int _fd; }; #endif /* _MODBUSRS232COMM_H */ apcupsd-3.14.14/src/drivers/modbus/ModbusUsbComm.cpp000066400000000000000000000176651274230402600223230ustar00rootroot00000000000000/* * ModbusUsbComm.cpp * * USB communication layer for MODBUS driver */ /* * Copyright (C) 2014 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * Thanks go to APC/Schneider for providing the Apcupsd team with early access * to MODBUS protocol information to facilitate an Apcupsd driver. * * APC/Schneider has published the following relevant application notes: * * AN176: Modbus Implementation in APC Smart-UPS * * AN177: Software interface for Switched Outlet and UPS Management in Smart-UPS * * AN178: USB HID Implementation in Smart-UPS * */ #include "apc.h" #include "ModbusUsbComm.h" #define ModbusRTURx 0xFF8600FC #define ModbusRTUTx 0xFF8600FD ModbusUsbComm::ModbusUsbComm(uint8_t slaveaddr) : ModbusComm(slaveaddr) { } bool ModbusUsbComm::Open(const char *path) { // In case we're already open Close(); // Attempt to locate and open the UPS on USB if (!_hidups.Open(path)) return false; // Find ModbusRTUTx report hid_item_t item; if (!_hidups.LocateItem(ModbusRTUTx, -1, -1, -1, HID_KIND_INPUT, &item)) { Dmsg(0, "%s: Unable to find ModbusRTUTx usage\n", __func__); goto error; } _rxrpt = item.report_ID; Dmsg(100, "%s: Found ModbusRTUTx in report id %d\n", __func__, _rxrpt); // Find ModbusRTURx report if (!_hidups.LocateItem(ModbusRTURx, -1, -1, -1, HID_KIND_OUTPUT, &item)) { Dmsg(0, "%s: Unable to find ModbusRTURx usage\n", __func__); goto error; } _txrpt = item.report_ID; Dmsg(100, "%s: Found ModbusRTURx in report id %d\n", __func__, _txrpt); _open = true; return true; error: _hidups.Close(); return false; } bool ModbusUsbComm::Close() { _open = false; _hidups.Close(); return true; } bool ModbusUsbComm::ModbusTx(const ModbusFrame *frm, unsigned int sz) { // MODBUS/USB is limited to 63 bytes of payload (we don't bother with // fragmentation/reassembly). Since we drop the CRC (last 2 bytes) because // MODBUS/USB doesn't use it, frame size is 2 less than what caller says. if (sz-2 > MODBUS_USB_REPORT_MAX_FRAME_SIZE) return false; // Wait for idle if (!WaitIdle()) return false; Dmsg(100, "%s: Sending frame\n", __func__); hex_dump(100, frm, sz); // We add HID report id as the first byte of the report, then at most 63 // bytes of payload. uint8_t rpt[MODBUS_USB_REPORT_SIZE] = {0}; rpt[0] = _txrpt; memcpy(rpt+1, frm, sz-2); return _hidups.InterruptWrite(USB_ENDPOINT_OUT|1, rpt, MODBUS_USB_REPORT_SIZE, MODBUS_RESPONSE_TIMEOUT_MS) == (int)MODBUS_USB_REPORT_SIZE; } bool ModbusUsbComm::ModbusRx(ModbusFrame *frm, unsigned int *sz) { struct timeval now, exittime; // Determine time at which we need to exit gettimeofday(&exittime, NULL); exittime.tv_sec += MODBUS_RESPONSE_TIMEOUT_MS / 1000; exittime.tv_usec += (MODBUS_RESPONSE_TIMEOUT_MS % 1000) * 1000; if (exittime.tv_usec >= 1000000) { ++exittime.tv_sec; exittime.tv_usec -= 1000000; } int ret; uint8_t rpt[MODBUS_USB_REPORT_SIZE]; while (1) { gettimeofday(&now, NULL); int timeout = TV_DIFF_MS(now, exittime); if (timeout <= 0 || (ret = _hidups.InterruptRead(USB_ENDPOINT_IN|1, rpt, MODBUS_USB_REPORT_SIZE, timeout)) == -ETIMEDOUT) { Dmsg(0, "%s: TIMEOUT\n", __func__); return false; } // Temporary failure if (ret == -EINTR || ret == -EAGAIN) continue; // Fatal error if (ret <= 0) { Dmsg(0, "%s: Read error: %d\n", __func__, ret); return false; } // Filter out non-MODBUS reports if (rpt[0] != _rxrpt) { Dmsg(100, "%s: Ignoring report id %u\n", __func__, rpt[0]); continue; } // Bad report size ... fatal if (ret != (int)MODBUS_USB_REPORT_SIZE) { Dmsg(0, "%s: Bad size %d\n", __func__, ret); return false; } // We always get a full report containing MODBUS_USB_REPORT_MAX_FRAME_SIZE // bytes of data. Clip to actual size of live data by looking at the MODBUS // PDU header. This is a blatant layering violation, but no way around it // here. Which byte(s) we look at and how we calculate the length depends // on the opcode. unsigned frmsz; if (rpt[2] == MODBUS_FC_READ_HOLDING_REGS) { // READ_HOLDING_REGS response includes a size byte. // Add 3 bytes to PDU size to account for size byte itself // plus frame header (slaveaddr and op code). frmsz = rpt[3] + 3; } else if (rpt[2] == MODBUS_FC_WRITE_MULTIPLE_REGS) { // WRITE_MULTIPLE_REGS response is always a fixed length // 2 byte frame header (slaveaddr and op code) // 2 byte register starting address // 2 byte register count frmsz = 6; } else { // Unsupported response message...we can't calculate its length Dmsg(0, "%s: Unknown response type %x\n", __func__, rpt[2]); hex_dump(0, rpt, MODBUS_USB_REPORT_SIZE); return false; } if (frmsz > MODBUS_USB_REPORT_MAX_FRAME_SIZE) { Dmsg(0, "%s: Fragmented PDU received...not supported\n", __func__); return false; } // Copy data to caller's buffer. Live data starts after USB report id byte. memcpy(frm, rpt+1, frmsz); // MODBUS/USB doesn't provide a CRC. // Fill one in to make upper layer happy. uint16_t crc = ModbusCrc(*frm, frmsz); (*frm)[frmsz] = crc & 0xff; (*frm)[frmsz+1] = crc >> 8; *sz = frmsz + 2; hex_dump(100, frm, *sz); return true; } } #define S_TO_NS(x) ( (x) * 1000000000ULL ) #define MS_TO_NS(x) ( (x) * 1000000ULL ) #define US_TO_NS(x) ( (x) * 1000ULL ) #define NS_TO_MS(x) ( ((x)+999999) / 1000000ULL ) uint64_t ModbusUsbComm::GetTod() { struct timeval now; gettimeofday(&now, NULL); return S_TO_NS(now.tv_sec) + US_TO_NS(now.tv_usec); } bool ModbusUsbComm::WaitIdle() { // Current TOD uint64_t now = GetTod(); // When we will give up by uint64_t exittime = now + MS_TO_NS(MODBUS_IDLE_WAIT_TIMEOUT_MS); // Initial idle target uint64_t target = now + MS_TO_NS(MODBUS_INTERFRAME_TIMEOUT_MS); uint8_t rpt[MODBUS_USB_REPORT_SIZE]; while (target <= exittime) { int rc = _hidups.InterruptRead(USB_ENDPOINT_IN|1, rpt, MODBUS_USB_REPORT_SIZE, NS_TO_MS(target-now)); if (rc == -ETIMEDOUT) { // timeout: line is now idle return true; } else if (rc <= 0 && rc != -EINTR && rc != -EAGAIN) { // fatal error Dmsg(0, "%s: interrupt_read failed: %s\n", __func__, strerror(-rc)); return false; } // Refresh TOD now = GetTod(); if (rc > 0) { if (rpt[0] == _rxrpt) { Dmsg(0, "%s: Out of sync\n", __func__); hex_dump(0, rpt, rc); // Reset wait time target = now + MS_TO_NS(MODBUS_INTERFRAME_TIMEOUT_MS); } else { // Non-MODBUS reports are not an issue, just continue waiting Dmsg(100, "%s: Non-MODBUS report id %u\n", __func__, rpt[0]); } } } return false; } apcupsd-3.14.14/src/drivers/modbus/ModbusUsbComm.h000066400000000000000000000027501274230402600217550ustar00rootroot00000000000000/* * ModbusUsbComm.h * * Public header file for the modbus driver. */ /* * Copyright (C) 2014 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _MODBUSUSBCOMM_H #define _MODBUSUSBCOMM_H #include "ModbusComm.h" #include "HidUps.h" class ModbusUsbComm: public ModbusComm { public: ModbusUsbComm(uint8_t slaveaddr = DEFAULT_SLAVE_ADDR); virtual ~ModbusUsbComm() {} virtual bool Open(const char *dev); virtual bool Close(); private: virtual bool ModbusTx(const ModbusFrame *frm, unsigned int sz); virtual bool ModbusRx(ModbusFrame *frm, unsigned int *sz); bool WaitIdle(); static uint64_t GetTod(); static const unsigned MODBUS_USB_REPORT_SIZE = 64; static const unsigned MODBUS_USB_REPORT_MAX_FRAME_SIZE = MODBUS_USB_REPORT_SIZE - 1; HidUps _hidups; uint8_t _rxrpt; uint8_t _txrpt; }; #endif /* _MODBUSUSBCOMM_H */ apcupsd-3.14.14/src/drivers/modbus/mapping.cpp000066400000000000000000000230601274230402600212210ustar00rootroot00000000000000/* * mapping.cpp * * APC MODBUS register mappings */ /* * Copyright (C) 2013 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * Register mapping information below was derived from APC/Schneider Electric * Application Note #176 * * Thanks go to APC/Schneider for providing the Apcupsd team with early access * to MODBUS protocol information to facilitate an Apcupsd driver. * * APC/Schneider has published the following relevant application notes: * * AN176: Modbus Implementation in APC Smart-UPS * * AN177: Software interface for Switched Outlet and UPS Management in Smart-UPS * * AN178: USB HID Implementation in Smart-UPS * */ #include "mapping.h" using namespace APCModbusMapping; // APC MODBUS Registers addr nr type scale const RegInfo APCModbusMapping::REG_UPS_STATUS = { 0, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_UPS_STATUS_CHANGE_CAUSE = { 2, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_MOG_OUTLET_STATUS = { 3, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_SOG0_OUTLET_STATUS = { 6, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_SOG1_OUTLET_STATUS = { 9, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_SOG2_OUTLET_STATUS = { 12, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_SOG3_OUTLET_STATUS = { 15, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_SIMPLE_SIGNALLING_STATUS = { 18, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_GENERAL_ERROR = { 19, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_POWER_SYSTEM_ERROR = { 20, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_BATTERY_SYSTEM_ERROR = { 22, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_BATTERY_TEST_STATUS = { 23, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_CALIBRATION_STATUS = { 24, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_BATTERY_LIFETIME_STATUS = { 25, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_USER_INTERFACE_STATUS = { 26, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_RUNTIME_REMAINING = { 128, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_STATE_OF_CHARGE_PCT = { 130, 1, DT_UINT, 9 }; const RegInfo APCModbusMapping::REG_BATTERY_VOLTAGE = { 131, 1, DT_INT, 5 }; const RegInfo APCModbusMapping::REG_BATTERY_DATE = { 133, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_BATTERY_TEMPERATURE = { 135, 1, DT_INT, 7 }; const RegInfo APCModbusMapping::REG_OUTPUT_0_REAL_POWER_PCT = { 136, 1, DT_UINT, 8 }; const RegInfo APCModbusMapping::REG_OUTPUT_0_APPARENT_POWER_PCT = { 138, 1, DT_UINT, 8 }; const RegInfo APCModbusMapping::REG_OUTPUT_0_CURRENT = { 140, 1, DT_UINT, 5 }; const RegInfo APCModbusMapping::REG_OUTPUT_0_VOLTAGE = { 142, 1, DT_UINT, 6 }; const RegInfo APCModbusMapping::REG_OUTPUT_FREQUENCY = { 144, 1, DT_UINT, 7 }; const RegInfo APCModbusMapping::REG_OUTPUT_ENERGY = { 145, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_INPUT_STATUS = { 150, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_INPUT_0_VOLTAGE = { 151, 1, DT_UINT, 6 }; const RegInfo APCModbusMapping::REG_INPUT_EFFICIENCY = { 154, 1, DT_INT }; const RegInfo APCModbusMapping::REG_MOG_TURN_OFF_COUNTDOWN = { 155, 1, DT_INT }; const RegInfo APCModbusMapping::REG_MOG_TURN_ON_COUNTDOWN = { 156, 1, DT_INT }; const RegInfo APCModbusMapping::REG_MOG_STAY_OFF_COUNTDOWN = { 157, 2, DT_INT }; const RegInfo APCModbusMapping::REG_SOG0_TURN_OFF_COUNTDOWN = { 159, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG0_TURN_ON_COUNTDOWN = { 160, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG0_STAY_OFF_COUNTDOWN = { 161, 2, DT_INT }; const RegInfo APCModbusMapping::REG_SOG1_TURN_OFF_COUNTDOWN = { 163, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG1_TURN_ON_COUNTDOWN = { 164, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG1_STAY_OFF_COUNTDOWN = { 165, 2, DT_INT }; const RegInfo APCModbusMapping::REG_SOG2_TURN_OFF_COUNTDOWN = { 167, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG2_TURN_ON_COUNTDOWN = { 168, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG2_STAY_OFF_COUNTDOWN = { 169, 2, DT_INT }; const RegInfo APCModbusMapping::REG_SOG3_TURN_OFF_COUNTDOWN = { 171, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG3_TURN_ON_COUNTDOWN = { 172, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG3_STAY_OFF_COUNTDOWN = { 173, 2, DT_INT }; const RegInfo APCModbusMapping::REG_FW_VERSION = { 516, 8, DT_STRING }; const RegInfo APCModbusMapping::REG_MODEL = { 532, 16, DT_STRING }; const RegInfo APCModbusMapping::REG_SKU = { 548, 16, DT_STRING }; const RegInfo APCModbusMapping::REG_SERIAL_NUMBER = { 564, 8, DT_STRING }; const RegInfo APCModbusMapping::REG_BATTERY_SKU = { 572, 8, DT_STRING }; const RegInfo APCModbusMapping::REG_EXTERNAL_BATTERY_SKU = { 580, 8, DT_STRING }; const RegInfo APCModbusMapping::REG_OUTPUT_APPARENT_POWER_RATING = { 588, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_OUTPUT_REAL_POWER_RATING = { 589, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_SOG_RELAY_CONFIG = { 590, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_MANUFACTURE_DATE = { 591, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_OUTPUT_VOLTAGE_SETTING = { 592, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_BATTERY_DATE_SETTING = { 595, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_NAME = { 596, 8, DT_STRING }; const RegInfo APCModbusMapping::REG_MOG_TURN_OFF_COUNT_SETTING = { 1029, 1, DT_INT }; const RegInfo APCModbusMapping::REG_MOG_TURN_ON_COUNT_SETTING = { 1030, 1, DT_INT }; const RegInfo APCModbusMapping::REG_MOG_STAY_OFF_COUNT_SETTING = { 1031, 2, DT_INT }; const RegInfo APCModbusMapping::REG_SOG0_TURN_OFF_COUNT_SETTING = { 1033, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG0_TURN_ON_COUNT_SETTING = { 1034, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG0_STAY_OFF_COUNT_SETTING = { 1035, 2, DT_INT }; const RegInfo APCModbusMapping::REG_SOG1_TURN_OFF_COUNT_SETTING = { 1037, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG1_TURN_ON_COUNT_SETTING = { 1038, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG1_STAY_OFF_COUNT_SETTING = { 1039, 2, DT_INT }; const RegInfo APCModbusMapping::REG_SOG2_TURN_OFF_COUNT_SETTING = { 1041, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG2_TURN_ON_COUNT_SETTING = { 1042, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG2_STAY_OFF_COUNT_SETTING = { 1043, 2, DT_INT }; const RegInfo APCModbusMapping::REG_SOG3_TURN_OFF_COUNT_SETTING = { 1045, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG3_TURN_ON_COUNT_SETTING = { 1046, 1, DT_INT }; const RegInfo APCModbusMapping::REG_SOG3_STAY_OFF_COUNT_SETTING = { 1047, 2, DT_INT }; const RegInfo APCModbusMapping::REG_UPS_CMD = { 1536, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_OUTLET_CMD = { 1538, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_SIMPLE_SIGNALLING_CMD = { 1540, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_BATTERY_TEST_CMD = { 1541, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_CALIBRATION_CMD = { 1542, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_USER_INTERFACE_CMD = { 1543, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_MODBUS_MAP_ID = { 2048, 2, DT_STRING }; const RegInfo APCModbusMapping::REG_TEST_STRING = { 2050, 4, DT_STRING }; const RegInfo APCModbusMapping::REG_TEST_4B_NUMBER_1 = { 2054, 2, DT_UINT }; const RegInfo APCModbusMapping::REG_TEST_4B_NUMBER_2 = { 2056, 2, DT_INT }; const RegInfo APCModbusMapping::REG_TEST_2B_NUMBER_1 = { 2058, 1, DT_UINT }; const RegInfo APCModbusMapping::REG_TEST_2B_NUMBER_2 = { 2059, 1, DT_INT }; const RegInfo APCModbusMapping::REG_TEST_BPI_NUMBER_1 = { 2060, 1, DT_INT, 6 }; const RegInfo APCModbusMapping::REG_TEST_BPI_NUMBER_2 = { 2061, 1, DT_INT, 6 }; apcupsd-3.14.14/src/drivers/modbus/mapping.h000066400000000000000000000441731274230402600206760ustar00rootroot00000000000000/* * mapping.h * * APC MODBUS register mappings */ /* * Copyright (C) 2013 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * Register mapping information below was derived from APC/Schneider Electric * Application Note #176 * * Thanks go to APC/Schneider for providing the Apcupsd team with early access * to MODBUS protocol information to facilitate an Apcupsd driver. * * APC/Schneider has published the following relevant application notes: * * AN176: Modbus Implementation in APC Smart-UPS * * AN177: Software interface for Switched Outlet and UPS Management in Smart-UPS * * AN178: USB HID Implementation in Smart-UPS * */ #ifndef __APCMODBUSMAPPING_H_ #define __APCMODBUSMAPPING_H_ #include #include namespace APCModbusMapping { enum DataType { DT_STRING, // ASCII string DT_UINT, // Unsigned integer or float DT_INT, // Signed integer or float }; struct RegInfo { // MODBUS address of first register uint16_t addr; // Number of consecutive registers that comprise this data element uint16_t nregs; // Type of the data DataType type; // Scaling to be applied to convert INT/UINT to float uint8_t scale; }; // Dates in APC MODBUS registers are expressed as number of days since // 1/1/2000. This constant represents 1/1/2000 (UTC) as UNIX timestamp. static const time_t MODBUS_BASE_TIMESTAMP = 946684800; inline time_t ModbusRegTotime_t(uint64_t reg) { return MODBUS_BASE_TIMESTAMP + reg * 60 * 60 * 24; } inline uint64_t time_tToModbusReg(time_t t) { return (t - MODBUS_BASE_TIMESTAMP) / 60 / 60 / 24; } // UPS_STATUS register bits static const uint32_t US_ONLINE = (1U << 1); static const uint32_t US_ONBATTERY = (1U << 2); static const uint32_t US_OUTPUTOFF = (1U << 4); static const uint32_t US_FAULT = (1U << 5); static const uint32_t US_INPUTBAD = (1U << 6); static const uint32_t US_TEST = (1U << 7); static const uint32_t US_PENDING_OUTPUTON = (1U << 8); static const uint32_t US_PENDING_OUTPUTOFF = (1U << 9); static const uint32_t US_HIGH_EFFICIENCY = (1U << 13); static const uint32_t US_INFO_ALERT = (1U << 14); // SIMPLE_SIGNALING_STATUS register bits static const uint32_t SSS_POWER_FAILURE = (1U << 0); static const uint32_t SSS_SHUTDOWN_IMMINENT = (1U << 1); // GENERAL_ERROR register bits static const uint32_t GE_SITE_WIRING = (1U << 0); static const uint32_t GE_EEPROM = (1U << 1); static const uint32_t GE_ADC = (1U << 2); static const uint32_t GE_LOGIC_PS = (1U << 3); static const uint32_t GE_INTERNAL_COMMS = (1U << 4); static const uint32_t GE_UI_BUTTON = (1U << 5); static const uint32_t GE_EPO_ACTIVE = (1U << 7); // POWER_SYSTEM_ERROR register bits static const uint32_t PSE_OUTPUT_OVERLOAD = (1U << 0); static const uint32_t PSE_OUTPUT_SHORT = (1U << 1); static const uint32_t PSE_OUTPUT_OVERVOLT = (1U << 2); static const uint32_t PSE_OUTPUT_OVERTEMP = (1U << 4); static const uint32_t PSE_BACKFEED_RELAY = (1U << 5); static const uint32_t PSE_AVR_RELAY = (1U << 6); static const uint32_t PSE_PFCINPUT_RELAY = (1U << 7); static const uint32_t PSE_OUTPUT_RELAY = (1U << 8); static const uint32_t PSE_BYPASS_RELAY = (1U << 9); static const uint32_t PSE_PFC = (1U << 11); static const uint32_t PSE_DC_BUS_OVERVOLT = (1U << 12); static const uint32_t PSE_INVERTER = (1U << 13); // BATTERY_SYSTEM_ERROR register bits static const uint32_t BSE_DISCONNECTED = (1U << 0); static const uint32_t BSE_OVERVOLT = (1U << 1); static const uint32_t BSE_NEEDS_REPLACEMENT = (1U << 2); static const uint32_t BSE_OVERTEMP = (1U << 3); static const uint32_t BSE_CHARGER = (1U << 4); static const uint32_t BSE_TEMP_SENSOR = (1U << 5); static const uint32_t BSE_BUS_SOFT_START = (1U << 6); // BATTERY_TEST_STATUS register bits static const uint32_t BTS_PENDING = (1U << 0); // result static const uint32_t BTS_IN_PROGRESS = (1U << 1); // result static const uint32_t BTS_PASSED = (1U << 2); // result static const uint32_t BTS_FAILED = (1U << 3); // result static const uint32_t BTS_REFUSED = (1U << 4); // result static const uint32_t BTS_ABORTED = (1U << 5); // result static const uint32_t BTS_SRC_PROTOCOL = (1U << 6); // source static const uint32_t BTS_SRC_LOCAL_UI = (1U << 7); // source static const uint32_t BTS_SRC_INTERNAL = (1U << 8); // source static const uint32_t BTS_INVALID_STATE = (1U << 9); // result modifier static const uint32_t BTS_INTERNAL_FAULT = (1U << 10); // result modifier static const uint32_t BTS_STATE_OF_CHARGE = (1U << 11); // result modifier // CALIBRATION_STATUS register bits static const uint32_t CS_PENDING = (1U << 0); // result static const uint32_t CS_IN_PROGRESS = (1U << 1); // result static const uint32_t CS_PASSED = (1U << 2); // result static const uint32_t CS_FAILED = (1U << 3); // result static const uint32_t CS_REFUSED = (1U << 4); // result static const uint32_t CS_ABORTED = (1U << 5); // result static const uint32_t CS_SRC_PROTOCOL = (1U << 6); // source static const uint32_t CS_SRC_LOCAL_UI = (1U << 7); // source static const uint32_t CS_SRC_INTERNAL = (1U << 8); // source static const uint32_t CS_INVALID_STATE = (1U << 9); // result modifier static const uint32_t CS_INTERNAL_FAULT = (1U << 10); // result modifier static const uint32_t CS_STATE_OF_CHARGE = (1U << 11); // result modifier static const uint32_t CS_LOAD_CHANGE = (1U << 12); // result modifier static const uint32_t CS_AC_INPUT_BAD = (1U << 13); // result modifier static const uint32_t CS_LOAD_TOO_LOW = (1U << 14); // result modifier static const uint32_t CS_OVER_CHARGE = (1U << 15); // result modifier // BATTERY_LIFETIME_STATUS register bits static const uint32_t BLS_OK = (1U << 0); static const uint32_t BLS_NEAR_END = (1U << 1); static const uint32_t BLS_EXCEEDED = (1U << 2); static const uint32_t BLS_NEAR_END_ACK = (1U << 3); static const uint32_t BLS_EXCEEDED_ACK = (1U << 4); // USER_INTERFACE_STATUS register bits static const uint32_t UIS_TEST_IN_PROGRESS = (1U << 0); static const uint32_t UIS_AUDIBLE_ALARM = (1U << 1); static const uint32_t UIS_ALARM_MUTED = (1U << 2); // INPUT_STATUS register bits static const uint32_t IS_ACCEPTABLE = (1U << 0); static const uint32_t IS_PENDING_ACCEPTABLE = (1U << 1); static const uint32_t IS_LOW_VOLTAGE = (1U << 2); static const uint32_t IS_HIGH_VOLTAGE = (1U << 3); static const uint32_t IS_DISTORTED = (1U << 4); static const uint32_t IS_BOOST = (1U << 5); static const uint32_t IS_TRIM = (1U << 6); static const uint32_t IS_LOW_FREQ = (1U << 7); static const uint32_t IS_HIGH_FREQ = (1U << 8); static const uint32_t IS_FREQ_PHASE_UNLOCKED = (1U << 9); // OUTPUT_VOLTAGE_SETTING register bits static const uint32_t OVS_100VAC = (1U << 0); static const uint32_t OVS_120VAC = (1U << 1); static const uint32_t OVS_200VAC = (1U << 2); static const uint32_t OVS_208VAC = (1U << 3); static const uint32_t OVS_220VAC = (1U << 4); static const uint32_t OVS_230VAC = (1U << 5); static const uint32_t OVS_240VAC = (1U << 6); // SIMPLE_SIGNALING_CMD register bits static const uint32_t SSC_REQUEST_SHUTDOWN = (1U << 0); static const uint32_t SSC_REMOTE_OFF = (1U << 1); static const uint32_t SSC_REMOTE_ON = (1U << 2); // BATTERY_TEST_CMD register bits static const uint32_t BTC_START_TEST = (1U << 0); // CALIBRATION_CMD register bits static const uint32_t CC_START_CALIBRATION = (1U << 0); static const uint32_t CC_ABORT_CALIBRATION = (1U << 1); // USER_INTERFACE_CMD register bits static const uint32_t UIC_SHORT_TEST = (1U << 0); static const uint32_t UIC_CONTINUOUS_TEST = (1U << 1); static const uint32_t UIC_MUTE_ALARMS = (1U << 2); static const uint32_t UIC_UNMUTE_ALARMS = (1U << 3); static const uint32_t UIC_ACK_BATTERY_ALARMS = (1U << 5); // OUTLET_STATUS register bits static const uint32_t OS_STATE_ON = (1U << 0); static const uint32_t OS_STATE_OFF = (1U << 1); static const uint32_t OS_PROCESS_REBOOT = (1U << 2); // modifier static const uint32_t OS_PROCESS_SHUTDOWN = (1U << 3); // modifier static const uint32_t OS_PROCESS_SLEEP = (1U << 4); // modifier static const uint32_t OS_PEND_OFF_DELAY = (1U << 7); // modifier static const uint32_t OS_PEND_ON_AC_PRESENCE = (1U << 8); // modifier static const uint32_t OS_PEND_ON_MIN_RUNTIME = (1U << 9); // modifier static const uint32_t OS_MEMBER_GROUP_PROC1 = (1U << 10); // modifier static const uint32_t OS_MEMBER_GROUP_PROC2 = (1U << 11); // modifier static const uint32_t OS_LOW_RUNTIME = (1U << 12); // modifier // OUTLET_COMMAND register bits static const uint32_t OC_CANCEL = (1U << 0); // command static const uint32_t OC_OUTPUT_ON = (1U << 1); // command static const uint32_t OC_OUTPUT_OFF = (1U << 2); // command static const uint32_t OC_OUTPUT_SHUTDOWN = (1U << 3); // command static const uint32_t OC_OUTPUT_REBOOT = (1U << 4); // command static const uint32_t OC_COLD_BOOT_ALLOWED = (1U << 5); // modifier static const uint32_t OC_USE_ON_DELAY = (1U << 6); // modifier static const uint32_t OC_USE_OFF_DELAY = (1U << 7); // modifier static const uint32_t OC_TARGET_UOG = (1U << 8); // target static const uint32_t OC_TARGET_SOG0 = (1U << 9); // target static const uint32_t OC_TARGET_SOG1 = (1U << 10); // target static const uint32_t OC_TARGET_SOG2 = (1U << 11); // target static const uint32_t OC_SRC_USB = (1U << 12); // source static const uint32_t OC_SRC_LOCAL_UI = (1U << 13); // source static const uint32_t OC_SRC_RJ45 = (1U << 14); // source static const uint32_t OC_SRC_SMARTSLOT1 = (1U << 15); // source // SOG_RELAY_CONFIG register bits static const uint32_t SRC_MOG_PRESENT = (1U << 0); static const uint32_t SRC_SOG0_PRESENT = (1U << 1); static const uint32_t SRC_SOG1_PRESENT = (1U << 2); static const uint32_t SRC_SOG2_PRESENT = (1U << 3); static const uint32_t SRC_SOG3_PRESENT = (1U << 4); // UPS_STATUS_CHANGE_CAUSE enum static const uint32_t USCC_SYSTEM_INIT = 0; static const uint32_t USCC_HIGH_INPUT_VOLTAGE = 1; static const uint32_t USCC_LOW_INPUT_VOLTAGE = 2; static const uint32_t USCC_DISTORTED_INPUT = 3; static const uint32_t USCC_RAPID_CHANGE = 4; static const uint32_t USCC_HIGH_INPUT_FREQ = 5; static const uint32_t USCC_LOW_INPUT_FREQ = 6; static const uint32_t USCC_FREQ_PHASE_DIFF = 7; static const uint32_t USCC_ACCEPTABLE_INPUT = 8; static const uint32_t USCC_AUTOMATIC_TEST = 9; static const uint32_t USCC_TEST_ENDED = 10; static const uint32_t USCC_LOCAL_UI_CMD = 11; static const uint32_t USCC_PROTOCOL_CMD = 12; static const uint32_t USCC_LOW_BATTERY_VOLTAGE = 13; static const uint32_t USCC_GENERAL_ERROR = 14; static const uint32_t USCC_POWER_SYSTEM_ERROR = 15; static const uint32_t USCC_BATTERY_SYSTEM_ERROR = 16; static const uint32_t USCC_ERROR_CLEARED = 17; static const uint32_t USCC_AUTO_RESTART = 18; static const uint32_t USCC_OUTPUT_DISTORTED = 19; static const uint32_t USCC_OUTPUT_ACCEPTABLE = 20; static const uint32_t USCC_EPO_INTERFACE = 21; static const uint32_t USCC_INPUT_PHASE_DELTA_OUT_OF_RANGE = 22; static const uint32_t USCC_INPUT_NEUTRAL_DISCONNECTED = 23; static const uint32_t USCC_ATS_TRANSFER = 24; static const uint32_t USCC_CONFIG_CHANGE = 25; static const uint32_t USCC_ALERT_ASSERTED = 26; static const uint32_t USCC_ALERT_CLEARED = 27; static const uint32_t USCC_PLUG_RATING_EXCEEDED = 28; static const uint32_t USCC_OUTLET_GRP_STATE_CHANGE = 29; static const uint32_t USCC_FAILURE_BYPASS_EXPIRED = 30; // Registers extern const RegInfo REG_UPS_STATUS; extern const RegInfo REG_UPS_STATUS_CHANGE_CAUSE; extern const RegInfo REG_MOG_OUTLET_STATUS; extern const RegInfo REG_SOG0_OUTLET_STATUS; extern const RegInfo REG_SOG1_OUTLET_STATUS; extern const RegInfo REG_SOG2_OUTLET_STATUS; extern const RegInfo REG_SOG3_OUTLET_STATUS; extern const RegInfo REG_SIMPLE_SIGNALLING_STATUS; extern const RegInfo REG_GENERAL_ERROR; extern const RegInfo REG_POWER_SYSTEM_ERROR; extern const RegInfo REG_BATTERY_SYSTEM_ERROR; extern const RegInfo REG_BATTERY_TEST_STATUS; extern const RegInfo REG_CALIBRATION_STATUS; extern const RegInfo REG_BATTERY_LIFETIME_STATUS; extern const RegInfo REG_USER_INTERFACE_STATUS; extern const RegInfo REG_RUNTIME_REMAINING; extern const RegInfo REG_STATE_OF_CHARGE_PCT; extern const RegInfo REG_BATTERY_VOLTAGE; extern const RegInfo REG_BATTERY_DATE; extern const RegInfo REG_BATTERY_TEMPERATURE; extern const RegInfo REG_OUTPUT_0_REAL_POWER_PCT; extern const RegInfo REG_OUTPUT_0_APPARENT_POWER_PCT; extern const RegInfo REG_OUTPUT_0_CURRENT; extern const RegInfo REG_OUTPUT_0_VOLTAGE; extern const RegInfo REG_OUTPUT_FREQUENCY; extern const RegInfo REG_OUTPUT_ENERGY; extern const RegInfo REG_INPUT_STATUS; extern const RegInfo REG_INPUT_0_VOLTAGE; extern const RegInfo REG_INPUT_EFFICIENCY; extern const RegInfo REG_MOG_TURN_OFF_COUNTDOWN; extern const RegInfo REG_MOG_TURN_ON_COUNTDOWN; extern const RegInfo REG_MOG_STAY_OFF_COUNTDOWN; extern const RegInfo REG_SOG0_TURN_OFF_COUNTDOWN; extern const RegInfo REG_SOG0_TURN_ON_COUNTDOWN; extern const RegInfo REG_SOG0_STAY_OFF_COUNTDOWN; extern const RegInfo REG_SOG1_TURN_OFF_COUNTDOWN; extern const RegInfo REG_SOG1_TURN_ON_COUNTDOWN; extern const RegInfo REG_SOG1_STAY_OFF_COUNTDOWN; extern const RegInfo REG_SOG2_TURN_OFF_COUNTDOWN; extern const RegInfo REG_SOG2_TURN_ON_COUNTDOWN; extern const RegInfo REG_SOG2_STAY_OFF_COUNTDOWN; extern const RegInfo REG_SOG3_TURN_OFF_COUNTDOWN; extern const RegInfo REG_SOG3_TURN_ON_COUNTDOWN; extern const RegInfo REG_SOG3_STAY_OFF_COUNTDOWN; extern const RegInfo REG_FW_VERSION; extern const RegInfo REG_MODEL; extern const RegInfo REG_SKU; extern const RegInfo REG_SERIAL_NUMBER; extern const RegInfo REG_BATTERY_SKU; extern const RegInfo REG_EXTERNAL_BATTERY_SKU; extern const RegInfo REG_OUTPUT_APPARENT_POWER_RATING; extern const RegInfo REG_OUTPUT_REAL_POWER_RATING; extern const RegInfo REG_SOG_RELAY_CONFIG; extern const RegInfo REG_MANUFACTURE_DATE; extern const RegInfo REG_OUTPUT_VOLTAGE_SETTING; extern const RegInfo REG_BATTERY_DATE_SETTING; extern const RegInfo REG_NAME; extern const RegInfo REG_MOG_TURN_OFF_COUNT_SETTING; extern const RegInfo REG_MOG_TURN_ON_COUNT_SETTING; extern const RegInfo REG_MOG_STAY_OFF_COUNT_SETTING; extern const RegInfo REG_SOG0_TURN_OFF_COUNT_SETTING; extern const RegInfo REG_SOG0_TURN_ON_COUNT_SETTING; extern const RegInfo REG_SOG0_STAY_OFF_COUNT_SETTING; extern const RegInfo REG_SOG1_TURN_OFF_COUNT_SETTING; extern const RegInfo REG_SOG1_TURN_ON_COUNT_SETTING; extern const RegInfo REG_SOG1_STAY_OFF_COUNT_SETTING; extern const RegInfo REG_SOG2_TURN_OFF_COUNT_SETTING; extern const RegInfo REG_SOG2_TURN_ON_COUNT_SETTING; extern const RegInfo REG_SOG2_STAY_OFF_COUNT_SETTING; extern const RegInfo REG_SOG3_TURN_OFF_COUNT_SETTING; extern const RegInfo REG_SOG3_TURN_ON_COUNT_SETTING; extern const RegInfo REG_SOG3_STAY_OFF_COUNT_SETTING; extern const RegInfo REG_UPS_CMD; extern const RegInfo REG_OUTLET_CMD; extern const RegInfo REG_SIMPLE_SIGNALLING_CMD; extern const RegInfo REG_BATTERY_TEST_CMD; extern const RegInfo REG_CALIBRATION_CMD; extern const RegInfo REG_USER_INTERFACE_CMD; extern const RegInfo REG_MODBUS_MAP_ID; extern const RegInfo REG_TEST_STRING; extern const RegInfo REG_TEST_4B_NUMBER_1; extern const RegInfo REG_TEST_4B_NUMBER_2; extern const RegInfo REG_TEST_2B_NUMBER_1; extern const RegInfo REG_TEST_2B_NUMBER_2; extern const RegInfo REG_TEST_BPI_NUMBER_1; extern const RegInfo REG_TEST_BPI_NUMBER_2; }; #endif // __APCMODBUSMAPPING_H_ apcupsd-3.14.14/src/drivers/modbus/modbus.cpp000066400000000000000000000515711274230402600210670ustar00rootroot00000000000000/* * modbus.cpp * * Driver for APC MODBUS protocol */ /* * Copyright (C) 2013 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * Thanks go to APC/Schneider for providing the Apcupsd team with early access * to MODBUS protocol information to facilitate an Apcupsd driver. * * APC/Schneider has published the following relevant application notes: * * AN176: Modbus Implementation in APC Smart-UPS * * AN177: Software interface for Switched Outlet and UPS Management in Smart-UPS * * AN178: USB HID Implementation in Smart-UPS * */ #include "apc.h" #include "modbus.h" #include "astring.h" #include "ModbusRs232Comm.h" #ifdef HAVE_MODBUS_USB_DRIVER #include "ModbusUsbComm.h" #endif using namespace APCModbusMapping; const ModbusUpsDriver::CiInfo ModbusUpsDriver::CI_TABLE[] = { // ci dynamic addr ln type { CI_UPSMODEL, false, ®_MODEL }, { CI_SERNO, false, ®_SERIAL_NUMBER }, { CI_IDEN, false, ®_NAME }, { CI_MANDAT, false, ®_MANUFACTURE_DATE }, { CI_BATTDAT, false, ®_BATTERY_DATE_SETTING }, { CI_NOMOUTV, false, ®_OUTPUT_VOLTAGE_SETTING }, { CI_REVNO, false, ®_FW_VERSION }, { CI_BUPSelfTest, false, ®_MODBUS_MAP_ID }, // Purposely after CI_REVNO { CI_NOMPOWER, false, ®_OUTPUT_REAL_POWER_RATING }, { CI_NomApparent, false, ®_OUTPUT_APPARENT_POWER_RATING }, { CI_DSHUTD, false, ®_MOG_TURN_OFF_COUNT_SETTING }, { CI_DWAKE, false, ®_MOG_TURN_ON_COUNT_SETTING }, // { CI_NOMBATTV, false, upsAdvBatteryNominalVoltage, // { CI_AlarmTimer, false, upsAdvConfigAlarmTimer, // { CI_DALARM, false, upsAdvConfigAlarm, // { CI_DLBATT, false, upsAdvConfigLowBatteryRunTime, // { CI_RETPCT, false, upsAdvConfigMinReturnCapacity, // { CI_SENS, false, upsAdvConfigSensitivity, // { CI_EXTBATTS, false, upsAdvBatteryNumOfBattPacks, // { CI_STESTI, false, // { CI_LTRANS, false, // { CI_HTRANS, false, { CI_VLINE, true, ®_INPUT_0_VOLTAGE }, { CI_VOUT, true, ®_OUTPUT_0_VOLTAGE }, { CI_OutputCurrent, true, ®_OUTPUT_0_CURRENT }, { CI_VBATT, true, ®_BATTERY_VOLTAGE }, { CI_FREQ, true, ®_OUTPUT_FREQUENCY }, { CI_ITEMP, true, ®_BATTERY_TEMPERATURE }, { CI_BATTLEV, true, ®_STATE_OF_CHARGE_PCT }, { CI_RUNTIM, true, ®_RUNTIME_REMAINING }, { CI_STATUS, true, ®_UPS_STATUS }, { CI_WHY_BATT, true, ®_UPS_STATUS_CHANGE_CAUSE },// purposely after CI_STATUS { CI_Calibration, true, ®_CALIBRATION_STATUS }, { CI_ST_STAT, true, ®_BATTERY_TEST_STATUS }, { CI_Overload, true, ®_POWER_SYSTEM_ERROR }, { CI_NeedReplacement, true, ®_BATTERY_SYSTEM_ERROR }, { CI_BatteryPresent, true, ®_BATTERY_SYSTEM_ERROR }, { CI_Boost, true, ®_INPUT_STATUS }, { CI_Trim, true, ®_INPUT_STATUS }, { CI_LOAD, true, ®_OUTPUT_0_REAL_POWER_PCT }, { CI_LoadApparent, true, ®_OUTPUT_0_APPARENT_POWER_PCT }, { CI_LowBattery, true, ®_SIMPLE_SIGNALLING_STATUS }, // { CI_VMIN, true, upsAdvInputMinLineVoltage // { CI_VMAX, true, upsAdvInputMaxLineVoltage // { CI_ATEMP, true, mUpsEnvironAmbientTemperature // { CI_HUMID, true, mUpsEnvironRelativeHumidity // { CI_BADBATTS, true, upsAdvBatteryNumOfBadBattPacks { -1 } /* END OF TABLE */ }; ModbusUpsDriver::ModbusUpsDriver(UPSINFO *ups) : UpsDriver(ups), _commlost_time(0), _comm(NULL) { } /* * Read UPS events. I.e. state changes. */ bool ModbusUpsDriver::check_state() { bool ret, onbatt, online; // Determine when we need to exit by struct timeval exittime, now; gettimeofday(&exittime, NULL); exittime.tv_sec += _ups->wait_time; while(1) { // See if it's time to exit gettimeofday(&now, NULL); if (now.tv_sec > exittime.tv_sec || (now.tv_sec == exittime.tv_sec && now.tv_usec >= exittime.tv_usec)) { return false; } // Try to recover from commlost by reopening port ret = !_ups->is_commlost() || _comm->Open(_ups->device); if (ret) { // Remember current online/onbatt state online = _ups->is_online(); onbatt = _ups->is_onbatt(); // Poll CI_STATUS ret = UpdateCi(CI_STATUS); } if (ret) { // If we were commlost, we're not any more if (_ups->is_commlost()) { _ups->clear_commlost(); generate_event(_ups, CMDCOMMOK); } // Exit immediately if on battery state changed if ((online ^ _ups->is_online()) || (onbatt ^ _ups->is_onbatt())) { return true; } } else { time_t now = time(NULL); if (_ups->is_commlost()) { // We already know we're commlost. // Log an event every 10 minutes. if ((now - _commlost_time) >= 10*60) { _commlost_time = now; log_event(_ups, event_msg[CMDCOMMFAILURE].level, event_msg[CMDCOMMFAILURE].msg); } } else { // Just became commlost...set commlost flag and log an event. _commlost_time = now; _ups->set_commlost(); generate_event(_ups, CMDCOMMFAILURE); _comm->Close(); } } sleep(1); } } bool ModbusUpsDriver::Open() { if (!_comm) { #ifdef HAVE_MODBUS_USB_DRIVER if (_ups->cable.type == CABLE_SMART) _comm = new ModbusRs232Comm(); else _comm = new ModbusUsbComm(); #else _comm = new ModbusRs232Comm(); #endif } _ups->fd = 1; return _comm->Open(_ups->device); } bool ModbusUpsDriver::Close() { bool ret = true; if (_comm) { ret = _comm->Close(); delete _comm; _comm = NULL; } _ups->fd = -1; return ret; } /* * Setup capabilities structure for UPS */ bool ModbusUpsDriver::get_capabilities() { for (const CiInfo *info = CI_TABLE; info->reg; info++) { uint8_t *data = _comm->ReadRegister(info->reg->addr, info->reg->nregs); if (data) { _ups->UPS_Cap[info->ci] = true; delete [] data; } } return _ups->UPS_Cap[CI_STATUS]; } const ModbusUpsDriver::CiInfo *ModbusUpsDriver::GetCiInfo(int ci) { const CiInfo *info = CI_TABLE; while (info->reg && info->ci != ci) info++; return info->reg ? info : NULL; } bool ModbusUpsDriver::UpdateCi(int ci) { const CiInfo *info = GetCiInfo(ci); return info ? UpdateCi(info) : false; } bool ModbusUpsDriver::UpdateCi(const CiInfo *info) { uint8_t *data = _comm->ReadRegister(info->reg->addr, info->reg->nregs); if (!data) { Dmsg(0, "%s: Failed reading %u/%u\n", __func__, info->reg->addr, info->reg->nregs); return false; } const unsigned int nbytes = info->reg->nregs * sizeof(uint16_t); uint64_t uint = 0; int64_t sint = 0; double dbl = 0; astring str; if (info->reg->type == DT_STRING) { // String type... for (unsigned int i = 0; i < nbytes; ++i) { // Extract from response message // Constrain to valid ASCII subset defined by APC if (data[i] < 0x20 || data[i] > 0x7E) str += ' '; else str += data[i]; } // Strip leading and trailing whitespace str.trim(); } else { // Integer type... for (unsigned int i = 0; i < nbytes; ++i) { // Extract from response message, MSB first uint = (uint << 8) | data[i]; } if (info->reg->type == DT_INT) { // Sign extend sint = uint; sint <<= (8 * (sizeof(uint) - nbytes)); sint >>= (8 * (sizeof(uint) - nbytes)); // Scale if (info->reg->scale) dbl = (double)sint / (1ULL << info->reg->scale); } else if (info->reg->scale) { // Scale dbl = (double)uint / (1ULL << info->reg->scale); } } // Done with data delete [] data; astring tmpstr; struct tm tmp; time_t date; switch (info->ci) { case CI_UPSMODEL: Dmsg(80, "Got CI_UPSMODEL: %s\n", str.str()); strlcpy(_ups->upsmodel, str, sizeof(_ups->upsmodel)); break; case CI_SERNO: Dmsg(80, "Got CI_SERNO: %s\n", str.str()); strlcpy(_ups->serial, str, sizeof(_ups->serial)); break; case CI_IDEN: Dmsg(80, "Got CI_IDEN: %s\n", str.str()); strlcpy(_ups->upsname, str, sizeof(_ups->upsname)); break; case CI_REVNO: Dmsg(80, "Got CI_REVNO: %s\n", str.str()); strlcpy(_ups->firmrev, str, sizeof(_ups->firmrev)); break; case CI_BUPSelfTest: Dmsg(80, "Got MODBUS_MAP_ID: %s\n", str.str()); tmpstr = _ups->firmrev; // Append to REVNO tmpstr += " / " + str; strlcpy(_ups->firmrev, tmpstr, sizeof(_ups->firmrev)); break; case CI_MANDAT: Dmsg(80, "Got CI_MANDAT: %llu\n", uint); // uint is in days since 1/1/2000 date = ModbusRegTotime_t(uint); gmtime_r(&date, &tmp); strftime(_ups->birth, sizeof(_ups->birth), "%Y-%m-%d", &tmp); break; case CI_BATTDAT: Dmsg(80, "Got CI_BATTDAT: %llu\n", uint); // uint is in days since 1/1/2000 date = ModbusRegTotime_t(uint); gmtime_r(&date, &tmp); strftime(_ups->battdat, sizeof(_ups->battdat), "%Y-%m-%d", &tmp); break; case CI_NOMOUTV: Dmsg(80, "Got CI_NOMOUTV: %llx\n", uint); if (uint & OVS_100VAC) _ups->NomOutputVoltage = 100; else if (uint & OVS_120VAC) _ups->NomOutputVoltage = 120; else if (uint & OVS_200VAC) _ups->NomOutputVoltage = 200; else if (uint & OVS_208VAC) _ups->NomOutputVoltage = 208; else if (uint & OVS_220VAC) _ups->NomOutputVoltage = 220; else if (uint & OVS_230VAC) _ups->NomOutputVoltage = 230; else if (uint & OVS_240VAC) _ups->NomOutputVoltage = 240; else _ups->NomOutputVoltage = -1; break; case CI_NOMPOWER: Dmsg(80, "Got CI_NOMPOWER: %llu\n", uint); _ups->NomPower = uint; break; case CI_NomApparent: Dmsg(80, "Got CI_NomApparent: %llu\n", uint); _ups->NomApparentPower = uint; break; case CI_DSHUTD: Dmsg(80, "Got CI_DSHUTD: %lld\n", sint); _ups->dshutd = sint; break; case CI_DWAKE: Dmsg(80, "Got CI_DWAKE: %lld\n", sint); _ups->dwake = sint; break; case CI_LowBattery: Dmsg(80, "Got CI_LowBattery: %llu\n", uint); _ups->set_battlow(uint & SSS_SHUTDOWN_IMMINENT); break; #if 0 case CI_STESTI: Dmsg(80, "Got CI_STESTI: %llx\n", uint); if (uint & 0x1) strlcpy(_ups->selftest, "OFF", sizeof(_ups->selftest)); else if (uint & 0x2) strlcpy(_ups->selftest, "ON", sizeof(_ups->selftest)); else if (uint & 0x14) strlcpy(_ups->selftest, "168", sizeof(_ups->selftest)); else if (uint & 0x28) strlcpy(_ups->selftest, "336", sizeof(_ups->selftest)); break; case CI_LTRANS: Dmsg(80, "Got CI_LTRANS: %llu\n", uint); _ups->lotrans = uint; break; case CI_HTRANS: Dmsg(80, "Got CI_HTRANS: %llu\n", uint); _ups->hitrans = uint; break; #endif case CI_LOAD: Dmsg(80, "Got CI_LOAD: %f\n", dbl); _ups->UPSLoad = dbl; break; case CI_LoadApparent: Dmsg(80, "Got CI_LoadApparent: %f\n", dbl); _ups->LoadApparent = dbl; break; case CI_VLINE: Dmsg(80, "Got CI_VLINE: %f\n", dbl); _ups->LineVoltage = dbl; break; case CI_VOUT: Dmsg(80, "Got CI_VOUT: %f\n", dbl); _ups->OutputVoltage = dbl; break; case CI_OutputCurrent: Dmsg(80, "Got CI_OutputCurrent: %f\n", dbl); _ups->OutputCurrent = dbl; break; case CI_VBATT: Dmsg(80, "Got CI_VBATT: %f\n", dbl); _ups->BattVoltage = dbl; break; case CI_FREQ: Dmsg(80, "Got CI_FREQ: %f\n", dbl); _ups->LineFreq = dbl; break; case CI_ITEMP: Dmsg(80, "Got CI_ITEMP: %f\n", dbl); _ups->UPSTemp = dbl; break; case CI_BATTLEV: Dmsg(80, "Got CI_BATTLEV: %f\n", dbl); _ups->BattChg = dbl; break; case CI_RUNTIM: Dmsg(80, "Got CI_RUNTIM: %llu\n", uint); _ups->TimeLeft = uint / 60; // secs to mins break; case CI_ST_STAT: Dmsg(80, "Got CI_ST_STAT: 0x%llx\n", uint); if (uint & (BTS_PENDING|BTS_IN_PROGRESS)) _ups->testresult = TEST_INPROGRESS; else if (uint & BTS_PASSED) _ups->testresult = TEST_PASSED; else if (uint & BTS_FAILED) _ups->testresult = TEST_FAILED; else if (uint == 0) _ups->testresult = TEST_NONE; else _ups->testresult = TEST_UNKNOWN; break; case CI_WHY_BATT: Dmsg(80, "Got CI_WHY_BATT: %llx\n", uint); // Only update if we're on battery now if (_ups->is_onbatt()) { switch(uint) { case USCC_HIGH_INPUT_VOLTAGE: _ups->lastxfer = XFER_OVERVOLT; break; case USCC_LOW_INPUT_VOLTAGE: _ups->lastxfer = XFER_UNDERVOLT; break; case USCC_DISTORTED_INPUT: _ups->lastxfer = XFER_NOTCHSPIKE; break; case USCC_RAPID_CHANGE: _ups->lastxfer = XFER_RIPPLE; break; case USCC_HIGH_INPUT_FREQ: case USCC_LOW_INPUT_FREQ: case USCC_FREQ_PHASE_DIFF: _ups->lastxfer = XFER_FREQ; break; case USCC_AUTOMATIC_TEST: _ups->lastxfer = XFER_SELFTEST; break; case USCC_LOCAL_UI_CMD: case USCC_PROTOCOL_CMD: _ups->lastxfer = XFER_FORCED; break; default: _ups->lastxfer = XFER_UNKNOWN; break; } } break; case CI_STATUS: Dmsg(80, "Got CI_STATUS: 0x%llx\n", uint); // Clear the following flags: only one status will be TRUE _ups->clear_online(); _ups->clear_onbatt(); if (uint & US_ONLINE) _ups->set_online(); else if (uint & US_ONBATTERY) _ups->set_onbatt(); break; case CI_Calibration: Dmsg(80, "Got CI_Calibration: 0x%llx\n", uint); _ups->set_calibration(uint & (CS_PENDING|CS_IN_PROGRESS)); break; case CI_Overload: Dmsg(80, "Got CI_Overload: 0x%llx\n", uint); _ups->set_overload(uint & PSE_OUTPUT_OVERLOAD); break; case CI_NeedReplacement: Dmsg(80, "Got CI_NeedReplacement: 0x%llx\n", uint); _ups->set_replacebatt(uint & BSE_NEEDS_REPLACEMENT); break; case CI_BatteryPresent: Dmsg(80, "Got CI_BatteryPresent: 0x%llx\n", uint); _ups->set_battpresent(!(uint & BSE_DISCONNECTED)); break; case CI_Boost: Dmsg(80, "Got CI_Boost: 0x%llx\n", uint); _ups->set_boost(uint & IS_BOOST); break; case CI_Trim: Dmsg(80, "Got CI_Trim: 0x%llx\n", uint); _ups->set_trim(uint & IS_TRIM); break; } return true; } bool ModbusUpsDriver::UpdateCis(bool dynamic) { for (unsigned int i = 0; CI_TABLE[i].ci != -1; i++) { if (_ups->UPS_Cap[CI_TABLE[i].ci] && CI_TABLE[i].dynamic == dynamic) { if (!UpdateCi(CI_TABLE+i)) return false; } } return true; } /* * Read UPS info that remains unchanged -- e.g. transfer * voltages, shutdown delay, ... * * This routine is called once when apcupsd is starting */ bool ModbusUpsDriver::read_static_data() { write_lock(_ups); bool ret = UpdateCis(false); write_unlock(_ups); return ret; } /* * Read UPS info that changes -- e.g. Voltage, temperature, ... * * This routine is called once every N seconds to get * a current idea of what the UPS is doing. */ bool ModbusUpsDriver::read_volatile_data() { write_lock(_ups); bool ret = UpdateCis(true); if (ret) { // Successful query, update timestamp _ups->poll_time = time(NULL); } write_unlock(_ups); return ret; } bool ModbusUpsDriver::kill_power() { return write_int_to_ups(REG_SIMPLE_SIGNALLING_CMD, SSC_REQUEST_SHUTDOWN); } bool ModbusUpsDriver::shutdown() { return write_int_to_ups(REG_SIMPLE_SIGNALLING_CMD, SSC_REMOTE_OFF); } bool ModbusUpsDriver::entry_point(int command, void *data) { switch (command) { case DEVICE_CMD_CHECK_SELFTEST: Dmsg(80, "Checking self test.\n"); /* Reason for last transfer to batteries */ if (_ups->UPS_Cap[CI_WHY_BATT] && UpdateCis(true)) { Dmsg(80, "Transfer reason: %d\n", _ups->lastxfer); /* See if this is a self test rather than power failure */ if (_ups->lastxfer == XFER_SELFTEST) { /* * set Self Test start time */ _ups->SelfTest = time(NULL); Dmsg(80, "Self Test time: %s", ctime(&_ups->SelfTest)); } } break; case DEVICE_CMD_GET_SELFTEST_MSG: default: return false; } return true; } bool ModbusUpsDriver::write_string_to_ups(const APCModbusMapping::RegInfo ®, const char *str) { if (reg.type != DT_STRING) return false; int len = reg.nregs * sizeof(uint16_t); astring strcpy = str; if (strcpy.len() > len) { // Truncate strcpy = strcpy.substr(0, len); } else { // Pad while (strcpy.len() < len) strcpy += ' '; } return _comm->WriteRegister(reg.addr, reg.nregs, (const uint8_t*)strcpy.str()); } bool ModbusUpsDriver::write_int_to_ups(const APCModbusMapping::RegInfo ®, uint64_t val) { if (reg.type != DT_UINT && reg.type != DT_INT) return false; unsigned int len = reg.nregs * sizeof(uint16_t); uint8_t data[len]; for (unsigned int i = 0; i < len; ++i) data[i] = val >> (8*(len-i-1)); return _comm->WriteRegister(reg.addr, reg.nregs, data); } bool ModbusUpsDriver::read_string_from_ups(const APCModbusMapping::RegInfo ®, astring *val) { if (reg.type != DT_STRING) return false; unsigned int len = reg.nregs * sizeof(uint16_t); uint8_t *data = _comm->ReadRegister(reg.addr, reg.nregs); if (!data) return false; *val = ""; for (unsigned int i = 0; i < len; ++i) { // Extract from response message // Constrain to valid ASCII subset defined by APC if (data[i] < 0x20 || data[i] > 0x7E) *val += ' '; else *val += data[i]; } delete [] data; // Strip leading and trailing whitespace val->trim(); return true; } bool ModbusUpsDriver::read_int_from_ups(const APCModbusMapping::RegInfo ®, uint64_t *val) { if (reg.type != DT_UINT && reg.type != DT_INT) return false; unsigned int len = reg.nregs * sizeof(uint16_t); uint8_t *data = _comm->ReadRegister(reg.addr, reg.nregs); if (!data) return false; *val = 0; for (unsigned int i = 0; i < len; ++i) *val = (*val << 8) | data[i]; delete [] data; return true; } bool ModbusUpsDriver::read_dbl_from_ups(const APCModbusMapping::RegInfo ®, double *val) { if (reg.type != DT_UINT && reg.type != DT_INT) return false; // Read raw unscaled value from UPS uint64_t uint; if (!read_int_from_ups(reg, &uint)) return false; // Scale if (reg.type == DT_INT) { // Sign extend int64_t sint = uint; unsigned int nbytes = reg.nregs * sizeof(uint16_t); sint <<= (8 * (sizeof(uint) - nbytes)); sint >>= (8 * (sizeof(uint) - nbytes)); *val = (double)sint / (1ULL << reg.scale); } else { *val = (double)uint / (1ULL << reg.scale); } return true; } apcupsd-3.14.14/src/drivers/modbus/modbus.h000066400000000000000000000053371274230402600205330ustar00rootroot00000000000000/* * modbus.h * * Public header file for the modbus driver. */ /* * Copyright (C) 2013 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * Thanks go to APC/Schneider for providing the Apcupsd team with early access * to MODBUS protocol information to facilitate an Apcupsd driver. * * APC/Schneider has published the following relevant application notes: * * AN176: Modbus Implementation in APC Smart-UPS * * AN177: Software interface for Switched Outlet and UPS Management in Smart-UPS * * AN178: USB HID Implementation in Smart-UPS * */ #ifndef _MODBUS_H #define _MODBUS_H #include #include "mapping.h" class astring; class ModbusComm; class ModbusUpsDriver: public UpsDriver { public: ModbusUpsDriver(UPSINFO *ups); virtual ~ModbusUpsDriver() {} static UpsDriver *Factory(UPSINFO *ups) { return new ModbusUpsDriver(ups); } virtual bool get_capabilities(); virtual bool read_volatile_data(); virtual bool read_static_data(); virtual bool kill_power(); virtual bool shutdown(); virtual bool check_state(); virtual bool Open(); virtual bool Close(); virtual bool entry_point(int command, void *data); bool write_string_to_ups(const APCModbusMapping::RegInfo ®, const char *str); bool write_int_to_ups(const APCModbusMapping::RegInfo ®, uint64_t val); bool write_dbl_to_ups(const APCModbusMapping::RegInfo ®, double val); bool read_string_from_ups(const APCModbusMapping::RegInfo ®, astring *val); bool read_int_from_ups(const APCModbusMapping::RegInfo ®, uint64_t *val); bool read_dbl_from_ups(const APCModbusMapping::RegInfo ®, double *val); private: struct CiInfo { int ci; bool dynamic; const APCModbusMapping::RegInfo *reg; }; static const CiInfo CI_TABLE[]; const CiInfo *GetCiInfo(int ci); bool UpdateCis(bool dynamic); bool UpdateCi(const CiInfo *info); bool UpdateCi(int ci); time_t _commlost_time; ModbusComm *_comm; }; #endif /* _MODBUS_H */ apcupsd-3.14.14/src/drivers/net/000077500000000000000000000000001274230402600163565ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/net/Makefile000066400000000000000000000002651274230402600200210ustar00rootroot00000000000000topdir:=../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) all-targets: libnetdrv.a libnetdrv.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/net/net.c000066400000000000000000000441131274230402600173130ustar00rootroot00000000000000/* * net.c * * Network client driver. */ /* * Copyright (C) 2001-2006 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "net.h" /* * List of variables that can be read by getupsvar(). * First field is that name given to getupsvar(), * Second field is our internal name as produced by the STATUS * output from apcupsd. * Third field, if 0 returns everything to the end of the * line, and if 1 returns only to first space (e.g. integers, * and floating point values. */ const NetUpsDriver::CmdTrans NetUpsDriver::cmdtrans[] = { {"battcap", "BCHARGE", 1}, {"battdate", "BATTDATE", 1}, {"battpct", "BCHARGE", 1}, {"battvolt", "BATTV", 1}, {"cable", "CABLE", 0}, {"date", "DATE", 0}, {"firmware", "FIRMWARE", 0}, {"highxfer", "HITRANS", 1}, {"hostname", "HOSTNAME", 1}, {"laststest", "LASTSTEST",0}, {"lastxfer", "LASTXFER", 0}, /* reason for last xfer to batteries */ {"linemax", "MAXLINEV", 1}, {"linemin", "MINLINEV", 1}, {"loadpct", "LOADPCT", 1}, {"lowbatt", "DLOWBATT", 1}, /* low battery power off delay */ {"lowxfer", "LOTRANS", 1}, {"maxtime", "MAXTIME", 1}, {"mbattchg", "MBATTCHG", 1}, {"mintimel", "MINTIMEL", 1}, {"model", "MODEL", 0}, {"nombattv", "NOMBATTV", 1}, {"nominv", "NOMINV", 1}, {"nomoutv", "NOMOUTV", 1}, {"nompower", "NOMPOWER", 1}, {"outputfreq", "LINEFREQ", 1}, {"outputv", "OUTPUTV", 1}, {"version", "VERSION", 1}, {"retpct", "RETPCT", 1}, /* min batt to turn on UPS */ {"runtime", "TIMELEFT", 1}, {"selftest", "SELFTEST", 1}, /* results of last self test */ {"sense", "SENSE", 1}, {"serialno", "SERIALNO", 1}, {"status", "STATFLAG", 1}, {"transhi", "HITRANS", 1}, {"translo", "LOTRANS", 1}, {"upsload", "LOADPCT", 1}, {"upsmode", "UPSMODE", 0}, {"upsname", "UPSNAME", 1}, {"upstemp", "ITEMP", 1}, {"utility", "LINEV", 1}, {NULL, NULL} }; /* Convert UPS response to enum */ SelfTestResult NetUpsDriver::decode_testresult(char* str) { if (!strncmp(str, "OK", 2)) return TEST_PASSED; else if (!strncmp(str, "NO", 2)) return TEST_NONE; else if (!strncmp(str, "BT", 2)) return TEST_FAILCAP; else if (!strncmp(str, "NG", 2)) return TEST_FAILED; else if (!strncmp(str, "WN", 2)) return TEST_WARNING; else if (!strncmp(str, "IP", 2)) return TEST_INPROGRESS; else return TEST_UNKNOWN; } /* Convert UPS response to enum */ LastXferCause NetUpsDriver::decode_lastxfer(char *str) { Dmsg(80, "Transfer reason: %s\n", str); if (!strcmp(str, "No transfers since turnon")) return XFER_NONE; else if (!strcmp(str, "Automatic or explicit self test")) return XFER_SELFTEST; else if (!strcmp(str, "Forced by software")) return XFER_FORCED; else if (!strcmp(str, "Low line voltage")) return XFER_UNDERVOLT; else if (!strcmp(str, "High line voltage")) return XFER_OVERVOLT; else if (!strcmp(str, "Line voltage notch or spike")) return XFER_NOTCHSPIKE; else if (!strcmp(str, "Unacceptable line voltage changes")) return XFER_RIPPLE; else if (!strcmp(str, "Input frequency out of range")) return XFER_FREQ; else return XFER_UNKNOWN; } NetUpsDriver::NetUpsDriver(UPSINFO *ups) : UpsDriver(ups), _hostname(NULL), _port(0), _sockfd(INVALID_SOCKET), _got_caps(false), _got_static_data(false), _last_fill_time(0), _statlen(0), _tlog(0), _comm_err(false), _comm_loss(0) { memset(_device, 0, sizeof(_device)); memset(_statbuf, 0, sizeof(_statbuf)); } /* * Returns 1 if var found * answer has var * Returns 0 if variable name not found * answer has "Not found" is variable name not found * answer may have "N/A" if the UPS does not support this * feature * Returns -1 if network problem * answer has "N/A" if host is not available or network error */ bool NetUpsDriver::getupsvar(const char *request, char *answer, int anslen) { int i; const char *stat_match = NULL; char *find; int nfields = 0; char format[21]; for (i = 0; cmdtrans[i].request; i++) { if (!(strcmp(cmdtrans[i].request, request))) { stat_match = cmdtrans[i].upskeyword; nfields = cmdtrans[i].nfields; } } if (stat_match) { if ((find = strstr(_statbuf, stat_match)) != NULL) { if (nfields == 1) { /* get one field */ asnprintf(format, sizeof(format), "%%*s %%*s %%%ds", anslen); sscanf(find, format, answer); } else { /* get everything to eol */ i = 0; find += 11; /* skip label */ while (*find != '\n' && i < anslen - 1) answer[i++] = *find++; answer[i] = 0; } if (strcmp(answer, "N/A") == 0) { return 0; } Dmsg(100, "Return 1 for getupsvar %s %s\n", request, answer); return true; } } else { Dmsg(100, "Hey!!! No match in getupsvar for %s!\n", request); } strlcpy(answer, "Not found", anslen); return false; } bool NetUpsDriver::poll_ups() { int n, stat = 1; char buf[1000]; _statbuf[0] = 0; _statlen = 0; Dmsg(20, "Opening connection to %s:%d\n", _hostname, _port); if ((_sockfd = net_open(_hostname, NULL, _port)) < 0) { Dmsg(90, "Exit poll_ups 0 comm lost: %s\n", strerror(-_sockfd)); if (!_ups->is_commlost()) { _ups->set_commlost(); } return false; } if ((n = net_send(_sockfd, "status", 6)) != 6) { net_close(_sockfd); Dmsg(90, "Exit poll_ups 0 net_send fails: %s\n", strerror(-n)); _ups->set_commlost(); return false; } Dmsg(99, "===============\n"); while ((n = net_recv(_sockfd, buf, sizeof(buf) - 1)) > 0) { buf[n] = 0; strlcat(_statbuf, buf, sizeof(_statbuf)); Dmsg(99, "Partial buf (%d, %d):\n%s", n, strlen(_statbuf), buf); } Dmsg(99, "===============\n"); if (n < 0) { stat = 0; Dmsg(90, "Exit poll_ups 0 bad stat net_recv: %s\n", strerror(-n)); _ups->set_commlost(); } else { _ups->clear_commlost(); } net_close(_sockfd); Dmsg(99, "Buffer:\n%s\n", _statbuf); _statlen = strlen(_statbuf); Dmsg(90, "Exit poll_ups, stat=%d\n", stat); return stat; } /* * Fill buffer with data from UPS network daemon * Returns false on error * Returns true if OK */ #define SLEEP_TIME 2 bool NetUpsDriver::fill_status_buffer() { time_t now; /* Poll or fill the buffer maximum one time per second */ now = time(NULL); if ((now - _last_fill_time) < 2) { Dmsg(90, "Exit fill_status_buffer OK less than 2 sec\n"); return true; } if (!poll_ups()) { /* generate event once */ if (!_comm_err) { execute_command(_ups, ups_event[CMDCOMMFAILURE]); _comm_err = true; } /* log every 10 minutes */ if (now - _tlog >= 10 * 60) { _tlog = now; log_event(_ups, event_msg[CMDCOMMFAILURE].level, event_msg[CMDCOMMFAILURE].msg); } } else { if (_comm_err) { generate_event(_ups, CMDCOMMOK); _tlog = 0; _comm_err = false; } _last_fill_time = now; if (!_got_caps) get_capabilities(); if (_got_caps && !_got_static_data) read_static_data(); } return !_comm_err; } bool NetUpsDriver::get_ups_status_flag(int fill) { char answer[200]; int stat = 1; int32_t newStatus; /* this really should be uint32_t! */ int32_t masterStatus; /* status from master */ if (!_got_caps) { get_capabilities(); if (!_got_caps) return false; } if (!_got_static_data) { read_static_data(); if (!_got_static_data) return false; } if (fill) { /* * Not locked because no one else should be writing in the * status buffer, and we don't want to lock across I/O * operations. */ stat = fill_status_buffer(); } write_lock(_ups); answer[0] = 0; if (!getupsvar("status", answer, sizeof(answer))) { Dmsg(100, "HEY!!! Couldn't get status flag.\n"); stat = 0; masterStatus = 0; } else { /* * Make sure we don't override local bits, and that * all non-local bits are set/cleared correctly. * * local bits = UPS_commlost|UPS_shutdown|UPS_slave|UPS_slavedown| * UPS_prev_onbatt|UPS_prev_battlow|UPS_onbatt_msg| * UPS_fastpoll|UPS_plugged|UPS_dev_setup */ /* First transfer set or not set all non-local bits */ masterStatus = strtol(answer, NULL, 0); newStatus = masterStatus & ~UPS_LOCAL_BITS; /* clear local bits */ _ups->Status &= UPS_LOCAL_BITS; /* clear non-local bits */ _ups->Status |= newStatus; /* set new non-local bits */ /* * Now set any special bits, note this is set only, we do * not clear these bits, but let our own core code clear them */ newStatus = masterStatus & (UPS_commlost | UPS_fastpoll); _ups->Status |= newStatus; } Dmsg(100, "Got Status = %s 0x%x\n", answer, _ups->Status); if (masterStatus & UPS_shutdown && !_ups->is_shut_remote()) { _ups->set_shut_remote(); /* if master is shutting down so do we */ log_event(_ups, LOG_ERR, "Shutdown because NIS master is shutting down."); Dmsg(100, "Set SHUT_REMOTE because of master status.\n"); } /* * If we lost connection with master and we * are running on batteries, shutdown on the fourth * consequtive pass here. While on batteries, this code * is called once per second. */ if (stat == 0 && _ups->is_onbatt()) { if (_comm_loss++ == 4 && !_ups->is_shut_remote()) { _ups->set_shut_remote(); log_event(_ups, LOG_ERR, "Shutdown because loss of comm with NIS master while on batteries."); Dmsg(100, "Set SHUT_REMOTE because of loss of comm on batteries.\n"); } } else { _comm_loss = 0; } write_unlock(_ups); return stat; } bool NetUpsDriver::Open() { strlcpy(_device, _ups->device, sizeof(_device)); strlcpy(_ups->master_name, _ups->device, sizeof(_ups->master_name)); strlcpy(_ups->upsclass.long_name, "Net Slave", sizeof(_ups->upsclass.long_name)); /* Now split the device. */ _hostname = _device; char *cp = strchr(_device, ':'); if (cp) { *cp = '\0'; cp++; _port = atoi(cp); } else { /* use NIS port as default */ _port = _ups->statusport; } _statbuf[0] = 0; _statlen = 0; /* Fake core code. Will go away when _ups->fd is cleaned up. */ _ups->fd = 1; return true; } bool NetUpsDriver::Close() { /* Fake core code. Will go away when _ups->fd will be cleaned up. */ _ups->fd = -1; return true; } bool NetUpsDriver::get_capabilities() { char answer[200]; write_lock(_ups); if (poll_ups()) { _ups->UPS_Cap[CI_VLINE] = getupsvar("utility", answer, sizeof(answer)); _ups->UPS_Cap[CI_LOAD] = getupsvar("loadpct", answer, sizeof(answer)); _ups->UPS_Cap[CI_BATTLEV] = getupsvar("battcap", answer, sizeof(answer)); _ups->UPS_Cap[CI_RUNTIM] = getupsvar("runtime", answer, sizeof(answer)); _ups->UPS_Cap[CI_VMAX] = getupsvar("linemax", answer, sizeof(answer)); _ups->UPS_Cap[CI_VMIN] = getupsvar("linemin", answer, sizeof(answer)); _ups->UPS_Cap[CI_VOUT] = getupsvar("outputv", answer, sizeof(answer)); _ups->UPS_Cap[CI_SENS] = getupsvar("sense", answer, sizeof(answer)); _ups->UPS_Cap[CI_DLBATT] = getupsvar("lowbatt", answer, sizeof(answer)); _ups->UPS_Cap[CI_LTRANS] = getupsvar("lowxfer", answer, sizeof(answer)); _ups->UPS_Cap[CI_HTRANS] = getupsvar("highxfer", answer, sizeof(answer)); _ups->UPS_Cap[CI_RETPCT] = getupsvar("retpct", answer, sizeof(answer)); _ups->UPS_Cap[CI_ITEMP] = getupsvar("upstemp", answer, sizeof(answer)); _ups->UPS_Cap[CI_VBATT] = getupsvar("battvolt", answer, sizeof(answer)); _ups->UPS_Cap[CI_FREQ] = getupsvar("outputfreq", answer, sizeof(answer)); _ups->UPS_Cap[CI_WHY_BATT] = getupsvar("lastxfer", answer, sizeof(answer)); _ups->UPS_Cap[CI_ST_STAT] = getupsvar("selftest", answer, sizeof(answer)); _ups->UPS_Cap[CI_SERNO] = getupsvar("serialno", answer, sizeof(answer)); _ups->UPS_Cap[CI_BATTDAT] = getupsvar("battdate", answer, sizeof(answer)); _ups->UPS_Cap[CI_NOMBATTV] = getupsvar("nombattv", answer, sizeof(answer)); _ups->UPS_Cap[CI_NOMINV] = getupsvar("nominv", answer, sizeof(answer)); _ups->UPS_Cap[CI_NOMOUTV] = getupsvar("nomoutv", answer, sizeof(answer)); _ups->UPS_Cap[CI_NOMPOWER] = getupsvar("nompower", answer, sizeof(answer)); _ups->UPS_Cap[CI_REVNO] = getupsvar("firmware", answer, sizeof(answer)); _ups->UPS_Cap[CI_UPSMODEL] = getupsvar("model", answer, sizeof(answer)); _got_caps = true; } else { _got_caps = false; } write_unlock(_ups); return true; } bool NetUpsDriver::check_state() { int sleep_time; sleep_time = _ups->wait_time; Dmsg(100, "Sleep %d secs.\n", sleep_time); sleep(sleep_time); get_ups_status_flag(1); return true; } #define GETVAR(ci,str) \ (_ups->UPS_Cap[ci] && getupsvar(str, answer, sizeof(answer))) bool NetUpsDriver::read_volatile_data() { char answer[200]; if (!fill_status_buffer()) return 0; write_lock(_ups); _ups->set_slave(); /* ***FIXME**** poll time needs to be scanned */ _ups->poll_time = time(NULL); _ups->last_master_connect_time = _ups->poll_time; if (GETVAR(CI_VLINE, "utility")) _ups->LineVoltage = atof(answer); if (GETVAR(CI_LOAD, "loadpct")) _ups->UPSLoad = atof(answer); if (GETVAR(CI_BATTLEV, "battcap")) _ups->BattChg = atof(answer); if (GETVAR(CI_RUNTIM, "runtime")) _ups->TimeLeft = atof(answer); if (GETVAR(CI_VMAX, "linemax")) _ups->LineMax = atof(answer); if (GETVAR(CI_VMIN, "linemin")) _ups->LineMin = atof(answer); if (GETVAR(CI_VOUT, "outputv")) _ups->OutputVoltage = atof(answer); if (GETVAR(CI_SENS, "sense")) _ups->sensitivity[0] = answer[0]; if (GETVAR(CI_DLBATT, "lowbatt")) _ups->dlowbatt = (int)atof(answer); if (GETVAR(CI_LTRANS, "lowxfer")) _ups->lotrans = (int)atof(answer); if (GETVAR(CI_HTRANS, "highxfer")) _ups->hitrans = (int)atof(answer); if (GETVAR(CI_RETPCT, "retpct")) _ups->rtnpct = (int)atof(answer); if (GETVAR(CI_ITEMP, "upstemp")) _ups->UPSTemp = atof(answer); if (GETVAR(CI_VBATT, "battvolt")) _ups->BattVoltage = atof(answer); if (GETVAR(CI_FREQ, "outputfreq")) _ups->LineFreq = atof(answer); if (GETVAR(CI_WHY_BATT, "lastxfer")) _ups->lastxfer = decode_lastxfer(answer); if (GETVAR(CI_ST_STAT, "selftest")) _ups->testresult = decode_testresult(answer); write_unlock(_ups); get_ups_status_flag(0); return true; } bool NetUpsDriver::read_static_data() { char answer[200]; write_lock(_ups); if (poll_ups()) { if (!getupsvar( "upsname", _ups->upsname, sizeof(_ups->upsname))) { log_event(_ups, LOG_ERR, "getupsvar: failed for \"upsname\"."); } if (!getupsvar( "model", _ups->upsmodel, sizeof(_ups->upsmodel))) { log_event(_ups, LOG_ERR, "getupsvar: failed for \"model\"."); } if (!getupsvar( "upsmode", _ups->upsclass.long_name, sizeof(_ups->upsclass.long_name))) { log_event(_ups, LOG_ERR, "getupsvar: failed for \"upsmode\"."); } if (GETVAR(CI_SERNO, "serialno")) strlcpy(_ups->serial, answer, sizeof(_ups->serial)); if (GETVAR(CI_BATTDAT, "battdate")) strlcpy(_ups->battdat, answer, sizeof(_ups->battdat)); if (GETVAR(CI_NOMBATTV, "nombattv")) _ups->nombattv = atof(answer); if (GETVAR(CI_NOMINV, "nominv")) _ups->NomInputVoltage = (int)atof(answer); if (GETVAR(CI_NOMOUTV, "nomoutv")) _ups->NomOutputVoltage = (int)atof(answer); if (GETVAR(CI_NOMPOWER, "nompower")) _ups->NomPower = (int)atof(answer); if (GETVAR(CI_REVNO, "firmware")) strlcpy(_ups->firmrev, answer, sizeof(_ups->firmrev)); _got_static_data = true; } else { _got_static_data = false; } write_unlock(_ups); return true; } bool NetUpsDriver::entry_point(int command, void *data) { char answer[200]; switch (command) { case DEVICE_CMD_CHECK_SELFTEST: Dmsg(80, "Checking self test.\n"); /* * XXX FIXME * * One day we will do this test inside the driver and not as an * entry point. */ /* Reason for last transfer to batteries */ if (GETVAR(CI_WHY_BATT, "lastxfer")) { _ups->lastxfer = decode_lastxfer(answer); Dmsg(80, "Transfer reason: %d\n", _ups->lastxfer); /* See if this is a self test rather than power false */ if (_ups->lastxfer == XFER_SELFTEST) { /* * set Self Test start time */ _ups->SelfTest = time(NULL); Dmsg(80, "Self Test time: %s", ctime(&_ups->SelfTest)); } } break; case DEVICE_CMD_GET_SELFTEST_MSG: if (!GETVAR(CI_ST_STAT, "selftest")) return false; _ups->testresult = decode_testresult(answer); break; default: return false; } return true; } apcupsd-3.14.14/src/drivers/net/net.h000066400000000000000000000036501274230402600173210ustar00rootroot00000000000000/* * net.h * * Public header file for the net client driver. */ /* * Copyright (C) 2000-2006 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _NET_H #define _NET_H #define BIGBUF 4096 class NetUpsDriver: public UpsDriver { public: NetUpsDriver(UPSINFO *ups); virtual ~NetUpsDriver() {} static UpsDriver *Factory(UPSINFO *ups) { return new NetUpsDriver(ups); } virtual bool get_capabilities(); virtual bool read_volatile_data(); virtual bool read_static_data(); virtual bool check_state(); virtual bool Open(); virtual bool Close(); virtual bool entry_point(int command, void *data); private: bool getupsvar(const char *request, char *answer, int anslen); bool poll_ups(); bool fill_status_buffer(); bool get_ups_status_flag(int fill); static SelfTestResult decode_testresult(char* str); static LastXferCause decode_lastxfer(char *str); struct CmdTrans { const char *request; const char *upskeyword; int nfields; }; static const CmdTrans cmdtrans[]; char _device[MAXSTRING]; char *_hostname; int _port; sock_t _sockfd; bool _got_caps; bool _got_static_data; time_t _last_fill_time; char _statbuf[BIGBUF]; int _statlen; time_t _tlog; bool _comm_err; int _comm_loss; }; #endif /* _NET_H */ apcupsd-3.14.14/src/drivers/pcnet/000077500000000000000000000000001274230402600167015ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/pcnet/Makefile000066400000000000000000000002711274230402600203410ustar00rootroot00000000000000topdir:=../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) all-targets: libpcnetdrv.a libpcnetdrv.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/pcnet/packets/000077500000000000000000000000001274230402600203335ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/pcnet/packets/README000066400000000000000000000003171274230402600212140ustar00rootroot00000000000000Recorded packets for testing PCNET driver. Authentication info: username="apc" password="0123456789ABCDEF0123456789" Packets can be send to apcupsd using netcat: cat packet0.dat | nc -u localhost 3052 apcupsd-3.14.14/src/drivers/pcnet/packets/packet0.dat000066400000000000000000000007201274230402600223530ustar00rootroot00000000000000MACONFIG MV=v1.7.0 PC=172.26.0.45 DT=07/21/2006 TM=15:47:02 SR=09 SU=1BE33E RD=7ADB TA=172.26.0.47 PT=3052 CL=AC1A0021 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 CL=00 MD=65e3ad185e17237ca9c9c282d3a7adfc apcupsd-3.14.14/src/drivers/pcnet/packets/packet1.dat000066400000000000000000000007471274230402600223650ustar00rootroot00000000000000MASTATUS MV=v1.7.0 PC=172.26.0.45 DT=07/21/2006 TM=15:47:27 SR=09 SU=1BED3F RD=3161 TA=172.26.0.47 UC=1 SD=0 SM=2 4F=116.6 51=08 7E=00 3E=000 4C=116.6 50=038.3 43=028.8 78=03/31/06 6A=0031: 47=T 56=FWD 63=UPS03R 66=090.0 58=NO 67=024 39=FF 27=00 38=00 6E=AS0614132629 6D=03/31/06 62=617.3.D 01=Smart-UPS 1500 RM 42=27.27 46=60.00 4D=118.0 4E=115.9 45=336 75=127 6C=106 65=00 6F=120 73=H 71=02 6B=0 70=090 72=000 05=00000000 MC=0 I0=0 MD=97913cc4d03f6e42735ae35d25411bfb apcupsd-3.14.14/src/drivers/pcnet/packets/packet2.dat000066400000000000000000000007471274230402600223660ustar00rootroot00000000000000MASTATUS MV=v1.7.0 PC=172.26.0.45 DT=07/21/2006 TM=15:47:53 SR=09 SU=1BF738 RD=A193 TA=172.26.0.47 UC=1 SD=0 SM=2 4F=116.6 51=08 7E=00 3E=000 4C=116.6 50=037.7 43=028.8 78=03/31/06 6A=0031: 47=T 56=FWD 63=UPS03R 66=090.0 58=NO 67=024 39=FF 27=00 38=00 6E=AS0614132629 6D=03/31/06 62=617.3.D 01=Smart-UPS 1500 RM 42=27.27 46=60.00 4D=118.0 4E=115.9 45=336 75=127 6C=106 65=00 6F=120 73=H 71=02 6B=0 70=090 72=000 05=00000000 MC=0 I0=0 MD=0b2c1efb42a257a4fbb3510110c39c68 apcupsd-3.14.14/src/drivers/pcnet/pcnet.c000066400000000000000000000617101274230402600201630ustar00rootroot00000000000000/* * pcnet.c * * Driver for PowerChute Network Shutdown protocol. */ /* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "pcnet.h" #include #include /* UPS broadcasts status packets to UDP port 3052 */ #define PCNET_DEFAULT_PORT 3052 /* * Number of seconds with no data before we declare COMMLOST. * UPS should report in every 25 seconds. We allow 2 missing * reports plus a fudge factor. */ #define COMMLOST_TIMEOUT 55 /* Win32 needs a special close for sockets */ #ifdef HAVE_MINGW #define close(fd) closesocket(fd) #endif /* Convert UPS response to enum and string */ SelfTestResult PcnetUpsDriver::decode_testresult(const char* str) { /* * Responses are: * "OK" - good battery, * "BT" - failed due to insufficient capacity, * "NG" - failed due to overload, * "NO" - no results available (no test performed in last 5 minutes) */ if (str[0] == 'O' && str[1] == 'K') return TEST_PASSED; else if (str[0] == 'B' && str[1] == 'T') return TEST_FAILCAP; else if (str[0] == 'N' && str[1] == 'G') return TEST_FAILLOAD; return TEST_NONE; } /* Convert UPS response to enum and string */ LastXferCause PcnetUpsDriver::decode_lastxfer(const char *str) { Dmsg(80, "Transfer reason: %c\n", *str); switch (*str) { case 'N': return XFER_NA; case 'R': return XFER_RIPPLE; case 'H': return XFER_OVERVOLT; case 'L': return XFER_UNDERVOLT; case 'T': return XFER_NOTCHSPIKE; case 'O': return XFER_NONE; case 'K': return XFER_FORCED; case 'S': return XFER_SELFTEST; default: return XFER_UNKNOWN; } } PcnetUpsDriver::PcnetUpsDriver(UPSINFO *ups) : UpsDriver(ups), _ipaddr(NULL), _user(NULL), _pass(NULL), _auth(false), _uptime(0), _reboots(0), _datatime(0), _runtimeInSeconds(false), _fd(INVALID_SOCKET) { memset(_device, 0, sizeof(_device)); } bool PcnetUpsDriver::pcnet_process_data(const char *key, const char *value) { unsigned long cmd; int ci; bool ret; double tmp; /* Make sure we have a value */ if (*value == '\0') return false; /* Detect remote shutdown command */ if (strcmp(key, "SD") == 0) { cmd = strtoul(value, NULL, 10); switch (cmd) { case 0: Dmsg(80, "SD: The UPS is NOT shutting down\n"); _ups->clear_shut_remote(); break; case 1: Dmsg(80, "SD: The UPS is shutting down\n"); _ups->set_shut_remote(); break; default: Dmsg(80, "Unrecognized SD value %s!\n", value); break; } return true; } /* Key must be 2 hex digits */ if (!isxdigit(key[0]) || !isxdigit(key[1])) return false; /* Convert command to CI */ cmd = strtoul(key, NULL, 16); for (ci=0; ciUPS_Cmd[ci] == cmd) break; /* No match? */ if (ci == CI_MAXCI) return false; /* Mark this CI as available */ _ups->UPS_Cap[ci] = true; /* Handle the data */ ret = true; switch (ci) { /* * VOLATILE DATA */ case CI_STATUS: Dmsg(80, "Got CI_STATUS: %s\n", value); _ups->Status &= ~0xFF; /* clear APC byte */ _ups->Status |= strtoul(value, NULL, 16) & 0xFF; /* set APC byte */ break; case CI_LQUAL: Dmsg(80, "Got CI_LQUAL: %s\n", value); strlcpy(_ups->linequal, value, sizeof(_ups->linequal)); break; case CI_WHY_BATT: Dmsg(80, "Got CI_WHY_BATT: %s\n", value); _ups->lastxfer = decode_lastxfer(value); break; case CI_ST_STAT: Dmsg(80, "Got CI_ST_STAT: %s\n", value); _ups->testresult = decode_testresult(value); break; case CI_VLINE: Dmsg(80, "Got CI_VLINE: %s\n", value); _ups->LineVoltage = atof(value); break; case CI_VMIN: Dmsg(80, "Got CI_VMIN: %s\n", value); _ups->LineMin = atof(value); break; case CI_VMAX: Dmsg(80, "Got CI_VMAX: %s\n", value); _ups->LineMax = atof(value); break; case CI_VOUT: Dmsg(80, "Got CI_VOUT: %s\n", value); _ups->OutputVoltage = atof(value); break; case CI_BATTLEV: Dmsg(80, "Got CI_BATTLEV: %s\n", value); _ups->BattChg = atof(value); break; case CI_VBATT: Dmsg(80, "Got CI_VBATT: %s\n", value); _ups->BattVoltage = atof(value); break; case CI_LOAD: Dmsg(80, "Got CI_LOAD: %s\n", value); _ups->UPSLoad = atof(value); break; case CI_FREQ: Dmsg(80, "Got CI_FREQ: %s\n", value); _ups->LineFreq = atof(value); break; case CI_RUNTIM: Dmsg(80, "Got CI_RUNTIM: %s\n", value); tmp = atof(value); _ups->TimeLeft = _runtimeInSeconds ? tmp/60 : tmp; break; case CI_ITEMP: Dmsg(80, "Got CI_ITEMP: %s\n", value); _ups->UPSTemp = atof(value); break; case CI_DIPSW: Dmsg(80, "Got CI_DIPSW: %s\n", value); _ups->dipsw = strtoul(value, NULL, 16); break; case CI_REG1: Dmsg(80, "Got CI_REG1: %s\n", value); _ups->reg1 = strtoul(value, NULL, 16); break; case CI_REG2: Dmsg(80, "Got CI_REG2: %s\n", value); _ups->reg2 = strtoul(value, NULL, 16); _ups->set_battpresent(!(_ups->reg2 & 0x20)); break; case CI_REG3: Dmsg(80, "Got CI_REG3: %s\n", value); _ups->reg3 = strtoul(value, NULL, 16); break; case CI_HUMID: Dmsg(80, "Got CI_HUMID: %s\n", value); _ups->humidity = atof(value); break; case CI_ATEMP: Dmsg(80, "Got CI_ATEMP: %s\n", value); _ups->ambtemp = atof(value); break; case CI_ST_TIME: Dmsg(80, "Got CI_ST_TIME: %s\n", value); _ups->LastSTTime = atof(value); break; /* * STATIC DATA */ case CI_SENS: Dmsg(80, "Got CI_SENS: %s\n", value); strlcpy(_ups->sensitivity, value, sizeof(_ups->sensitivity)); break; case CI_DWAKE: Dmsg(80, "Got CI_DWAKE: %s\n", value); _ups->dwake = (int)atof(value); break; case CI_DSHUTD: Dmsg(80, "Got CI_DSHUTD: %s\n", value); _ups->dshutd = (int)atof(value); break; case CI_LTRANS: Dmsg(80, "Got CI_LTRANS: %s\n", value); _ups->lotrans = (int)atof(value); break; case CI_HTRANS: Dmsg(80, "Got CI_HTRANS: %s\n", value); _ups->hitrans = (int)atof(value); break; case CI_RETPCT: Dmsg(80, "Got CI_RETPCT: %s\n", value); _ups->rtnpct = (int)atof(value); break; case CI_DALARM: Dmsg(80, "Got CI_DALARM: %s\n", value); strlcpy(_ups->beepstate, value, sizeof(_ups->beepstate)); break; case CI_DLBATT: Dmsg(80, "Got CI_DLBATT: %s\n", value); _ups->dlowbatt = (int)atof(value); break; case CI_IDEN: Dmsg(80, "Got CI_IDEN: %s\n", value); if (_ups->upsname[0] == 0) strlcpy(_ups->upsname, value, sizeof(_ups->upsname)); break; case CI_STESTI: Dmsg(80, "Got CI_STESTI: %s\n", value); strlcpy(_ups->selftest, value, sizeof(_ups->selftest)); break; case CI_MANDAT: Dmsg(80, "Got CI_MANDAT: %s\n", value); strlcpy(_ups->birth, value, sizeof(_ups->birth)); break; case CI_SERNO: Dmsg(80, "Got CI_SERNO: %s\n", value); strlcpy(_ups->serial, value, sizeof(_ups->serial)); break; case CI_BATTDAT: Dmsg(80, "Got CI_BATTDAT: %s\n", value); strlcpy(_ups->battdat, value, sizeof(_ups->battdat)); break; case CI_NOMOUTV: Dmsg(80, "Got CI_NOMOUTV: %s\n", value); _ups->NomOutputVoltage = (int)atof(value); break; case CI_NOMBATTV: Dmsg(80, "Got CI_NOMBATTV: %s\n", value); _ups->nombattv = atof(value); break; case CI_REVNO: Dmsg(80, "Got CI_REVNO: %s\n", value); strlcpy(_ups->firmrev, value, sizeof(_ups->firmrev)); break; case CI_EXTBATTS: Dmsg(80, "Got CI_EXTBATTS: %s\n", value); _ups->extbatts = (int)atof(value); break; case CI_BADBATTS: Dmsg(80, "Got CI_BADBATTS: %s\n", value); _ups->badbatts = (int)atof(value); break; case CI_UPSMODEL: Dmsg(80, "Got CI_UPSMODEL: %s\n", value); strlcpy(_ups->upsmodel, value, sizeof(_ups->upsmodel)); break; case CI_EPROM: Dmsg(80, "Got CI_EPROM: %s\n", value); strlcpy(_ups->eprom, value, sizeof(_ups->eprom)); break; default: Dmsg(100, "Unknown CI (%d)\n", ci); ret = false; break; } return ret; } char *PcnetUpsDriver::digest2ascii(md5_byte_t *digest) { static char ascii[33]; char byte[3]; int idx; /* Convert binary digest to ascii */ ascii[0] = '\0'; for (idx=0; idx<16; idx++) { snprintf(byte, sizeof(byte), "%02x", (unsigned char)digest[idx]); strlcat(ascii, byte, sizeof(ascii)); } return ascii; } struct pair { const char* key; const char* value; }; #define MAX_PAIRS 256 const char *PcnetUpsDriver::lookup_key(const char *key, struct pair table[]) { int idx; const char *ret = NULL; for (idx=0; table[idx].key; idx++) { if (strcmp(key, table[idx].key) == 0) { ret = table[idx].value; break; } } return ret; } struct pair *PcnetUpsDriver::auth_and_map_packet(char *buf, int len) { char *key, *end, *ptr, *value; const char *val, *hash=NULL; static struct pair pairs[MAX_PAIRS+1]; md5_state_t ms; md5_byte_t digest[16]; unsigned int idx; unsigned long uptime, reboots; /* If there's no MD= field, drop the packet */ if ((ptr = strstr(buf, "MD=")) == NULL || ptr == buf) return NULL; if (_auth) { /* Calculate the MD5 of the packet before messing with it */ md5_init(&ms); md5_append(&ms, (md5_byte_t*)buf, ptr-buf); md5_append(&ms, (md5_byte_t*)_user, strlen(_user)); md5_append(&ms, (md5_byte_t*)_pass, strlen(_pass)); md5_finish(&ms, digest); /* Convert binary digest to ascii */ hash = digest2ascii(digest); } /* Build a table of pointers to key/value pairs */ memset(pairs, 0, sizeof(pairs)); ptr = buf; idx = 0; while (*ptr && idx < MAX_PAIRS) { /* Find the beginning of the line */ while (isspace(*ptr)) ptr++; key = ptr; /* Find the end of the line */ while (*ptr && *ptr != '\r' && *ptr != '\n') ptr++; end = ptr; if (*ptr != '\0') ptr++; /* Remove trailing whitespace */ do { *end-- = '\0'; } while (end >= key && isspace(*end)); Dmsg(300, "process_packet: line='%s'\n", key); /* Split the string */ if ((value = strchr(key, '=')) == NULL) continue; *value++ = '\0'; Dmsg(300, "process_packet: key='%s' value='%s'\n", key, value); /* Save key/value in table */ pairs[idx].key = key; pairs[idx].value = value; idx++; } if (_auth) { /* Check calculated hash vs received */ Dmsg(200, "process_packet: calculated=%s\n", hash); val = lookup_key("MD", pairs); if (!val || strcmp(hash, val)) { Dmsg(200, "process_packet: message hash failed\n"); return NULL; } Dmsg(200, "process_packet: message hash passed\n", val); /* Check management card IP address */ val = lookup_key("PC", pairs); if (!val) { Dmsg(200, "process_packet: Missing PC field\n"); return NULL; } Dmsg(200, "process_packet: Expected IP=%s\n", _ipaddr); Dmsg(200, "process_packet: Received IP=%s\n", val); if (strcmp(val, _ipaddr)) { Dmsg(200, "process_packet: IP address mismatch\n", _ipaddr, val); return NULL; } } /* * Check that uptime and/or reboots have advanced. If not, * this packet could be out of order, or an attacker may * be trying to replay an old packet. */ val = lookup_key("SR", pairs); if (!val) { Dmsg(200, "process_packet: Missing SR field\n"); return NULL; } reboots = strtoul(val, NULL, 16); val = lookup_key("SU", pairs); if (!val) { Dmsg(200, "process_packet: Missing SU field\n"); return NULL; } uptime = strtoul(val, NULL, 16); Dmsg(200, "process_packet: Our reboots=%d\n", _reboots); Dmsg(200, "process_packet: UPS reboots=%d\n", reboots); Dmsg(200, "process_packet: Our uptime=%d\n", _uptime); Dmsg(200, "process_packet: UPS uptime=%d\n", uptime); if ((reboots == _reboots && uptime <= _uptime) || (reboots < _reboots)) { Dmsg(200, "process_packet: Packet is out of order or replayed\n"); return NULL; } _reboots = reboots; _uptime = uptime; return pairs; } int PcnetUpsDriver::wait_for_data(int wait_time) { struct timeval tv, now, exit; fd_set rfds; bool done = false; struct sockaddr_in from; socklen_t fromlen; int retval; char buf[4096]; struct pair *map; int idx; /* Figure out when we need to exit by */ gettimeofday(&exit, NULL); exit.tv_sec += wait_time; while (!done) { /* Figure out how long until we have to exit */ gettimeofday(&now, NULL); if (now.tv_sec > exit.tv_sec || (now.tv_sec == exit.tv_sec && now.tv_usec >= exit.tv_usec)) { /* Done already? How time flies... */ break; } tv.tv_sec = exit.tv_sec - now.tv_sec; tv.tv_usec = exit.tv_usec - now.tv_usec; if (tv.tv_usec < 0) { tv.tv_sec--; /* Normalize */ tv.tv_usec += 1000000; } Dmsg(100, "Waiting for %d.%d\n", tv.tv_sec, tv.tv_usec); FD_ZERO(&rfds); FD_SET(_fd, &rfds); retval = select(_fd + 1, &rfds, NULL, NULL, &tv); if (retval == 0) { /* No chars available in TIMER seconds. */ break; } else if (retval == -1) { if (errno == EINTR || errno == EAGAIN) /* assume SIGCHLD */ continue; Dmsg(200, "select error: ERR=%s\n", strerror(errno)); return 0; } do { fromlen = sizeof(from); retval = recvfrom(_fd, buf, sizeof(buf)-1, 0, (struct sockaddr*)&from, &fromlen); } while (retval == -1 && (errno == EAGAIN || errno == EINTR)); if (retval < 0) { /* error */ Dmsg(200, "recvfrom error: ERR=%s\n", strerror(errno)); // usb_link_check(ups); /* notify that link is down, wait */ break; } Dmsg(200, "Packet from: %d.%d.%d.%d\n", (ntohl(from.sin_addr.s_addr) >> 24) & 0xff, (ntohl(from.sin_addr.s_addr) >> 16) & 0xff, (ntohl(from.sin_addr.s_addr) >> 8) & 0xff, ntohl(from.sin_addr.s_addr) & 0xff); /* Ensure the packet is nul-terminated */ buf[retval] = '\0'; hex_dump(300, buf, retval); map = auth_and_map_packet(buf, retval); if (map == NULL) continue; write_lock(_ups); for (idx=0; map[idx].key; idx++) done |= pcnet_process_data(map[idx].key, map[idx].value); write_unlock(_ups); } /* If we successfully received a data packet, update timer. */ if (done) { time(&_datatime); Dmsg(100, "Valid data at time_t=%d\n", _datatime); } return done; } /* * Read UPS events. I.e. state changes. */ bool PcnetUpsDriver::check_state() { return wait_for_data(_ups->wait_time); } bool PcnetUpsDriver::Open() { struct sockaddr_in addr; char *ptr; write_lock(_ups); unsigned short port = PCNET_DEFAULT_PORT; if (_ups->device[0] != '\0') { _auth = true; strlcpy(_device, _ups->device, sizeof(_device)); ptr = _device; _ipaddr = ptr; ptr = strchr(ptr, ':'); if (ptr == NULL) Error_abort("Malformed DEVICE [ip:user:pass]\n"); *ptr++ = '\0'; _user = ptr; ptr = strchr(ptr, ':'); if (ptr == NULL) Error_abort("Malformed DEVICE [ip:user:pass]\n"); *ptr++ = '\0'; _pass = ptr; if (*ptr == '\0') Error_abort("Malformed DEVICE [ip:user:pass]\n"); // Last segment is optional port number ptr = strchr(ptr, ':'); if (ptr) { *ptr++ = '\0'; port = atoi(ptr); if (port == 0) port = PCNET_DEFAULT_PORT; } } _fd = socket_cloexec(PF_INET, SOCK_DGRAM, 0); if (_fd == INVALID_SOCKET) Error_abort("Cannot create socket (%d)\n", errno); // Although SO_BROADCAST is typically described as enabling broadcast // *transmission* (which is not what we want) on some systems it appears to // be needed for broadcast reception as well. We will attempt to set it // everywhere and not worry if it fails. int enable = 1; (void)setsockopt(_fd, SOL_SOCKET, SO_BROADCAST, (const char*)&enable, sizeof(enable)); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = INADDR_ANY; if (bind(_fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { close(_fd); Error_abort("Cannot bind socket (%d)\n", errno); } /* Reset datatime to now */ time(&_datatime); /* * Note, we set _ups->fd here so the "core" of apcupsd doesn't * think we are a slave, which is what happens when it is -1. * (ADK: Actually this only appears to be true for apctest as * apcupsd proper uses the UPS_slave flag.) * Internally, we use the fd in our own private space */ _ups->fd = 1; write_unlock(_ups); return 1; } bool PcnetUpsDriver::Close() { write_lock(_ups); close(_fd); _fd = INVALID_SOCKET; write_unlock(_ups); return 1; } /* * Setup capabilities structure for UPS */ bool PcnetUpsDriver::get_capabilities() { /* * Unfortunately, we don't know capabilities until we * receive the first broadcast status message. */ int rc = wait_for_data(COMMLOST_TIMEOUT); if (rc) { // Disable workaround ... recent Smart-UPS RT 5000 XL don't have this issue // and workaround is causing bad readings #if 0 /* * Check for quirk where UPS reports runtime remaining in seconds * instead of the usual minutes. So far this has been reported on * "Smart-UPS RT 5000 XL" and "Smart-UPS X 3000". We will assume it * affects all RT and X series models. */ if (_ups->UPS_Cap[CI_UPSMODEL] && (!strncmp(_ups->upsmodel, "Smart-UPS X", 11) || !strncmp(_ups->upsmodel, "Smart-UPS RT", 12))) { Dmsg(50, "Enabling runtime-in-seconds quirk [%s]\n", _ups->upsmodel); _runtimeInSeconds = true; if (_ups->UPS_Cap[CI_RUNTIM]) _ups->TimeLeft /= 60; // Adjust initial value } #endif } return _ups->UPS_Cap[CI_STATUS]; } /* * Read UPS info that remains unchanged -- e.g. transfer * voltages, shutdown delay, ... * * This routine is called once when apcupsd is starting */ bool PcnetUpsDriver::read_static_data() { /* * First set of data was gathered already in pcnet_ups_get_capabilities(). * All additional data gathering is done in pcnet_ups_check_state() */ return 1; } /* * Read UPS info that changes -- e.g. Voltage, temperature, ... * * This routine is called once every N seconds to get * a current idea of what the UPS is doing. */ bool PcnetUpsDriver::read_volatile_data() { time_t now, diff; /* * All our data gathering is done in pcnet_ups_check_state(). * But we do use this function to check our commlost state. */ time(&now); diff = now - _datatime; if (_ups->is_commlost()) { if (diff < COMMLOST_TIMEOUT) { generate_event(_ups, CMDCOMMOK); _ups->clear_commlost(); } } else { if (diff >= COMMLOST_TIMEOUT) { generate_event(_ups, CMDCOMMFAILURE); _ups->set_commlost(); } } return 1; } bool PcnetUpsDriver::kill_power() { struct sockaddr_in addr; char data[1024]; sock_t s; int len=0, temp=0; char *start; const char *cs, *hash; struct pair *map; md5_state_t ms; md5_byte_t digest[16]; /* We cannot perform a killpower without authentication data */ if (!_auth) { Error_abort("Cannot perform killpower without authentication " "data. Please set ip:user:pass for DEVICE in " "apcupsd.conf.\n"); } /* Open a TCP stream to the UPS */ s = socket_cloexec(PF_INET, SOCK_STREAM, 0); if (s == INVALID_SOCKET) { Dmsg(100, "pcnet_ups_kill_power: Unable to open socket: %s\n", strerror(errno)); return 0; } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(80); inet_pton(AF_INET, _ipaddr, &addr.sin_addr.s_addr); if (connect(s, (sockaddr*)&addr, sizeof(addr))) { Dmsg(100, "pcnet_ups_kill_power: Unable to connect to %s:%d: %s\n", _ipaddr, 80, strerror(errno)); close(s); return 0; } /* Send a simple HTTP request for "/macontrol.htm". */ asnprintf(data, sizeof(data), "GET /macontrol.htm HTTP/1.1\r\n" "Host: %s\r\n" "\r\n", _ipaddr); Dmsg(200, "Request:\n---\n%s---\n", data); if (send(s, data, strlen(data), 0) != (int)strlen(data)) { Dmsg(100, "pcnet_ups_kill_power: send failed: %s\n", strerror(errno)); close(s); return 0; } /* * Read data until we find the 0-length chunk. * We know that AP9617 uses chunked encoding, so we * can count on the 0-length chunk at the end. */ do { len += temp; temp = recv(s, data+len, sizeof(data)-len-1, 0); if (temp >= 0) data[len+temp] = '\0'; } while(temp > 0 && strstr(data, "\r\n0\r\n") == NULL); Dmsg(200, "Response:\n---\n%s---\n", data); if (temp < 0) { Dmsg(100, "pcnet_ups_kill_power: recv failed: %s\n", strerror(errno)); close(s); return 0; } /* * Find "" since that's where the real authenticated * data begins. Everything before that is headers. */ start = strstr(data, ""); if (start == NULL) { Dmsg(100, "pcnet_ups_kill_power: Malformed data\n"); close(s); return 0; } /* * Authenticate and map the packet contents. This will * extract all key/value pairs and ensure the packet * authentication hash is valid. */ map = auth_and_map_packet(start, strlen(start)); if (map == NULL) { close(s); return 0; } /* Check that we got a challenge string. */ cs = lookup_key("CS", map); if (cs == NULL) { Dmsg(200, "pcnet_ups_kill_power: Missing CS field\n"); close(s); return 0; } /* * Now construct the hash of the packet we're about to * send using the challenge string from the packet we * just received, plus our username and passphrase. */ md5_init(&ms); md5_append(&ms, (md5_byte_t*)"macontrol1_control_shutdown_1=1,", 32); md5_append(&ms, (md5_byte_t*)cs, strlen(cs)); md5_append(&ms, (md5_byte_t*)_user, strlen(_user)); md5_append(&ms, (md5_byte_t*)_pass, strlen(_pass)); md5_finish(&ms, digest); hash = digest2ascii(digest); /* Send the shutdown request */ asnprintf(data, sizeof(data), "POST /Forms/macontrol1 HTTP/1.1\r\n" "Host: %s\r\n" "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: 72\r\n" "\r\n" "macontrol1%%5fcontrol%%5fshutdown%%5f1=1%%2C%s", _ipaddr, hash); Dmsg(200, "Request: (strlen=%d)\n---\n%s---\n", strlen(data), data); if (send(s, data, strlen(data), 0) != (int)strlen(data)) { Dmsg(100, "pcnet_ups_kill_power: send failed: %s\n", strerror(errno)); close(s); return 0; } /* That's it, we're done. */ close(s); return 1; } bool PcnetUpsDriver::entry_point(int command, void *data) { switch (command) { case DEVICE_CMD_CHECK_SELFTEST: Dmsg(80, "Checking self test.\n"); if (_ups->UPS_Cap[CI_WHY_BATT] && _ups->lastxfer == XFER_SELFTEST) { /* * set Self Test start time */ _ups->SelfTest = time(NULL); Dmsg(80, "Self Test time: %s", ctime(&_ups->SelfTest)); } break; case DEVICE_CMD_GET_SELFTEST_MSG: /* * This is a bit kludgy. The selftest result isn't available from * the UPS for about 10 seconds after the selftest completes. So we * invoke pcnet_ups_check_state() with a 12 second timeout, * expecting that it should get a status report before then. */ /* Let check_status wait for the result */ write_unlock(_ups); wait_for_data(12); write_lock(_ups); break; default: return FAILURE; } return SUCCESS; } apcupsd-3.14.14/src/drivers/pcnet/pcnet.h000066400000000000000000000032221274230402600201620ustar00rootroot00000000000000/* * pcnet.h * * Public header file for the pcnet driver. */ #ifndef _PCNET_H #define _PCNET_H #include "md5.h" class PcnetUpsDriver: public UpsDriver { public: PcnetUpsDriver(UPSINFO *ups); virtual ~PcnetUpsDriver() {} static UpsDriver *Factory(UPSINFO *ups) { return new PcnetUpsDriver(ups); } virtual bool get_capabilities(); virtual bool read_volatile_data(); virtual bool read_static_data(); virtual bool kill_power(); virtual bool check_state(); virtual bool Open(); virtual bool Close(); virtual bool entry_point(int command, void *data); private: bool pcnet_process_data(const char *key, const char *value); struct pair *auth_and_map_packet(char *buf, int len); int wait_for_data(int wait_time); static SelfTestResult decode_testresult(const char* str); static LastXferCause decode_lastxfer(const char *str); static char *digest2ascii(md5_byte_t *digest); static const char *lookup_key(const char *key, struct pair table[]); char _device[MAXSTRING]; /* Copy of ups->device */ char *_ipaddr; /* IP address of UPS */ char *_user; /* Username */ char *_pass; /* Pass phrase */ bool _auth; /* Authenticate? */ unsigned long _uptime; /* UPS uptime counter */ unsigned long _reboots; /* UPS reboot counter */ time_t _datatime; /* Last time we got valid data */ bool _runtimeInSeconds; /* UPS reports runtime in seconds */ sock_t _fd; /* Socket connection */ }; #endif /* _PCNET_H */ apcupsd-3.14.14/src/drivers/snmplite/000077500000000000000000000000001274230402600174235ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/snmplite/Makefile000066400000000000000000000003211274230402600210570ustar00rootroot00000000000000topdir:=../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.cpp) $(wildcard *.c) all-targets: libsnmplitedrv.a libsnmplitedrv.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/snmplite/apc-mib.cpp000066400000000000000000000343461274230402600214510ustar00rootroot00000000000000/* * mib.cpp * * CI -> OID mapping for SNMP Lite UPS driver */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "snmplite-common.h" #include "mibs.h" #include "apc-oids.h" using namespace Asn; static struct CiOidMap CiOidMap[] = { // CI OID type dynamic? {CI_UPSMODEL, upsBasicIdentModel, OCTETSTRING, false}, {CI_SERNO, upsAdvIdentSerialNumber, OCTETSTRING, false}, {CI_IDEN, upsBasicIdentName, OCTETSTRING, false}, {CI_REVNO, upsAdvIdentFirmwareRevision, OCTETSTRING, false}, {CI_MANDAT, upsAdvIdentDateOfManufacture, OCTETSTRING, false}, {CI_BATTDAT, upsBasicBatteryLastReplaceDate, OCTETSTRING, false}, {CI_NOMBATTV, upsAdvBatteryNominalVoltage, INTEGER, false}, {CI_NOMOUTV, upsAdvConfigRatedOutputVoltage, INTEGER, false}, {CI_LTRANS, upsAdvConfigLowTransferVolt, INTEGER, false}, {CI_HTRANS, upsAdvConfigHighTransferVolt, INTEGER, false}, {CI_DWAKE, upsAdvConfigReturnDelay, TIMETICKS, false}, {CI_AlarmTimer, upsAdvConfigAlarmTimer, TIMETICKS, false}, // Must be before CI_DALARM {CI_DALARM, upsAdvConfigAlarm, INTEGER, false}, {CI_DLBATT, upsAdvConfigLowBatteryRunTime, TIMETICKS, false}, {CI_DSHUTD, upsAdvConfigShutoffDelay, TIMETICKS, false}, {CI_RETPCT, upsAdvConfigMinReturnCapacity, INTEGER, false}, {CI_SENS, upsAdvConfigSensitivity, INTEGER, false}, {CI_EXTBATTS, upsAdvBatteryNumOfBattPacks, INTEGER, false}, {CI_STESTI, upsAdvTestDiagnosticSchedule, INTEGER, false}, {CI_VLINE, upsAdvInputLineVoltage, GAUGE, true }, {CI_VOUT, upsAdvOutputVoltage, GAUGE, true }, {CI_VBATT, upsAdvBatteryActualVoltage, INTEGER, true }, {CI_FREQ, upsAdvInputFrequency, GAUGE, true }, {CI_LOAD, upsAdvOutputLoad, GAUGE, true }, {CI_ITEMP, upsAdvBatteryTemperature, GAUGE, true }, {CI_ATEMP, mUpsEnvironAmbientTemperature, GAUGE, true }, {CI_HUMID, mUpsEnvironRelativeHumidity, GAUGE, true }, {CI_ST_STAT, upsAdvTestDiagnosticsResults, INTEGER, true }, {CI_BATTLEV, upsAdvBatteryCapacity, GAUGE, true }, {CI_RUNTIM, upsAdvBatteryRunTimeRemaining, TIMETICKS, true }, {CI_WHY_BATT, upsAdvInputLineFailCause, INTEGER, true }, {CI_BADBATTS, upsAdvBatteryNumOfBadBattPacks, INTEGER, true }, {CI_VMIN, upsAdvInputMinLineVoltage, GAUGE, true }, {CI_VMAX, upsAdvInputMaxLineVoltage, GAUGE, true }, // These 5 collectively are used to obtain the data for CI_STATUS. // All bits are available in upsBasicStateOutputState at once but // the old AP960x cards do not appear to support that OID, so we use // it only for the overload flag which is not available elsewhere. {CI_STATUS, upsBasicOutputStatus, INTEGER, true }, {CI_NeedReplacement, upsAdvBatteryReplaceIndicator, INTEGER, true }, {CI_LowBattery, upsBasicBatteryStatus, INTEGER, true }, {CI_Calibration, upsAdvTestCalibrationResults, INTEGER, true }, {CI_Overload, upsBasicStateOutputState, OCTETSTRING, true }, {-1, NULL, false} /* END OF TABLE */ }; #define TIMETICKS_TO_SECS 100 #define SECS_TO_MINS 60 // Seen in the field: ITEMP OID occasionally sent by UPS is bogus. Value // appears to come from CI_RUNTIM OID. Confirmed via Wireshark that error is on // UPS Web/SNMP card side. As a workaround in apcupsd we will filter out // obviously bogus ITEMPs. // // Issue was observed on: // UPS: Smart-UPS RT 5000 XL // SNMP module: // MN:AP9619 HR:A10 MD:07/12/2007 // MB:v3.8.6 PF:v3.5.5 PN:apc_hw02_aos_355.bin AF1:v3.5.5 AN1:apc_hw02_sumx_355.bin #define MAX_SANE_ITEMP 200 static void apc_update_ci(UPSINFO *ups, int ci, Snmp::Variable &data) { static unsigned int alarmtimer = 0; switch (ci) { case CI_VLINE: Dmsg(80, "Got CI_VLINE: %d\n", data.u32); ups->LineVoltage = data.u32; break; case CI_VOUT: Dmsg(80, "Got CI_VOUT: %d\n", data.u32); ups->OutputVoltage = data.u32; break; case CI_VBATT: Dmsg(80, "Got CI_VBATT: %d\n", data.u32); ups->BattVoltage = data.u32; break; case CI_FREQ: Dmsg(80, "Got CI_FREQ: %d\n", data.u32); ups->LineFreq = data.u32; break; case CI_LOAD: Dmsg(80, "Got CI_LOAD: %d\n", data.u32); ups->UPSLoad = data.u32; break; case CI_ITEMP: Dmsg(80, "Got CI_ITEMP: %d\n", data.u32); if (data.u32 <= MAX_SANE_ITEMP) ups->UPSTemp = data.u32; else Dmsg(10, "Ignoring out-of-range ITEMP: %d\n", data.u32); break; case CI_ATEMP: Dmsg(80, "Got CI_ATEMP: %d\n", data.u32); ups->ambtemp = data.u32; break; case CI_HUMID: Dmsg(80, "Got CI_HUMID: %d\n", data.u32); ups->humidity = data.u32; break; case CI_NOMBATTV: Dmsg(80, "Got CI_NOMBATTV: %d\n", data.u32); ups->nombattv = data.u32; break; case CI_NOMOUTV: Dmsg(80, "Got CI_NOMOUTV: %d\n", data.u32); ups->NomOutputVoltage = data.u32; break; case CI_NOMINV: Dmsg(80, "Got CI_NOMINV: %d\n", data.u32); ups->NomInputVoltage = data.u32; break; case CI_NOMPOWER: Dmsg(80, "Got CI_NOMPOWER: %d\n", data.u32); ups->NomPower = data.u32; break; case CI_LTRANS: Dmsg(80, "Got CI_LTRANS: %d\n", data.u32); ups->lotrans = data.u32; break; case CI_HTRANS: Dmsg(80, "Got CI_HTRANS: %d\n", data.u32); ups->hitrans = data.u32; break; case CI_DWAKE: Dmsg(80, "Got CI_DWAKE: %d\n", data.u32); ups->dwake = data.u32; break; case CI_ST_STAT: Dmsg(80, "Got CI_ST_STAT: %d\n", data.u32); switch (data.u32) { case 1: /* Passed */ ups->testresult = TEST_PASSED; break; case 2: /* Failed */ case 3: /* Invalid test */ ups->testresult = TEST_FAILED; break; case 4: /* Test in progress */ ups->testresult = TEST_INPROGRESS; break; default: ups->testresult = TEST_UNKNOWN; break; } break; case CI_AlarmTimer: Dmsg(80, "Got CI_AlarmTimer: %d\n", data.u32); // Remember alarm timer setting; we will use it for CI_DALARM alarmtimer = data.u32; break; case CI_DALARM: Dmsg(80, "Got CI_DALARM: %d\n", data.u32); switch (data.u32) { case 1: // Timed (uses CI_AlarmTimer) if (ups->UPS_Cap[CI_AlarmTimer] && alarmtimer < 30) strlcpy(ups->beepstate, "0", sizeof(ups->beepstate)); // 5 secs else strlcpy(ups->beepstate, "T", sizeof(ups->beepstate)); // 30 secs break; case 2: // LowBatt strlcpy(ups->beepstate, "L", sizeof(ups->beepstate)); break; case 3: // None strlcpy(ups->beepstate, "N", sizeof(ups->beepstate)); break; default: strlcpy(ups->beepstate, "T", sizeof(ups->beepstate)); break; } break; case CI_UPSMODEL: Dmsg(80, "Got CI_UPSMODEL: %s\n", data.str.str()); strlcpy(ups->upsmodel, data.str, sizeof(ups->upsmodel)); break; case CI_SERNO: Dmsg(80, "Got CI_SERNO: %s\n", data.str.str()); strlcpy(ups->serial, data.str, sizeof(ups->serial)); break; case CI_MANDAT: Dmsg(80, "Got CI_MANDAT: %s\n", data.str.str()); strlcpy(ups->birth, data.str, sizeof(ups->birth)); break; case CI_BATTLEV: Dmsg(80, "Got CI_BATTLEV: %d\n", data.u32); ups->BattChg = data.u32; break; case CI_RUNTIM: Dmsg(80, "Got CI_RUNTIM: %d\n", data.u32); ups->TimeLeft = data.u32 / TIMETICKS_TO_SECS / SECS_TO_MINS; break; case CI_BATTDAT: Dmsg(80, "Got CI_BATTDAT: %s\n", data.str.str()); strlcpy(ups->battdat, data.str, sizeof(ups->battdat)); break; case CI_IDEN: Dmsg(80, "Got CI_IDEN: %s\n", data.str.str()); strlcpy(ups->upsname, data.str, sizeof(ups->upsname)); break; case CI_STATUS: Dmsg(80, "Got CI_STATUS: %d\n", data.u32); /* Clear the following flags: only one status will be TRUE */ ups->clear_online(); ups->clear_onbatt(); ups->clear_boost(); ups->clear_trim(); switch (data.u32) { case 2: ups->set_online(); break; case 3: ups->set_onbatt(); break; case 4: ups->set_online(); ups->set_boost(); break; case 12: ups->set_online(); ups->set_trim(); break; case 1: /* unknown */ case 5: /* timed sleeping */ case 6: /* software bypass */ case 7: /* UPS off */ case 8: /* UPS rebooting */ case 9: /* switched bypass */ case 10: /* hardware failure bypass */ case 11: /* sleeping until power returns */ default: /* unknown */ break; } break; case CI_NeedReplacement: Dmsg(80, "Got CI_NeedReplacement: %d\n", data.u32); if (data.u32 == 2) ups->set_replacebatt(); else ups->clear_replacebatt(); break; case CI_LowBattery: Dmsg(80, "Got CI_LowBattery: %d\n", data.u32); if (data.u32 == 3) ups->set_battlow(); else ups->clear_battlow(); break; case CI_Calibration: Dmsg(80, "Got CI_Calibration: %d\n", data.u32); if (data.u32 == 3) ups->set_calibration(); else ups->clear_calibration(); break; case CI_Overload: Dmsg(80, "Got CI_Overload: %c\n", data.str[8]); if (data.str[8] == '1') ups->set_overload(); else ups->clear_overload(); break; case CI_DSHUTD: Dmsg(80, "Got CI_DSHUTD: %d\n", data.u32); ups->dshutd = data.u32 / TIMETICKS_TO_SECS; break; case CI_RETPCT: Dmsg(80, "Got CI_RETPCT: %d\n", data.u32); ups->rtnpct = data.u32; break; case CI_WHY_BATT: Dmsg(80, "Got CI_WHY_BATT: %d\n", data.u32); switch (data.u32) { case 1: ups->lastxfer = XFER_NONE; break; case 2: /* High line voltage */ ups->lastxfer = XFER_OVERVOLT; break; case 3: /* Brownout */ case 4: /* Blackout */ ups->lastxfer = XFER_UNDERVOLT; break; case 5: /* Small sag */ case 6: /* Deep sag */ case 7: /* Small spike */ case 8: /* Deep spike */ ups->lastxfer = XFER_NOTCHSPIKE; break; case 9: ups->lastxfer = XFER_SELFTEST; break; case 10: ups->lastxfer = XFER_RIPPLE; break; default: ups->lastxfer = XFER_UNKNOWN; break; } break; case CI_SENS: Dmsg(80, "Got CI_SENS: %d\n", data.u32); switch (data.u32) { case 1: strlcpy(ups->sensitivity, "Auto", sizeof(ups->sensitivity)); break; case 2: strlcpy(ups->sensitivity, "Low", sizeof(ups->sensitivity)); break; case 3: strlcpy(ups->sensitivity, "Medium", sizeof(ups->sensitivity)); break; case 4: strlcpy(ups->sensitivity, "High", sizeof(ups->sensitivity)); break; default: strlcpy(ups->sensitivity, "Unknown", sizeof(ups->sensitivity)); break; } break; case CI_REVNO: Dmsg(80, "Got CI_REVNO: %s\n", data.str.str()); strlcpy(ups->firmrev, data.str, sizeof(ups->firmrev)); break; case CI_EXTBATTS: Dmsg(80, "Got CI_EXTBATTS: %d\n", data.u32); ups->extbatts = data.u32; break; case CI_BADBATTS: Dmsg(80, "Got CI_BADBATTS: %d\n", data.u32); ups->badbatts = data.u32; break; case CI_DLBATT: Dmsg(80, "Got CI_DLBATT: %d\n", data.u32); ups->dlowbatt = data.u32 / TIMETICKS_TO_SECS / SECS_TO_MINS; break; case CI_STESTI: Dmsg(80, "Got CI_STESTI: %d\n", data.u32); switch (data.u32) { case 2: strlcpy(ups->selftest, "336", sizeof(ups->selftest)); break; case 3: strlcpy(ups->selftest, "168", sizeof(ups->selftest)); break; case 4: strlcpy(ups->selftest, "ON", sizeof(ups->selftest)); break; case 1: case 5: default: strlcpy(ups->selftest, "OFF", sizeof(ups->selftest)); break; } break; case CI_VMIN: Dmsg(80, "Got CI_VMIN: %d\n", data.u32); ups->LineMin = data.u32; break; case CI_VMAX: Dmsg(80, "Got CI_VMAX: %d\n", data.u32); ups->LineMax = data.u32; break; } } static int apc_killpower(Snmp::SnmpEngine *snmp) { Snmp::Variable var(Asn::INTEGER, 2); return snmp->Set(upsBasicControlConserveBattery, &var); } static int apc_shutdown(Snmp::SnmpEngine *snmp) { Snmp::Variable var(Asn::INTEGER, 2); return snmp->Set(upsAdvControlUpsOff, &var); } // Export strategy to snmplite.cpp struct MibStrategy ApcMibStrategy = { "APC", CiOidMap, apc_update_ci, apc_killpower, apc_shutdown, }; apcupsd-3.14.14/src/drivers/snmplite/apc-oids.h000066400000000000000000001151461274230402600213030ustar00rootroot00000000000000#ifndef __OIDS_H_ #define __OIDS_H_ /* * oids.h * * UPS-related OIDs from APC's PowerNet MIB * * Generated from powernet398.mib (rev 3.9.8) * */ #ifdef __GNUC__ #define __UNUSED__ __attribute__((unused)) #else #define __UNUSED__ #endif // // Note that because these are all declared static, the compiler will eliminate // those that we do not reference. It will warn about it, however, so need to // suppress that where possible. // __UNUSED__ static int upsBasicIdentModel[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 1, 1, 1, -1}; __UNUSED__ static int upsBasicIdentName[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 1, 1, 2, -1}; __UNUSED__ static int upsAdvIdentFirmwareRevision[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 1, 2, 1, -1}; __UNUSED__ static int upsAdvIdentDateOfManufacture[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 1, 2, 2, -1}; __UNUSED__ static int upsAdvIdentSerialNumber[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 1, 2, 3, -1}; __UNUSED__ static int upsAdvIdentFirmwareRevision2[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 1, 2, 4, -1}; __UNUSED__ static int upsAdvIdentSkuNumber[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 1, 2, 5, -1}; __UNUSED__ static int upsBasicBatteryStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 1, 1, -1}; __UNUSED__ static int upsBasicBatteryTimeOnBattery[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 1, 2, -1}; __UNUSED__ static int upsBasicBatteryLastReplaceDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 1, 3, -1}; __UNUSED__ static int upsAdvBatteryCapacity[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 1, -1}; __UNUSED__ static int upsAdvBatteryTemperature[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 2, -1}; __UNUSED__ static int upsAdvBatteryRunTimeRemaining[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 3, -1}; __UNUSED__ static int upsAdvBatteryReplaceIndicator[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 4, -1}; __UNUSED__ static int upsAdvBatteryNumOfBattPacks[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 5, -1}; __UNUSED__ static int upsAdvBatteryNumOfBadBattPacks[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 6, -1}; __UNUSED__ static int upsAdvBatteryNominalVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 7, -1}; __UNUSED__ static int upsAdvBatteryActualVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 8, -1}; __UNUSED__ static int upsAdvBatteryCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 9, -1}; __UNUSED__ static int upsAdvTotalDCCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 2, 10, -1}; __UNUSED__ static int upsHighPrecBatteryCapacity[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 3, 1, -1}; __UNUSED__ static int upsHighPrecBatteryTemperature[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 3, 2, -1}; __UNUSED__ static int upsHighPrecBatteryNominalVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 3, 3, -1}; __UNUSED__ static int upsHighPrecBatteryActualVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 3, 4, -1}; __UNUSED__ static int upsHighPrecBatteryCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 3, 5, -1}; __UNUSED__ static int upsHighPrecTotalDCCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 2, 3, 6, -1}; __UNUSED__ static int upsBasicInputPhase[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 1, 1, -1}; __UNUSED__ static int upsAdvInputLineVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 2, 1, -1}; __UNUSED__ static int upsAdvInputMaxLineVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 2, 2, -1}; __UNUSED__ static int upsAdvInputMinLineVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 2, 3, -1}; __UNUSED__ static int upsAdvInputFrequency[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 2, 4, -1}; __UNUSED__ static int upsAdvInputLineFailCause[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 2, 5, -1}; __UNUSED__ static int upsHighPrecInputLineVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 3, 1, -1}; __UNUSED__ static int upsHighPrecInputMaxLineVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 3, 2, -1}; __UNUSED__ static int upsHighPrecInputMinLineVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 3, 3, -1}; __UNUSED__ static int upsHighPrecInputFrequency[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 3, 3, 4, -1}; __UNUSED__ static int upsBasicOutputStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 1, 1, -1}; __UNUSED__ static int upsBasicOutputPhase[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 1, 2, -1}; __UNUSED__ static int upsBasicSystemStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 1, 3, -1}; __UNUSED__ static int upsAdvOutputVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 2, 1, -1}; __UNUSED__ static int upsAdvOutputFrequency[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 2, 2, -1}; __UNUSED__ static int upsAdvOutputLoad[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 2, 3, -1}; __UNUSED__ static int upsAdvOutputCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 2, 4, -1}; __UNUSED__ static int upsAdvOutputRedundancy[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 2, 5, -1}; __UNUSED__ static int upsAdvOutputKVACapacity[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 2, 6, -1}; __UNUSED__ static int upsHighPrecOutputVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 3, 1, -1}; __UNUSED__ static int upsHighPrecOutputFrequency[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 3, 2, -1}; __UNUSED__ static int upsHighPrecOutputLoad[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 3, 3, -1}; __UNUSED__ static int upsHighPrecOutputCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 4, 3, 4, -1}; __UNUSED__ static int upsBasicConfigNumDevices[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 1, 1, -1}; __UNUSED__ static int upsBasicConfigDeviceTableDeviceIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 1, 2, 1, 1, -1}; __UNUSED__ static int upsBasicConfigDeviceTableDeviceName[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 1, 2, 1, 2, -1}; __UNUSED__ static int upsBasicConfigDeviceTableVaRating[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 1, 2, 1, 3, -1}; __UNUSED__ static int upsBasicConfigDeviceTableAcceptThisDevice[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 1, 2, 1, 4, -1}; __UNUSED__ static int upsAdvConfigRatedOutputVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 1, -1}; __UNUSED__ static int upsAdvConfigHighTransferVolt[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 2, -1}; __UNUSED__ static int upsAdvConfigLowTransferVolt[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 3, -1}; __UNUSED__ static int upsAdvConfigAlarm[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 4, -1}; __UNUSED__ static int upsAdvConfigAlarmTimer[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 5, -1}; __UNUSED__ static int upsAdvConfigMinReturnCapacity[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 6, -1}; __UNUSED__ static int upsAdvConfigSensitivity[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 7, -1}; __UNUSED__ static int upsAdvConfigLowBatteryRunTime[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 8, -1}; __UNUSED__ static int upsAdvConfigReturnDelay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 9, -1}; __UNUSED__ static int upsAdvConfigShutoffDelay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 10, -1}; __UNUSED__ static int upsAdvConfigUpsSleepTime[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 11, -1}; __UNUSED__ static int upsAdvConfigSetEEPROMDefaults[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 12, -1}; __UNUSED__ static int upsAdvConfigDipSwitchSettingDipSwitchIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 13, 1, 1, -1}; __UNUSED__ static int upsAdvConfigDipSwitchSettingDipSwitchStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 13, 1, 2, -1}; __UNUSED__ static int upsAdvConfigBattExhaustThresh[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 14, -1}; __UNUSED__ static int upsAdvConfigPassword[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 15, -1}; __UNUSED__ static int apcUpsConfigFieldIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 16, 1, 1, -1}; __UNUSED__ static int apcUpsConfigFieldOID[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 16, 1, 2, -1}; __UNUSED__ static int apcUpsConfigFieldValueRange[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 16, 1, 3, -1}; __UNUSED__ static int upsAdvConfigBattCabAmpHour[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 17, -1}; __UNUSED__ static int upsAdvConfigPositionSelector[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 18, -1}; __UNUSED__ static int upsAdvConfigOutputFreqRange[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 19, -1}; __UNUSED__ static int upsAdvConfigUPSFail[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 20, -1}; __UNUSED__ static int upsAdvConfigAlarmRedundancy[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 21, -1}; __UNUSED__ static int upsAdvConfigAlarmLoadOver[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 22, -1}; __UNUSED__ static int upsAdvConfigAlarmRuntimeUnder[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 23, -1}; __UNUSED__ static int upsAdvConfigVoutReporting[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 24, -1}; __UNUSED__ static int upsAdvConfigNumExternalBatteries[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 25, -1}; __UNUSED__ static int upsAdvConfigSimpleSignalShutdowns[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 26, -1}; __UNUSED__ static int upsAdvConfigMaxShutdownTime[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 27, -1}; __UNUSED__ static int upsAsiUpsControlServerRequestShutdown[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 28, -1}; __UNUSED__ static int upsAdvConfigMinReturnRuntime[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 29, -1}; __UNUSED__ static int upsAdvConfigBasicSignalLowBatteryDuration[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 30, -1}; __UNUSED__ static int upsAdvConfigBypassPhaseLockRequired[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 31, -1}; __UNUSED__ static int upsAdvConfigOutputFreqSlewRate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 32, -1}; __UNUSED__ static int upsAdvConfigChargerLevel[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 33, -1}; __UNUSED__ static int upsAdvConfigBypassToleranceSetting[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 34, -1}; __UNUSED__ static int upsAdvConfigMainsSetting[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 35, -1}; __UNUSED__ static int upsAdvConfigACWiringSetting[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 36, -1}; __UNUSED__ static int upsAdvConfigUpperOutputVoltTolerance[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 37, -1}; __UNUSED__ static int upsAdvConfigLowerOutputVoltTolerance[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 38, -1}; __UNUSED__ static int upsAdvConfigUpperBypassVoltTolerance[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 39, -1}; __UNUSED__ static int upsAdvConfigLowerBypassVoltTolerance[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 40, -1}; __UNUSED__ static int upsAdvConfigOutofSyncBypassTransferDelay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 5, 2, 41, -1}; __UNUSED__ static int upsBasicControlConserveBattery[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 1, 1, -1}; __UNUSED__ static int upsAdvControlUpsOff[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 1, -1}; __UNUSED__ static int upsAdvControlRebootShutdownUps[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 2, -1}; __UNUSED__ static int upsAdvControlUpsSleep[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 3, -1}; __UNUSED__ static int upsAdvControlSimulatePowerFail[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 4, -1}; __UNUSED__ static int upsAdvControlFlashAndBeep[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 5, -1}; __UNUSED__ static int upsAdvControlTurnOnUPS[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 6, -1}; __UNUSED__ static int upsAdvControlBypassSwitch[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 7, -1}; __UNUSED__ static int upsAdvControlRebootUpsWithOrWithoutAC[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 8, -1}; __UNUSED__ static int upsAdvControlFirmwareUpdate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 6, 2, 9, -1}; __UNUSED__ static int upsAdvTestDiagnosticSchedule[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 1, -1}; __UNUSED__ static int upsAdvTestDiagnostics[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 2, -1}; __UNUSED__ static int upsAdvTestDiagnosticsResults[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 3, -1}; __UNUSED__ static int upsAdvTestLastDiagnosticsDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 4, -1}; __UNUSED__ static int upsAdvTestRuntimeCalibration[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 5, -1}; __UNUSED__ static int upsAdvTestCalibrationResults[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 6, -1}; __UNUSED__ static int upsAdvTestCalibrationDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 7, -1}; __UNUSED__ static int upsAdvTestDiagnosticTime[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 8, -1}; __UNUSED__ static int upsAdvTestDiagnosticDay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 7, 2, 9, -1}; __UNUSED__ static int upsCommStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 8, 1, -1}; __UNUSED__ static int upsPhaseResetMaxMinValues[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 1, 1, -1}; __UNUSED__ static int upsPhaseNumInputs[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 1, -1}; __UNUSED__ static int upsPhaseInputTableIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 2, 1, 1, -1}; __UNUSED__ static int upsPhaseNumInputPhases[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 2, 1, 2, -1}; __UNUSED__ static int upsPhaseInputVoltageOrientation[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 2, 1, 3, -1}; __UNUSED__ static int upsPhaseInputFrequency[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 2, 1, 4, -1}; __UNUSED__ static int upsPhaseInputType[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 2, 1, 5, -1}; __UNUSED__ static int upsPhaseInputName[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 2, 1, 6, -1}; __UNUSED__ static int upsPhaseInputPhaseTableIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 1, -1}; __UNUSED__ static int upsPhaseInputPhaseIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 2, -1}; __UNUSED__ static int upsPhaseInputVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 3, -1}; __UNUSED__ static int upsPhaseInputMaxVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 4, -1}; __UNUSED__ static int upsPhaseInputMinVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 5, -1}; __UNUSED__ static int upsPhaseInputCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 6, -1}; __UNUSED__ static int upsPhaseInputMaxCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 7, -1}; __UNUSED__ static int upsPhaseInputMinCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 8, -1}; __UNUSED__ static int upsPhaseInputPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 9, -1}; __UNUSED__ static int upsPhaseInputMaxPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 10, -1}; __UNUSED__ static int upsPhaseInputMinPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 2, 3, 1, 11, -1}; __UNUSED__ static int upsPhaseNumOutputs[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 1, -1}; __UNUSED__ static int upsPhaseOutputTableIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 2, 1, 1, -1}; __UNUSED__ static int upsPhaseNumOutputPhases[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 2, 1, 2, -1}; __UNUSED__ static int upsPhaseOutputVoltageOrientation[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 2, 1, 3, -1}; __UNUSED__ static int upsPhaseOutputFrequency[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 2, 1, 4, -1}; __UNUSED__ static int upsPhaseOutputPhaseTableIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 1, -1}; __UNUSED__ static int upsPhaseOutputPhaseIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 2, -1}; __UNUSED__ static int upsPhaseOutputVoltage[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 3, -1}; __UNUSED__ static int upsPhaseOutputCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 4, -1}; __UNUSED__ static int upsPhaseOutputMaxCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 5, -1}; __UNUSED__ static int upsPhaseOutputMinCurrent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 6, -1}; __UNUSED__ static int upsPhaseOutputLoad[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 7, -1}; __UNUSED__ static int upsPhaseOutputMaxLoad[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 8, -1}; __UNUSED__ static int upsPhaseOutputMinLoad[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 9, -1}; __UNUSED__ static int upsPhaseOutputPercentLoad[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 10, -1}; __UNUSED__ static int upsPhaseOutputMaxPercentLoad[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 11, -1}; __UNUSED__ static int upsPhaseOutputMinPercentLoad[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 12, -1}; __UNUSED__ static int upsPhaseOutputPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 13, -1}; __UNUSED__ static int upsPhaseOutputMaxPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 14, -1}; __UNUSED__ static int upsPhaseOutputMinPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 15, -1}; __UNUSED__ static int upsPhaseOutputPercentPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 16, -1}; __UNUSED__ static int upsPhaseOutputMaxPercentPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 17, -1}; __UNUSED__ static int upsPhaseOutputMinPercentPower[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 9, 3, 3, 1, 18, -1}; __UNUSED__ static int upsSCGMembershipGroupNumber[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 1, 1, -1}; __UNUSED__ static int upsSCGActiveMembershipStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 1, 2, -1}; __UNUSED__ static int upsSCGPowerSynchronizationDelayTime[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 1, 3, -1}; __UNUSED__ static int upsSCGReturnBatteryCapacityOffset[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 1, 4, -1}; __UNUSED__ static int upsSCGMultiCastIP[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 1, 5, -1}; __UNUSED__ static int upsSCGNumOfGroupMembers[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 2, 1, -1}; __UNUSED__ static int upsSCGStatusTableIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 2, 2, 1, 1, -1}; __UNUSED__ static int upsSCGMemberIP[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 2, 2, 1, 2, -1}; __UNUSED__ static int upsSCGACInputStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 2, 2, 1, 3, -1}; __UNUSED__ static int upsSCGACOutputStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 10, 2, 2, 1, 4, -1}; __UNUSED__ static int upsBasicStateOutputState[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 11, 1, 1, -1}; __UNUSED__ static int upsAdvStateAbnormalConditions[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 11, 2, 1, -1}; __UNUSED__ static int upsAdvStateSymmetra3PhaseSpecificFaults[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 11, 2, 2, -1}; __UNUSED__ static int upsAdvStateDP300ESpecificFaults[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 11, 2, 3, -1}; __UNUSED__ static int upsAdvStateSymmetraSpecificFaults[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 11, 2, 4, -1}; __UNUSED__ static int upsAdvStateSmartUPSSpecificFaults[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 11, 2, 5, -1}; __UNUSED__ static int upsAdvStateSystemMessages[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 11, 2, 6, -1}; __UNUSED__ static int upsOutletGroupStatusTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 1, 1, -1}; __UNUSED__ static int upsOutletGroupStatusIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 1, 2, 1, 1, -1}; __UNUSED__ static int upsOutletGroupStatusName[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 1, 2, 1, 2, -1}; __UNUSED__ static int upsOutletGroupStatusGroupState[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 1, 2, 1, 3, -1}; __UNUSED__ static int upsOutletGroupStatusCommandPending[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 1, 2, 1, 4, -1}; __UNUSED__ static int upsOutletGroupStatusOutletType[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 1, 2, 1, 5, -1}; __UNUSED__ static int upsOutletGroupConfigTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 1, -1}; __UNUSED__ static int upsOutletGroupConfigIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 1, -1}; __UNUSED__ static int upsOutletGroupConfigName[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 2, -1}; __UNUSED__ static int upsOutletGroupConfigPowerOnDelay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 3, -1}; __UNUSED__ static int upsOutletGroupConfigPowerOffDelay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 4, -1}; __UNUSED__ static int upsOutletGroupConfigRebootDuration[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 5, -1}; __UNUSED__ static int upsOutletGroupConfigMinReturnRuntime[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 6, -1}; __UNUSED__ static int upsOutletGroupConfigOutletType[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 7, -1}; __UNUSED__ static int upsOutletGroupConfigLoadShedControlSkipOffDelay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 8, -1}; __UNUSED__ static int upsOutletGroupConfigLoadShedControlAutoRestart[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 9, -1}; __UNUSED__ static int upsOutletGroupConfigLoadShedControlTimeOnBattery[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 10, -1}; __UNUSED__ static int upsOutletGroupConfigLoadShedControlRuntimeRemaining[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 11, -1}; __UNUSED__ static int upsOutletGroupConfigLoadShedControlInOverload[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 12, -1}; __UNUSED__ static int upsOutletGroupConfigLoadShedTimeOnBattery[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 13, -1}; __UNUSED__ static int upsOutletGroupConfigLoadShedRuntimeRemaining[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 2, 2, 1, 14, -1}; __UNUSED__ static int upsOutletGroupControlTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 3, 1, -1}; __UNUSED__ static int upsOutletGroupControlIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 3, 2, 1, 1, -1}; __UNUSED__ static int upsOutletGroupControlName[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 3, 2, 1, 2, -1}; __UNUSED__ static int upsOutletGroupControlCommand[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 3, 2, 1, 3, -1}; __UNUSED__ static int upsOutletGroupControlOutletType[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 12, 3, 2, 1, 4, -1}; __UNUSED__ static int upsDiagIMTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 1, -1}; __UNUSED__ static int upsDiagIMIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 1, -1}; __UNUSED__ static int upsDiagIMType[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 2, -1}; __UNUSED__ static int upsDiagIMStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 3, -1}; __UNUSED__ static int upsDiagIMFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 4, -1}; __UNUSED__ static int upsDiagIMSlaveFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 5, -1}; __UNUSED__ static int upsDiagIMHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 6, -1}; __UNUSED__ static int upsDiagIMSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 7, -1}; __UNUSED__ static int upsDiagIMManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 1, 2, 1, 8, -1}; __UNUSED__ static int upsDiagPMTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 2, 1, -1}; __UNUSED__ static int upsDiagPMIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 2, 2, 1, 1, -1}; __UNUSED__ static int upsDiagPMStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 2, 2, 1, 2, -1}; __UNUSED__ static int upsDiagPMFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 2, 2, 1, 3, -1}; __UNUSED__ static int upsDiagPMHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 2, 2, 1, 4, -1}; __UNUSED__ static int upsDiagPMSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 2, 2, 1, 5, -1}; __UNUSED__ static int upsDiagPMManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 2, 2, 1, 6, -1}; __UNUSED__ static int upsDiagBatteryTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 3, 1, -1}; __UNUSED__ static int upsDiagBatteryFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 3, 2, 1, 1, -1}; __UNUSED__ static int upsDiagBatteryIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 3, 2, 1, 2, -1}; __UNUSED__ static int upsDiagBatteryStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 3, 2, 1, 3, -1}; __UNUSED__ static int upsDiagBatterySerialNumber[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 3, 2, 1, 4, -1}; __UNUSED__ static int upsDiagBatteryFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 3, 2, 1, 5, -1}; __UNUSED__ static int upsDiagBatteryManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 3, 2, 1, 6, -1}; __UNUSED__ static int upsDiagBatteryType[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 3, 2, 1, 7, -1}; __UNUSED__ static int upsDiagSubSysFrameTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 1, -1}; __UNUSED__ static int upsDiagSubSysFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 2, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysFrameType[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 2, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysFrameFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 2, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysFrameHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 2, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysFrameSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 2, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysFrameManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 2, 1, 6, -1}; __UNUSED__ static int upsDiagSubSysIntBypSwitchTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 3, -1}; __UNUSED__ static int upsDiagSubSysIntBypSwitchFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 4, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysIntBypSwitchIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 4, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysIntBypSwitchStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 4, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysIntBypSwitchFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 4, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysIntBypSwitchHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 4, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysIntBypSwitchSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 4, 1, 6, -1}; __UNUSED__ static int upsDiagSubSysIntBypSwitchManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 4, 1, 7, -1}; __UNUSED__ static int upsDiagSubSysBattMonitorTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 5, -1}; __UNUSED__ static int upsDiagSubSysBattMonitorFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 6, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysBattMonitorIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 6, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysBattMonitorStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 6, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysBattMonitorFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 6, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysBattMonitorHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 6, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysBattMonitorSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 6, 1, 6, -1}; __UNUSED__ static int upsDiagSubSysBattMonitorManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 6, 1, 7, -1}; __UNUSED__ static int upsDiagSubSysExternalSwitchGearTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 7, -1}; __UNUSED__ static int upsDiagSubSysExternalSwitchGearFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 8, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysExternalSwitchGearIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 8, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysExternalSwitchGearStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 8, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysExternalSwitchGearFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 8, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysExternalSwitchGearHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 8, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysExternalSwitchGearSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 8, 1, 6, -1}; __UNUSED__ static int upsDiagSubSysExternalSwitchGearManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 8, 1, 7, -1}; __UNUSED__ static int upsDiagSubSysDisplayInterfaceCardTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 9, -1}; __UNUSED__ static int upsDiagSubSysDisplayInterfaceCardFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 10, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysDisplayInterfaceCardIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 10, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysDisplayInterfaceCardStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 10, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysDCCircuitBreakerTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 11, -1}; __UNUSED__ static int upsDiagSubSysDCCircuitBreakerFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 12, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysDCCircuitBreakerIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 12, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysDCCircuitBreakerStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 12, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysSystemPowerSupplyTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 13, -1}; __UNUSED__ static int upsDiagSubSysSystemPowerSupplyFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 14, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysSystemPowerSupplyIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 14, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysSystemPowerSupplyStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 14, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysSystemPowerSupplyFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 14, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysSystemPowerSupplyHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 14, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysSystemPowerSupplySerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 14, 1, 6, -1}; __UNUSED__ static int upsDiagSubSysSystemPowerSupplyManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 14, 1, 7, -1}; __UNUSED__ static int upsDiagSubSysXRCommunicationCardTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 15, -1}; __UNUSED__ static int upsDiagSubSysXRCommunicationCardFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 16, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysXRCommunicationCardIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 16, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysXRCommunicationCardStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 16, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysXRCommunicationCardFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 16, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysXRCommunicationCardSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 16, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysExternalPowerFrameBoardTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 17, -1}; __UNUSED__ static int upsDiagSubSysExternalPowerFrameBoardFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 18, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysExternalPowerFrameBoardIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 18, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysExternalPowerFrameBoardStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 18, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysChargerTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 19, -1}; __UNUSED__ static int upsDiagSubSysChargerFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 20, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysChargerIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 20, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysChargerStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 20, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysInverterTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 21, -1}; __UNUSED__ static int upsDiagSubSysInverterFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 22, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysInverterIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 22, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysInverterStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 22, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysInverterFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 22, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysInverterHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 22, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysInverterSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 22, 1, 6, -1}; __UNUSED__ static int upsDiagSubSysInverterManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 22, 1, 7, -1}; __UNUSED__ static int upsDiagSubSysPowerFactorCorrectionTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 23, -1}; __UNUSED__ static int upsDiagSubSysPowerFactorCorrectionFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 24, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysPowerFactorCorrectionIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 24, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysPowerFactorCorrectionStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 24, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysPowerFactorCorrectionFirmwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 24, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysPowerFactorCorrectionHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 24, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysPowerFactorCorrectionSerialNum[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 24, 1, 6, -1}; __UNUSED__ static int upsDiagSubSysPowerFactorCorrectionManufactureDate[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 24, 1, 7, -1}; __UNUSED__ static int upsDiagSubSysNetworkComCardTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 25, -1}; __UNUSED__ static int upsDiagSubSysNetworkComCardIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 26, 1, 1, -1}; __UNUSED__ static int upsDiagSubSysNetworkComCardModelNumber[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 26, 1, 2, -1}; __UNUSED__ static int upsDiagSubSysNetworkComCardSerialNumber[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 26, 1, 3, -1}; __UNUSED__ static int upsDiagSubSysNetworkComCardDateOfManufacture[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 26, 1, 4, -1}; __UNUSED__ static int upsDiagSubSysNetworkComCardHardwareRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 26, 1, 5, -1}; __UNUSED__ static int upsDiagSubSysNetworkComCardFirmwareAppRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 26, 1, 6, -1}; __UNUSED__ static int upsDiagSubSysNetworkComCardFirmwareAppOSRev[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 4, 26, 1, 7, -1}; __UNUSED__ static int upsDiagSwitchGearStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 1, -1}; __UNUSED__ static int upsDiagSwitchGearInputSwitchStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 2, -1}; __UNUSED__ static int upsDiagSwitchGearOutputSwitchStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 3, -1}; __UNUSED__ static int upsDiagSwitchGearBypassSwitchStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 4, -1}; __UNUSED__ static int upsDiagSwitchGearBypassInputSwitchStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 5, -1}; __UNUSED__ static int upsDiagSwitchGearBreakerTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 6, -1}; __UNUSED__ static int switchgearBreakerIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 7, 1, 1, -1}; __UNUSED__ static int switchgearBreakerPresent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 7, 1, 2, -1}; __UNUSED__ static int switchgearBreakerName[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 7, 1, 3, -1}; __UNUSED__ static int upsDiagSubFeedBreakerTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 8, -1}; __UNUSED__ static int subfeedBreakerIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 9, 1, 1, -1}; __UNUSED__ static int subfeedBreakerPresent[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 9, 1, 2, -1}; __UNUSED__ static int subfeedBreakerRating[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 9, 1, 3, -1}; __UNUSED__ static int subfeedBreakerUpperAcceptPowerWarning[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 1, 9, 1, 4, -1}; __UNUSED__ static int upsDiagMCCBBoxStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 2, 1, -1}; __UNUSED__ static int upsDiagTransformerStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 5, 3, 1, -1}; __UNUSED__ static int upsDiagComBusInternalMIMStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 6, 1, -1}; __UNUSED__ static int upsDiagComBusInternalRIMStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 6, 2, -1}; __UNUSED__ static int upsDiagComBusMIMtoRIMStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 6, 3, -1}; __UNUSED__ static int upsDiagComBusExternalMIMStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 6, 4, -1}; __UNUSED__ static int upsDiagComBusExternalRIMStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 13, 6, 5, -1}; __UNUSED__ static int upsParallelSysLocalAddress[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 14, 1, -1}; __UNUSED__ static int upsParallelSysRemoteAddress[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 14, 2, -1}; __UNUSED__ static int upsParallelSysRedundancy[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 14, 3, -1}; __UNUSED__ static int upsIOFrameLayoutPositionID[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 1, -1}; __UNUSED__ static int upsBottomFeedFrameLayoutPositionID[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 2, -1}; __UNUSED__ static int upsSwitchGearLayoutPositionID[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 3, -1}; __UNUSED__ static int upsBatteryFrameLayoutTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 4, -1}; __UNUSED__ static int batteryFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 5, 1, 1, -1}; __UNUSED__ static int batteryFramePositionID[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 5, 1, 2, -1}; __UNUSED__ static int upsSideCarFrameLayoutTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 6, -1}; __UNUSED__ static int sideCarFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 7, 1, 1, -1}; __UNUSED__ static int sideCarFramePositionID[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 7, 1, 2, -1}; __UNUSED__ static int upsPowerFrameLayoutTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 8, -1}; __UNUSED__ static int powerFrameIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 9, 1, 1, -1}; __UNUSED__ static int powerFramePositionID[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 15, 9, 1, 2, -1}; __UNUSED__ static int upsIntegratedATSSelectedSource[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 1, -1}; __UNUSED__ static int upsIntegratedATSPreferredSource[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 2, -1}; __UNUSED__ static int upsIntegratedATSUpsReturnStaggering[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 3, -1}; __UNUSED__ static int upsIntegratedATSSourceTableSize[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 4, -1}; __UNUSED__ static int upsIntegratedATSSourceIndex[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 5, 1, 1, -1}; __UNUSED__ static int upsIntegratedATSSourceName[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 5, 1, 2, -1}; __UNUSED__ static int upsIntegratedATSSourceStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 5, 1, 3, -1}; __UNUSED__ static int upsIntegratedATSLineFailDelay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 5, 1, 4, -1}; __UNUSED__ static int upsIntegratedATSLineStabilityDelay[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 1, 16, 5, 1, 5, -1}; __UNUSED__ static int mUpsEnvironAmbientTemperature[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 1, 1, -1}; __UNUSED__ static int mUpsEnvironRelativeHumidity[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 1, 2, -1}; __UNUSED__ static int mUpsEnvironAmbientTemperature2[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 1, 3, -1}; __UNUSED__ static int mUpsEnvironRelativeHumidity2[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 1, 4, -1}; __UNUSED__ static int mUpsContactNumContacts[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 2, 1, -1}; __UNUSED__ static int mUpsContactTableContactNumber[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 2, 2, 1, 1, -1}; __UNUSED__ static int mUpsContactTableNormalState[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 2, 2, 1, 2, -1}; __UNUSED__ static int mUpsContactTableDescription[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 2, 2, 1, 3, -1}; __UNUSED__ static int mUpsContactTableMonitoringStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 2, 2, 1, 4, -1}; __UNUSED__ static int mUpsContactTableCurrentStatus[] = {1, 3, 6, 1, 4, 1, 318, 1, 1, 2, 2, 2, 1, 5, -1}; #endif apcupsd-3.14.14/src/drivers/snmplite/asn.cpp000066400000000000000000000374661274230402600207300ustar00rootroot00000000000000/* * asn.cpp * * ASN.1 type classes */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "asn.h" #include #include using namespace Asn; // ***************************************************************************** // Object // ***************************************************************************** Object *Object::Demarshal(unsigned char *&buffer, unsigned int &buflen) { // Must have at least one byte to work with if (buflen < 1) return NULL; // Extract type code from stream Identifier type = (Identifier)*buffer++; buflen--; // Create proper object based on type code Object *obj; switch (type) { case INTEGER: case COUNTER: case GAUGE: case TIMETICKS: obj = new Integer(type); break; case OCTETSTRING: case IPADDRESS: obj = new OctetString(); break; case OBJECTID: obj = new ObjectId(); break; case NULLL: obj = new Null(); break; case SEQUENCE: case GET_REQ_PDU: case GETNEXT_REQ_PDU: case GET_RSP_PDU: case TRAP_PDU: obj = new Sequence(type); break; default: printf("UNKNOWN ASN type=0x%02x\n", type); obj = NULL; break; } // Have the object demarshal itself from the stream if (obj && !obj->demarshal(buffer, buflen)) { delete obj; obj = NULL; } return obj; } int Object::numbits(unsigned int num) const { if (num == 0) return 1; int bits = 0; while (num) { bits++; num >>= 1; } return bits; } bool Object::marshalLength( unsigned int len, unsigned char *&buffer, unsigned int &buflen) const { // Compute number of bytes required to store length unsigned int bits = numbits(len); unsigned int datalen; if (bits <= 7) datalen = 1; else datalen = (bits + 7) / 8 + 1; // If no buffer provided, just return number of bytes required if (!buffer) { buflen += datalen; return true; } // Fail if not enough space remaining in buffer if (buflen < datalen) return false; // If using long form, begin with byte count if (datalen > 1) *buffer++ = (datalen - 1) | 0x80; // Encode length bytes switch (datalen) { case 5: *buffer++ = (len >> 24) & 0xff; case 4: *buffer++ = (len >> 16) & 0xff; case 3: *buffer++ = (len >> 8) & 0xff; case 2: case 1: *buffer++ = len & 0xff; break; } return true; } bool Object::marshalType(unsigned char *&buffer, unsigned int &buflen) const { // If no buffer provided, just return number of bytes required if (!buffer) { buflen++; return true; } // Fail if not enough room for data if (buflen < 1) return false; buflen--; // Store type directly in stream *buffer++ = _type; return true; } bool Object::demarshalLength( unsigned char *&buffer, unsigned int &buflen, unsigned int &vallen) const { // Must have at least one byte to work with if (buflen < 1) return false; unsigned int datalen = *buffer++; buflen--; // Values less than 128 are stored directly in the first (only) byte if (datalen < 128) { vallen = datalen; return true; } // For values > 128, first byte-128 indicates number of bytes to follow // Bail if not enough data for additional bytes datalen -= 128; if (buflen < datalen) return false; buflen -= datalen; // Read data bytes vallen = 0; while (datalen--) { vallen <<= 8; vallen |= *buffer++; } return true; } // ***************************************************************************** // Integer // ***************************************************************************** bool Integer::Marshal(unsigned char *&buffer, unsigned int &buflen) const { // Marshal the type code if (!marshalType(buffer, buflen)) return false; // Calculate the number of bytes it will require to store the value unsigned int datalen = 4; unsigned int tmp = _value; while (datalen > 1) { if (( _signed && (tmp & 0xff800000) != 0xff800000) || (!_signed && (tmp & 0xff800000) != 0x00000000)) break; tmp <<= 8; datalen--; } // Special case for unsigned value with MSb set if (!_signed && datalen == 4 && (tmp & 0x80000000)) datalen = 5; // Marshal the length if (!marshalLength(datalen, buffer, buflen)) return false; // If no buffer provided, just return number of bytes required if (!buffer) { buflen += datalen; return true; } // Fail if not enough room for data if (buflen < datalen) return false; buflen -= datalen; // Marshal the value itself switch (datalen) { case 5: *buffer++ = 0; case 4: *buffer++ = (_value >> 24) & 0xff; case 3: *buffer++ = (_value >> 16) & 0xff; case 2: *buffer++ = (_value >> 8) & 0xff; case 1: *buffer++ = _value & 0xff; } return true; } bool Integer::demarshal(unsigned char *&buffer, unsigned int &buflen) { // Unmarshal the data length unsigned int datalen; if (!demarshalLength(buffer, buflen, datalen) || datalen < 1 || datalen > 4 || buflen < datalen) { return false; } buflen -= datalen; // Determine signedness if (*buffer & 0x80) { // Start with all 1s so result will be sign-extended _value = (unsigned int)-1; _signed = true; } else { _value = 0; _signed = false; } // Unmarshal the data while (datalen--) { _value <<= 8; _value |= *buffer++; } return true; } // ***************************************************************************** // OctetString // ***************************************************************************** OctetString::OctetString(const char *value) : Object(OCTETSTRING), _data(NULL) { assign((const unsigned char *)value, strlen(value)); } OctetString::OctetString(const unsigned char *value, unsigned int len) : Object(OCTETSTRING), _data(NULL) { assign(value, len); } OctetString::OctetString(const OctetString &rhs) : Object(OCTETSTRING), _data(NULL) { assign(rhs._data, rhs._len); } OctetString &OctetString::operator=(const OctetString &rhs) { if (&rhs != this) assign(rhs._data, rhs._len); return *this; } bool OctetString::Marshal(unsigned char *&buffer, unsigned int &buflen) const { // Marshal the type code if (!marshalType(buffer, buflen)) return false; // Marshal the length if (!marshalLength(_len, buffer, buflen)) return false; // If no buffer provided, just return number of bytes required if (!buffer) { buflen += _len; return true; } // Bail if not enough room for data if ((unsigned int)buflen < _len) return false; buflen -= _len; // Marshal data memcpy(buffer, _data, _len); buffer += _len; return true; } bool OctetString::demarshal(unsigned char *&buffer, unsigned int &buflen) { // Unmarshal the data length unsigned int datalen; if (!demarshalLength(buffer, buflen, datalen) || datalen < 1 || buflen < datalen) { return false; } buflen -= datalen; // Unmarshal the data assign(buffer, datalen); buffer += datalen; return true; } void OctetString::assign(const unsigned char *data, unsigned int len) { delete [] _data; _data = new unsigned char[len+1]; memcpy(_data, data, len); _data[len] = '\0'; _len = len; } // ***************************************************************************** // ObjectId // ***************************************************************************** ObjectId::ObjectId(const int oid[]) : Object(OBJECTID), _value(NULL) { assign(oid); } ObjectId::ObjectId(const ObjectId &rhs) : Object(OBJECTID), _value(NULL) { assign(rhs._value, rhs._count); } ObjectId &ObjectId::operator=(const ObjectId &rhs) { if (&rhs != this) assign(rhs._value, rhs._count); return *this; } ObjectId &ObjectId::operator=(const int oid[]) { if (oid != _value) assign(oid); return *this; } void ObjectId::assign(const int oid[]) { unsigned int count = 0; while (oid[count] != -1) count++; assign(oid, count); } void ObjectId::assign(const int oid[], unsigned int count) { delete [] _value; _value = NULL; _count = count; if (_count) { _value = new int[_count]; memcpy(_value, oid, _count*sizeof(int)); } } bool ObjectId::operator==(const ObjectId &rhs) const { if (_count != rhs._count) return false; for (unsigned int i = 0; i < _count; i++) { if (_value[i] != rhs._value[i]) return false; } return true; } bool ObjectId::operator==(const int oid[]) const { unsigned int i; for (i = 0; i < _count && oid[i] != -1; i++) { if (_value[i] != oid[i]) return false; } return i == _count && oid[i] == -1; } // Same as operator== except we're allowed to be longer than the parameter bool ObjectId::IsChildOf(const int oid[]) { unsigned int i; for (i = 0; i < _count && oid[i] != -1; i++) { if (_value[i] != oid[i]) return false; } return i < _count && oid[i] == -1; } bool ObjectId::Marshal(unsigned char *&buffer, unsigned int &buflen) const { // Protect from trying to marshal an empty object if (!_value || _count < 2) return false; // Marshal the type code if (!marshalType(buffer, buflen)) return false; // ASN.1 requires a special case for first two identifiers unsigned int cnt = _count-1; unsigned int vals[cnt]; vals[0] = _value[0] * 40 + _value[1]; for (unsigned int i = 2; i < _count; i++) vals[i-1] = _value[i]; // Calculate number of octets required to store data // We can only store 7 bits of data in each octet, so round accordingly unsigned int datalen = 0; for (unsigned int i = 0; i < cnt; i++) datalen += (numbits(vals[i]) + 6) / 7; // Marshal the length if (!marshalLength(datalen, buffer, buflen)) return false; // If no buffer provided, just return number of bytes required if (!buffer) { buflen += datalen; return true; } // Bail if data bytes will not fit if (buflen < datalen) return false; buflen -= datalen; // Write data: 7 data bits per octet, bit 7 set on all but final octet for (unsigned int i = 0; i < cnt; i++) { unsigned int val = vals[i]; unsigned int noctets = (numbits(val) + 6) / 7; switch (noctets) { case 5: *buffer++ = ((val >> 28) & 0x7f) | 0x80; case 4: *buffer++ = ((val >> 21) & 0x7f) | 0x80; case 3: *buffer++ = ((val >> 14) & 0x7f) | 0x80; case 2: *buffer++ = ((val >> 7) & 0x7f) | 0x80; case 1: case 0: *buffer++ = val & 0x7f; } } return true; } bool ObjectId::demarshal(unsigned char *&buffer, unsigned int &buflen) { // Unmarshal the data length unsigned int datalen; if (!demarshalLength(buffer, buflen, datalen) || datalen < 1 || buflen < datalen) { return false; } buflen -= datalen; // Allocate new value array, sized for worst case. +1 is because of // ASN.1 special case of compressing first two ids into one octet. delete [] _value; _value = new int[datalen+1]; // Unmarshal identifier values unsigned int i = 0; while (datalen) { // Accumulate octets into this identifier _value[i] = 0; unsigned int val; do { datalen--; val = *buffer++; _value[i] <<= 7; _value[i] |= val & 0x7f; } while (datalen && val & 0x80); // Handle special case for first two ids if (i++ == 0) { _value[1] = _value[0] % 40; _value[0] /= 40; i++; } } _count = i; return true; } // ***************************************************************************** // Null // ***************************************************************************** bool Null::Marshal(unsigned char *&buffer, unsigned int &buflen) const { // Marshal the type code if (!marshalType(buffer, buflen)) return false; // Marshal the length if (!marshalLength(0, buffer, buflen)) return false; return true; } bool Null::demarshal(unsigned char *&buffer, unsigned int &buflen) { // Unmarshal the data length unsigned int datalen; return demarshalLength(buffer, buflen, datalen) && datalen == 0; } // ***************************************************************************** // Sequence // ***************************************************************************** Sequence::Sequence(Identifier type) : Object(type), _data(NULL), _size(0) { } Sequence::~Sequence() { clear(); } Sequence::Sequence(const Sequence &rhs) : Object(rhs._type), _data(NULL) { assign(rhs); } void Sequence::clear() { for (unsigned int i = 0; i < _size; i++) delete _data[i]; delete [] _data; _data = NULL; _size = 0; } bool Sequence::Marshal(unsigned char *&buffer, unsigned int &buflen) const { // Marshal the type code if (!marshalType(buffer, buflen)) return false; // Need to calculate the length of the marshalled sequence. // Do so by passing a NULL buffer to Marshal() which will // accumulate total length in buflen parameter. unsigned int datalen = 0; unsigned char *buf = NULL; for (unsigned int i = 0; i < _size; ++i) { if (!_data[i]->Marshal(buf, datalen)) return false; } // Now marshal the length itself if (!marshalLength(datalen, buffer, buflen)) return false; // If no buffer provided, just return number of bytes required if (!buffer) { buflen += datalen; return true; } // Marshal all items in the sequence for (unsigned int i = 0; i < _size; ++i) { if (!_data[i]->Marshal(buffer, buflen)) return false; } return true; } bool Sequence::demarshal(unsigned char *&buffer, unsigned int &buflen) { // Free any existing data clear(); // Unmarshal the sequence data length unsigned int datalen; if (!demarshalLength(buffer, buflen, datalen) || datalen < 1 || buflen < datalen) { return false; } // Unmarshal items from the stream until sequence data is exhausted unsigned char *start = buffer; while (datalen) { Object *obj = Object::Demarshal(buffer, datalen); if (!obj) return false; Append(obj); } buflen -= buffer-start; return true; } void Sequence::Append(Object *obj) { // realloc ... not efficient, but easy Object **tmp = new Object *[_size+1]; if (_data) { memcpy(tmp, _data, _size * sizeof(_data[0])); delete [] _data; } tmp[_size++] = obj; _data = tmp; } Object *Sequence::operator[](unsigned int idx) { if (idx >= _size) return NULL; return _data[idx]; } Sequence &Sequence::operator=(const Sequence &rhs) { if (this != &rhs) assign(rhs); return *this; } void Sequence::assign(const Sequence &rhs) { clear(); _type = rhs._type; _size = rhs._size; _data = new Object *[_size]; for (unsigned int i = 0; i < _size; i++) _data[i] = rhs._data[i]->copy(); } apcupsd-3.14.14/src/drivers/snmplite/asn.h000066400000000000000000000217751274230402600203710ustar00rootroot00000000000000/* * asn.h * * ASN.1 type classes */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __ASN_H #define __ASN_H #include "astring.h" #include "alist.h" namespace Asn { // Class field static const unsigned char UNIVERSAL = 0x00; static const unsigned char APPLICATION = 0x40; static const unsigned char CONTEXT = 0x80; static const unsigned char PRIVATE = 0xC0; // Primitive/Constructed field static const unsigned char CONSTRUCTED = 0x20; static const unsigned char PRIMITIVE = 0x00; // Built-in types from ASN.1 typedef unsigned char Identifier; static const Identifier INTEGER = UNIVERSAL | PRIMITIVE | 0x02; static const Identifier BITSTRING = UNIVERSAL | PRIMITIVE | 0x03; static const Identifier OCTETSTRING = UNIVERSAL | PRIMITIVE | 0x04; static const Identifier NULLL = UNIVERSAL | PRIMITIVE | 0x05; static const Identifier OBJECTID = UNIVERSAL | PRIMITIVE | 0x06; static const Identifier SEQUENCE = UNIVERSAL | CONSTRUCTED | 0x10; // SNMP-specific types static const Identifier IPADDRESS = APPLICATION | PRIMITIVE | 0x00; static const Identifier COUNTER = APPLICATION | PRIMITIVE | 0x01; static const Identifier GAUGE = APPLICATION | PRIMITIVE | 0x02; static const Identifier TIMETICKS = APPLICATION | PRIMITIVE | 0x03; static const Identifier GET_REQ_PDU = CONTEXT | CONSTRUCTED | 0x00; static const Identifier GETNEXT_REQ_PDU = CONTEXT | CONSTRUCTED | 0x01; static const Identifier GET_RSP_PDU = CONTEXT | CONSTRUCTED | 0x02; static const Identifier SET_REQ_PDU = CONTEXT | CONSTRUCTED | 0x03; static const Identifier TRAP_PDU = CONTEXT | CONSTRUCTED | 0x04; // ************************************************************************** // Forward declarations // ************************************************************************** class Integer; class ObjectId; class OctetString; class Sequence; // ************************************************************************** // Object // ************************************************************************** class Object { public: Object(Identifier type): _type(type) {} virtual ~Object() {} static Object *Demarshal(unsigned char *&buffer, unsigned int &buflen); Identifier Type() const { return _type; } Integer *AsInteger() { return (Integer*) this; } ObjectId *AsObjectId() { return (ObjectId*) this; } OctetString *AsOctetString() { return (OctetString*)this; } Sequence *AsSequence() { return (Sequence*) this; } virtual bool IsInteger() { return false; } virtual bool IsObjectId() { return false; } virtual bool IsOctetString() { return false; } virtual bool IsSequence() { return false; } virtual bool Marshal( unsigned char *&buffer, unsigned int &buflen) const = 0; virtual Object *copy() const = 0; protected: virtual bool demarshal(unsigned char *&buffer, unsigned int &buflen) = 0; bool marshalType(unsigned char *&buffer, unsigned int &buflen) const; bool marshalLength( unsigned int len, unsigned char *&buffer, unsigned int &buflen) const; bool demarshalLength( unsigned char *&buffer, unsigned int &buflen, unsigned int &vallen) const; int numbits(unsigned int num) const; Identifier _type; }; // ************************************************************************** // Integer // ************************************************************************** class Integer: public Object { public: Integer(Identifier id = INTEGER) : Object(id), _value(0), _signed(false) {} Integer(int value) : Object(INTEGER), _value(value), _signed(value < 0) {} virtual ~Integer() {} unsigned int UintValue() const { return _value; } int IntValue() const { return (int)_value; } Integer &operator=(int value) { _value = value; _signed = value < 0; return *this; } Integer &operator=(unsigned int value) { _value = value; _signed = false; return *this; } virtual Object *copy() const { return new Integer(*this); } virtual bool Marshal(unsigned char *&buffer, unsigned int &buflen) const; virtual bool IsInteger() { return true; } protected: virtual bool demarshal(unsigned char *&buffer, unsigned int &buflen); unsigned int _value; bool _signed; }; // ************************************************************************** // OctetString // ************************************************************************** class OctetString: public Object { public: OctetString() : Object(OCTETSTRING), _data(NULL), _len(0) {} OctetString(const char *value); OctetString(const unsigned char *value, unsigned int len); virtual ~OctetString() { delete [] _data; } OctetString(const OctetString &rhs); OctetString &operator=(const OctetString &rhs); const unsigned char *Value() const { return _data; } const unsigned int Length() const { return _len; } operator const char *() const { return (const char *)_data; } virtual Object *copy() const { return new OctetString(*this); } virtual bool Marshal(unsigned char *&buffer, unsigned int &buflen) const; virtual bool IsOctetString() { return true; } protected: virtual bool demarshal(unsigned char *&buffer, unsigned int &buflen); void assign(const unsigned char *data, unsigned int len); unsigned char *_data; unsigned int _len; }; // ************************************************************************** // ObjectId // ************************************************************************** class ObjectId: public Object { public: ObjectId() : Object(OBJECTID), _value(NULL), _count(0) {} ObjectId(const int oid[]); virtual ~ObjectId() { delete [] _value; } ObjectId(const ObjectId &rhs); ObjectId &operator=(const ObjectId &rhs); ObjectId &operator=(const int oid[]); bool operator==(const ObjectId &rhs) const; bool operator==(const int oid[]) const; bool operator!=(const ObjectId &rhs) const { return !(*this == rhs); } bool operator!=(const int oid[]) const { return !(*this == oid); } bool IsChildOf(const int oid[]); virtual Object *copy() const { return new ObjectId(*this); } virtual bool Marshal(unsigned char *&buffer, unsigned int &buflen) const; virtual bool IsObjectId() { return true; } protected: virtual bool demarshal(unsigned char *&buffer, unsigned int &buflen); void assign(const int oid[]); void assign(const int oid[], unsigned int count); int *_value; unsigned int _count; }; // ************************************************************************** // Null // ************************************************************************** class Null: public Object { public: Null() : Object(NULLL) {} virtual ~Null() {} virtual Object *copy() const { return new Null(*this); } virtual bool Marshal(unsigned char *&buffer, unsigned int &buflen) const; protected: virtual bool demarshal(unsigned char *&buffer, unsigned int &buflen); }; // ************************************************************************** // Sequence // ************************************************************************** class Sequence: public Object { public: Sequence(Identifier type = SEQUENCE); virtual ~Sequence(); Sequence(const Sequence &rhs); Sequence &operator=(const Sequence &rhs); unsigned int Size() { return _size; } Object *operator[](unsigned int idx); void Append(Object *obj); virtual Object *copy() const { return new Sequence(*this); } virtual bool Marshal(unsigned char *&buffer, unsigned int &buflen) const; virtual bool IsSequence() { return true; } protected: virtual bool demarshal(unsigned char *&buffer, unsigned int &buflen); void assign(const Sequence &rhs); void clear(); Object **_data; unsigned int _size; }; }; #endif apcupsd-3.14.14/src/drivers/snmplite/mge-mib.cpp000066400000000000000000000305451274230402600214530ustar00rootroot00000000000000/* * mge_mib.cpp * * CI -> OID mapping for SNMP Lite UPS driver */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "snmplite-common.h" #include "mibs.h" #include "mge-oids.h" using namespace Asn; static struct CiOidMap MGE_CiOidMap[] = { // CI OID type dynamic? {CI_UPSMODEL, upsmgIdentFamilyName, OCTETSTRING, false}, {CI_STATUS, upsmgOutputOnBattery, INTEGER, true }, {CI_WHY_BATT, upsmgInputLineFailCause, INTEGER, true }, {CI_ST_STAT, upsmgTestDiagResult, INTEGER, true }, {CI_VLINE, mginputVoltage, SEQUENCE, true }, {CI_VMAX, mginputMaximumVoltage, SEQUENCE, true }, {CI_VMIN, mginputMinimumVoltage, SEQUENCE, true }, {CI_VOUT, mgoutputVoltage, SEQUENCE, true }, {CI_BATTLEV, upsmgBatteryLevel, INTEGER, true }, {CI_VBATT, upsmgBatteryVoltage, INTEGER, true }, {CI_LOAD, mgoutputLoadPerPhase, SEQUENCE, true }, {CI_FREQ, mginputFrequency, SEQUENCE, true }, {CI_RUNTIM, upsmgBatteryRemainingTime, INTEGER, true }, {CI_ITEMP, upsmgBatteryTemperature, INTEGER, true }, {CI_DWAKE, mgreceptacleRestartDelay, INTEGER, false}, {CI_DSHUTD, upsmgConfigSysShutDuration, INTEGER, false}, {CI_LTRANS, upsmgConfigLowTransfer, INTEGER, false}, {CI_HTRANS, upsmgConfigHighTransfer, INTEGER, false}, {CI_RETPCT, upsmgConfigMinRechargeLevel, INTEGER, false}, {CI_AlarmTimer, upsmgConfigAlarmTimeDelay, INTEGER, false}, // before CI_DALARM ! {CI_DALARM, upsmgConfigAlarmAudible, INTEGER, false}, {CI_DLBATT, upsmgConfigLowBatteryTime, INTEGER, false}, // {CI_IDEN, upsmgIdentModelName, OCTETSTRING, false}, {CI_STESTI, upsmgTestBatterySchedule, INTEGER, false}, {CI_SERNO, upsmgIdentSerialNumber, OCTETSTRING, false}, {CI_NOMBATTV, upsmgConfigNominalBatteryVoltage, INTEGER, false}, {CI_HUMID, upsmgEnvironAmbientHumidity, INTEGER, true }, {CI_REVNO, upsmgIdentFirmwareVersion, OCTETSTRING, false}, // Version + SN of net card {CI_ATEMP, upsmgEnvironAmbientTemp, INTEGER, true }, {CI_NOMOUTV, upsmgConfigOutputNominalVoltage, INTEGER, false}, {CI_Boost, upsmgOutputOnBoost, INTEGER, true }, {CI_Trim, upsmgOutputOnBuck, INTEGER, true }, {CI_Overload, upsmgOutputOverLoad, INTEGER, true }, {CI_NeedReplacement, upsmgBatteryReplacement, INTEGER, true }, {CI_LowBattery, upsmgBatteryLowBattery, INTEGER, true }, {-1, NULL, false} /* END OF TABLE */ }; static void mge_update_ci(UPSINFO *ups, int ci, Snmp::Variable &data) { static int alarmtimer = 0; switch (ci) { case CI_UPSMODEL: Dmsg(80, "Got CI_UPSMODEL: %s\n", data.str.str()); strlcpy(ups->upsmodel, data.str, sizeof(ups->upsmodel)); break; case CI_STATUS: Dmsg(80, "Got CI_STATUS: %d\n", data.u32); if (data.u32 == 1) { ups->set_onbatt(); ups->clear_online(); } else { ups->set_online(); ups->clear_onbatt(); } break; case CI_WHY_BATT: switch (data.u32) { case 1: ups->lastxfer = XFER_NONE; break; case 2: /* voltage out of tolerance */ ups->lastxfer = XFER_NOTCHSPIKE; break; case 3: /* freq out of tolerance */ ups->lastxfer = XFER_FREQ; break; case 4: /* No power on line */ default: ups->lastxfer = XFER_UNKNOWN; break; } break; case CI_ST_STAT: Dmsg(80, "Got CI_ST_STAT: %d\n", data.u32); switch (data.u32) { case 1: /* Passed */ ups->testresult = TEST_PASSED; break; case 2: /* Failed */ ups->testresult = TEST_FAILED; break; default: ups->testresult = TEST_UNKNOWN; break; } break; case CI_VLINE: // take only first value of sequence if (data.seq.begin() != data.seq.end()) { ups->LineVoltage = ((double)data.seq.begin()->u32) / 10; for (alist::iterator iter = data.seq.begin(); iter != data.seq.end(); ++iter) Dmsg(80, "Got CI_VLINE: %d\n", iter->u32); } else { Dmsg(80, "CI_VLINE: empty reply received"); } break; case CI_VMAX: // take maximum of sequence values if (data.seq.begin() != data.seq.end()) { ups->LineMax = 0; for (alist::iterator iter = data.seq.begin(); iter != data.seq.end(); ++iter) { Dmsg(80, "Got CI_VMAX: %d\n", iter->u32); if (ups->LineMax < iter->u32) ups->LineMax = iter->u32; } ups->LineMax /= 10; Dmsg(80, "CI_VMAX= %g\n", ups->LineMax); } else { Dmsg(80, "CI_VMAX: empty reply received"); } break; case CI_VMIN: // take minimum of sequence values if (data.seq.begin() != data.seq.end()) { ups->LineMin = data.seq.begin()->u32; for (alist::iterator iter = data.seq.begin(); iter != data.seq.end(); ++iter) { Dmsg(80, "Got CI_VMIN: %d\n", iter->u32); if (ups->LineMin > iter->u32) ups->LineMin = iter->u32; } ups->LineMin /= 10; Dmsg(80, "CI_VMIN= %g\n", ups->LineMin); } else { Dmsg(80, "CI_VMIN: empty reply received"); } break; case CI_VOUT: // take only first value of sequence if (data.seq.begin() != data.seq.end()) { ups->OutputVoltage = ((double)data.seq.begin()->u32) / 10; for (alist::iterator iter = data.seq.begin(); iter != data.seq.end(); ++iter) Dmsg(80, "Got CI_VOUT: %d\n", iter->u32); } else { Dmsg(80, "CI_VMIN: empty reply received"); } break; case CI_BATTLEV: Dmsg(80, "Got CI_BATTLEV: %d\n", data.u32); ups->BattChg = data.u32; break; case CI_VBATT: Dmsg(80, "Got CI_VBATT: %d\n", data.u32); ups->BattVoltage = ((double)data.u32) / 10; break; case CI_LOAD: // caclulate the arithmetic average of all sequence values if (data.seq.begin() != data.seq.end()) { ups->UPSLoad = 0; for (alist::iterator iter = data.seq.begin(); iter != data.seq.end(); ++iter) { Dmsg(80, "Got CI_LOAD: %d\n", iter->u32); ups->UPSLoad += iter->u32; } ups->UPSLoad /= data.seq.size(); Dmsg(80, "CI_LOAD= %g\n", ups->UPSLoad); } else { Dmsg(80, "CI_LOAD: empty reply received"); } break; case CI_FREQ: // take only first value of sequence if (data.seq.begin() != data.seq.end()) { ups->LineFreq = ((double)data.seq.begin()->u32) / 10; for (alist::iterator iter = data.seq.begin(); iter != data.seq.end(); ++iter) Dmsg(80, "Got CI_FREQ: %d\n", iter->u32); } else { Dmsg(80, "CI_FREQ: empty reply received"); } break; case CI_RUNTIM: Dmsg(80, "Got CI_RUNTIM: %d\n", data.u32); ups->TimeLeft = ((double)data.u32) / 60; break; case CI_ITEMP: Dmsg(80, "Got CI_ITEMP: %d\n", data.u32); ups->UPSTemp = data.u32; break; case CI_DWAKE: Dmsg(80, "Got CI_DWAKE: %d\n", data.u32); ups->dwake = data.u32; break; case CI_DSHUTD: Dmsg(80, "Got CI_DSHUTD: %d\n", data.u32); ups->dshutd = data.u32; break; case CI_LTRANS: Dmsg(80, "Got CI_LTRANS: %d\n", data.u32); ups->lotrans = data.u32; break; case CI_HTRANS: Dmsg(80, "Got CI_HTRANS: %d\n", data.u32); ups->hitrans = data.u32; break; case CI_RETPCT: Dmsg(80, "Got CI_RETPCT: %d\n", data.u32); ups->rtnpct = data.u32; break; case CI_DALARM: Dmsg(80, "Got CI_DALARM: %d\n", data.u32); if (data.u32 == 1) if (alarmtimer) strlcpy(ups->beepstate, "Timed", sizeof(ups->beepstate)); else strlcpy(ups->beepstate, "NoDelay", sizeof(ups->beepstate)); else strlcpy(ups->beepstate, "NoAlarm", sizeof(ups->beepstate)); break; case CI_DLBATT: Dmsg(80, "Got CI_DLBATT: %d\n", data.u32); ups->dlowbatt = data.u32; break; case CI_IDEN: Dmsg(80, "Got CI_IDEN: %s\n", data.str.str()); strlcpy(ups->upsname, data.str, sizeof(ups->upsname)); break; case CI_STESTI: Dmsg(80, "Got CI_STESTI: %d\n", data.u32); switch (data.u32) { case 2: strlcpy(ups->selftest, "weekly", sizeof(ups->selftest)); break; case 3: strlcpy(ups->selftest, "monthly", sizeof(ups->selftest)); break; case 4: strlcpy(ups->selftest, "atTurnOn", sizeof(ups->selftest)); break; case 6: strlcpy(ups->selftest, "daily", sizeof(ups->selftest)); break; case 1: // unknown case 5: // none default: strlcpy(ups->selftest, "OFF", sizeof(ups->selftest)); break; } break; case CI_SERNO: Dmsg(80, "Got CI_SERNO: %s\n", data.str.str()); strlcpy(ups->serial, data.str, sizeof(ups->serial)); break; case CI_NOMBATTV: Dmsg(80, "Got CI_NOMBATTV: %d\n", data.u32); ups->nombattv = ((double)data.u32) / 10; break; case CI_HUMID: Dmsg(80, "Got CI_HUMID: %d\n", data.u32); ups->humidity = data.u32; break; case CI_REVNO: Dmsg(80, "Got CI_REVNO: %s\n", data.str.str()); strlcpy(ups->firmrev, data.str, sizeof(ups->firmrev)); break; case CI_ATEMP: Dmsg(80, "Got CI_ATEMP: %d\n", data.u32); ups->ambtemp = data.u32; break; case CI_NOMOUTV: Dmsg(80, "Got CI_NOMOUTV: %d\n", data.u32); ups->NomOutputVoltage = data.u32 / 10; break; case CI_Boost: Dmsg(200, "Got CI_Boost: %d\n", data.u32); if (data.u32 == 1) ups->set_boost(); else ups->clear_boost(); break; case CI_Trim: Dmsg(200, "Got CI_Trim(Buck): %d\n", data.u32); if (data.u32 == 1) ups->set_trim(); else ups->clear_trim(); break; case CI_Overload: Dmsg(80, "Got CI_Overload: %d\n", data.u32); if (data.u32 == 1) ups->set_overload(); else ups->clear_overload(); break; case CI_NeedReplacement: Dmsg(80, "Got CI_NeedReplacement: %d\n", data.u32); if (data.u32 == 1) ups->set_replacebatt(); else ups->clear_replacebatt(); break; case CI_LowBattery: Dmsg(80, "Got CI_LowBattery: %d\n", data.u32); if (data.u32 == 1) ups->set_battlow(); else ups->clear_battlow(); break; case CI_AlarmTimer: Dmsg(80, "Got CI_AlarmTimer: %d\n", data.u32); // Remember alarm timer setting; we will use it for CI_DALARM alarmtimer = data.u32; break; } } // Export strategy to snmplite.cpp struct MibStrategy MGEMibStrategy = { "MGE", MGE_CiOidMap, mge_update_ci, NULL, NULL, }; apcupsd-3.14.14/src/drivers/snmplite/mge-oids.h000066400000000000000000000434501274230402600213060ustar00rootroot00000000000000#ifndef __MGE_OIDS_H_ #define __MGE_OIDS_H_ /* * oids.h * * UPS-related OIDs from MGE's UPS MIB * * Generated from mgeups_mib17_ad.mib (rev 1.7ad) * */ #ifdef __GNUC__ #define __UNUSED__ __attribute__((unused)) #else #define __UNUSED__ #endif // // Note that because these are all declared static, the compiler will eliminate // those that we do not reference. It will warn about it, however, so need to // suppress that where possible. // __UNUSED__ static int upsmgIdentFamilyName[] = {1, 3, 6, 1, 4, 1, 705, 1, 1, 1, -1}; __UNUSED__ static int upsmgIdentModelName[] = {1, 3, 6, 1, 4, 1, 705, 1, 1, 2, -1}; __UNUSED__ static int upsmgIdentRevisionLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 1, 3, -1}; __UNUSED__ static int upsmgIdentFirmwareVersion[] = {1, 3, 6, 1, 4, 1, 705, 1, 1, 4, -1}; __UNUSED__ static int upsmgIdentUserID[] = {1, 3, 6, 1, 4, 1, 705, 1, 1, 5, -1}; __UNUSED__ static int upsmgIdentInstallationDate[] = {1, 3, 6, 1, 4, 1, 705, 1, 1, 6, -1}; __UNUSED__ static int upsmgIdentSerialNumber[] = {1, 3, 6, 1, 4, 1, 705, 1, 1, 7, -1}; __UNUSED__ static int upsmgManagersNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 1, -1}; __UNUSED__ static int mgmanagerIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 1, -1}; __UNUSED__ static int mgmanagerDeviceNumber[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 2, -1}; __UNUSED__ static int mgmanagerNMSType[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 3, -1}; __UNUSED__ static int mgmanagerCommType[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 4, -1}; __UNUSED__ static int mgmanagerDescr[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 5, -1}; __UNUSED__ static int mgmanagerAddress[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 6, -1}; __UNUSED__ static int mgmanagerCommunity[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 7, -1}; __UNUSED__ static int mgmanagerSeverityLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 8, -1}; __UNUSED__ static int mgmanagerTrapAck[] = {1, 3, 6, 1, 4, 1, 705, 1, 2, 2, 1, 9, -1}; __UNUSED__ static int upsmgReceptaclesNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 1, -1}; __UNUSED__ static int mgreceptacleIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 1, -1}; __UNUSED__ static int mgreceptacleLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 2, -1}; __UNUSED__ static int mgreceptacleType[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 3, -1}; __UNUSED__ static int mgreceptacleIdent[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 4, -1}; __UNUSED__ static int mgreceptacleState[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 5, -1}; __UNUSED__ static int mgreceptacleReceptacle[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 6, -1}; __UNUSED__ static int mgreceptaclePowerCons[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 7, -1}; __UNUSED__ static int mgreceptacleOverload[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 8, -1}; __UNUSED__ static int mgreceptacleAutonomy[] = {1, 3, 6, 1, 4, 1, 705, 1, 3, 2, 1, 9, -1}; __UNUSED__ static int upsmgConfigBatteryInstalled[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 1, -1}; __UNUSED__ static int upsmgConfigNominalBatteryVoltage[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 2, -1}; __UNUSED__ static int upsmgConfigNominalBatteryTime[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 3, -1}; __UNUSED__ static int upsmgConfigNominalRechargeTime[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 4, -1}; __UNUSED__ static int upsmgConfigMinRechargeLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 5, -1}; __UNUSED__ static int upsmgConfigMaxRechargeTime[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 6, -1}; __UNUSED__ static int upsmgConfigLowBatteryTime[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 7, -1}; __UNUSED__ static int upsmgConfigLowBatteryLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 8, -1}; __UNUSED__ static int upsmgConfigAutoRestart[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 9, -1}; __UNUSED__ static int upsmgConfigShutdownTimer[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 10, -1}; __UNUSED__ static int upsmgConfigSysShutDuration[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 11, -1}; __UNUSED__ static int upsmgConfigVARating[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 12, -1}; __UNUSED__ static int upsmgConfigLowTransfer[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 13, -1}; __UNUSED__ static int upsmgConfigHighTransfer[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 14, -1}; __UNUSED__ static int upsmgConfigOutputNominalVoltage[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 15, -1}; __UNUSED__ static int upsmgConfigOutputNominalCurrent[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 16, -1}; __UNUSED__ static int upsmgConfigOutputNomFrequency[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 17, -1}; __UNUSED__ static int upsmgConfigByPassType[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 18, -1}; __UNUSED__ static int upsmgConfigAlarmAudible[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 19, -1}; __UNUSED__ static int upsmgConfigAlarmTimeDelay[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 20, -1}; __UNUSED__ static int upsmgConfigDevicesNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 21, -1}; __UNUSED__ static int mgdeviceIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 22, 1, 1, -1}; __UNUSED__ static int mgdeviceReceptacleNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 22, 1, 2, -1}; __UNUSED__ static int mgdeviceIdent[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 22, 1, 3, -1}; __UNUSED__ static int mgdeviceVaRating[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 22, 1, 4, -1}; __UNUSED__ static int mgdeviceSequenceOff[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 22, 1, 5, -1}; __UNUSED__ static int mgdeviceSequenceOn[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 22, 1, 6, -1}; __UNUSED__ static int mgdeviceShutdownDuration[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 22, 1, 7, -1}; __UNUSED__ static int mgdeviceBootUpDuration[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 22, 1, 8, -1}; __UNUSED__ static int mgreceptacleIndexb[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 1, -1}; __UNUSED__ static int mgreceptacleStateTurnOn[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 2, -1}; __UNUSED__ static int mgreceptacleStateMainReturn[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 3, -1}; __UNUSED__ static int mgreceptacleStateDischarge[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 4, -1}; __UNUSED__ static int mgreceptacleShutoffLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 5, -1}; __UNUSED__ static int mgreceptacleShutoffTimer[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 6, -1}; __UNUSED__ static int mgreceptacleRestartLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 7, -1}; __UNUSED__ static int mgreceptacleRestartDelay[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 8, -1}; __UNUSED__ static int mgreceptacleShutdownDuration[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 9, -1}; __UNUSED__ static int mgreceptacleBootUpDuration[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 23, 1, 10, -1}; __UNUSED__ static int upsmgConfigExtAlarmNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 24, -1}; __UNUSED__ static int mgextAlarmIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 25, 1, 1, -1}; __UNUSED__ static int mgextAlarmUID[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 25, 1, 2, -1}; __UNUSED__ static int upsmgConfigEmergencyTestFail[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 26, -1}; __UNUSED__ static int upsmgConfigEmergencyOnByPass[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 27, -1}; __UNUSED__ static int upsmgConfigEmergencyOverload[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 28, -1}; __UNUSED__ static int mgcontrolDayIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 29, 1, 1, -1}; __UNUSED__ static int mgcontrolDayOn[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 29, 1, 2, -1}; __UNUSED__ static int mgcontrolDayOff[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 29, 1, 3, -1}; __UNUSED__ static int upsmgConfigLowBooster[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 30, -1}; __UNUSED__ static int upsmgConfigHighBooster[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 31, -1}; __UNUSED__ static int upsmgConfigLowFader[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 32, -1}; __UNUSED__ static int upsmgConfigHighFader[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 33, -1}; __UNUSED__ static int upsmgConfigSensorIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 1, -1}; __UNUSED__ static int upsmgConfigSensorName[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 2, -1}; __UNUSED__ static int upsmgConfigTemperatureLow[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 3, -1}; __UNUSED__ static int upsmgConfigTemperatureHigh[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 4, -1}; __UNUSED__ static int upsmgConfigTemperatureHysteresis[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 5, -1}; __UNUSED__ static int upsmgConfigHumidityLow[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 6, -1}; __UNUSED__ static int upsmgConfigHumidityHigh[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 7, -1}; __UNUSED__ static int upsmgConfigHumidityHysteresis[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 8, -1}; __UNUSED__ static int upsmgConfigInput1Name[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 9, -1}; __UNUSED__ static int upsmgConfigInput1ClosedLabel[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 10, -1}; __UNUSED__ static int upsmgConfigInput1OpenLabel[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 11, -1}; __UNUSED__ static int upsmgConfigInput2Name[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 12, -1}; __UNUSED__ static int upsmgConfigInput2ClosedLabel[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 13, -1}; __UNUSED__ static int upsmgConfigInput2OpenLabel[] = {1, 3, 6, 1, 4, 1, 705, 1, 4, 34, 1, 14, -1}; __UNUSED__ static int upsmgBatteryRemainingTime[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 1, -1}; __UNUSED__ static int upsmgBatteryLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 2, -1}; __UNUSED__ static int upsmgBatteryRechargeTime[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 3, -1}; __UNUSED__ static int upsmgBatteryRechargeLevel[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 4, -1}; __UNUSED__ static int upsmgBatteryVoltage[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 5, -1}; __UNUSED__ static int upsmgBatteryCurrent[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 6, -1}; __UNUSED__ static int upsmgBatteryTemperature[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 7, -1}; __UNUSED__ static int upsmgBatteryFullRechargeTime[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 8, -1}; __UNUSED__ static int upsmgBatteryFaultBattery[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 9, -1}; __UNUSED__ static int upsmgBatteryNoBattery[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 10, -1}; __UNUSED__ static int upsmgBatteryReplacement[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 11, -1}; __UNUSED__ static int upsmgBatteryUnavailableBattery[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 12, -1}; __UNUSED__ static int upsmgBatteryNotHighCharge[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 13, -1}; __UNUSED__ static int upsmgBatteryLowBattery[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 14, -1}; __UNUSED__ static int upsmgBatteryChargerFault[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 15, -1}; __UNUSED__ static int upsmgBatteryLowCondition[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 16, -1}; __UNUSED__ static int upsmgBatteryLowRecharge[] = {1, 3, 6, 1, 4, 1, 705, 1, 5, 17, -1}; __UNUSED__ static int upsmgInputPhaseNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 1, -1}; __UNUSED__ static int mginputIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 2, 1, 1, -1}; __UNUSED__ static int mginputVoltage[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 2, 1, 2, -1}; __UNUSED__ static int mginputFrequency[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 2, 1, 3, -1}; __UNUSED__ static int mginputMinimumVoltage[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 2, 1, 4, -1}; __UNUSED__ static int mginputMaximumVoltage[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 2, 1, 5, -1}; __UNUSED__ static int mginputCurrent[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 2, 1, 6, -1}; __UNUSED__ static int upsmgInputBadStatus[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 3, -1}; __UNUSED__ static int upsmgInputLineFailCause[] = {1, 3, 6, 1, 4, 1, 705, 1, 6, 4, -1}; __UNUSED__ static int upsmgOutputPhaseNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 1, -1}; __UNUSED__ static int mgoutputPhaseIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 2, 1, 1, -1}; __UNUSED__ static int mgoutputVoltage[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 2, 1, 2, -1}; __UNUSED__ static int mgoutputFrequency[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 2, 1, 3, -1}; __UNUSED__ static int mgoutputLoadPerPhase[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 2, 1, 4, -1}; __UNUSED__ static int mgoutputCurrent[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 2, 1, 5, -1}; __UNUSED__ static int upsmgOutputOnBattery[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 3, -1}; __UNUSED__ static int upsmgOutputOnByPass[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 4, -1}; __UNUSED__ static int upsmgOutputUnavailableByPass[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 5, -1}; __UNUSED__ static int upsmgOutputNoByPass[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 6, -1}; __UNUSED__ static int upsmgOutputUtilityOff[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 7, -1}; __UNUSED__ static int upsmgOutputOnBoost[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 8, -1}; __UNUSED__ static int upsmgOutputInverterOff[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 9, -1}; __UNUSED__ static int upsmgOutputOverLoad[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 10, -1}; __UNUSED__ static int upsmgOutputOverTemp[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 11, -1}; __UNUSED__ static int upsmgOutputOnBuck[] = {1, 3, 6, 1, 4, 1, 705, 1, 7, 12, -1}; __UNUSED__ static int upsmgEnvironAmbientTemp[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 1, -1}; __UNUSED__ static int upsmgEnvironAmbientHumidity[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 2, -1}; __UNUSED__ static int mgalarmNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 3, 1, 1, -1}; __UNUSED__ static int mgalarmState[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 3, 1, 2, -1}; __UNUSED__ static int upsmgEnvironSensorNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 4, -1}; __UNUSED__ static int mgsensorNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 5, 1, 1, -1}; __UNUSED__ static int mgsensorTemp[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 5, 1, 2, -1}; __UNUSED__ static int mgsensorHumidity[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 5, 1, 3, -1}; __UNUSED__ static int upsmgEnvironmentNum[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 6, -1}; __UNUSED__ static int upsmgEnvironmentIndex[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 1, -1}; __UNUSED__ static int upsmgEnvironmentComFailure[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 2, -1}; __UNUSED__ static int upsmgEnvironmentTemperature[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 3, -1}; __UNUSED__ static int upsmgEnvironmentTemperatureLow[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 4, -1}; __UNUSED__ static int upsmgEnvironmentTemperatureHigh[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 5, -1}; __UNUSED__ static int upsmgEnvironmentHumidity[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 6, -1}; __UNUSED__ static int upsmgEnvironmentHumidityLow[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 7, -1}; __UNUSED__ static int upsmgEnvironmentHumidityHigh[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 8, -1}; __UNUSED__ static int upsmgEnvironmentInput1State[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 9, -1}; __UNUSED__ static int upsmgEnvironmentInput2State[] = {1, 3, 6, 1, 4, 1, 705, 1, 8, 7, 1, 10, -1}; __UNUSED__ static int mgreceptacleIndexc[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 1, -1}; __UNUSED__ static int mgreceptacleOnDelay[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 2, -1}; __UNUSED__ static int mgreceptacleOnCtrl[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 3, -1}; __UNUSED__ static int mgreceptacleOnStatus[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 4, -1}; __UNUSED__ static int mgreceptacleOffDelay[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 5, -1}; __UNUSED__ static int mgreceptacleOffCtrl[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 6, -1}; __UNUSED__ static int mgreceptacleOffStatus[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 7, -1}; __UNUSED__ static int mgreceptacleToggleDelay[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 8, -1}; __UNUSED__ static int mgreceptacleToggleCtrl[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 9, -1}; __UNUSED__ static int mgreceptacleToggleStatus[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 10, -1}; __UNUSED__ static int mgreceptacleToggleDuration[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 1, 1, 11, -1}; __UNUSED__ static int upsmgControlDayOff[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 2, -1}; __UNUSED__ static int upsmgControlDayOn[] = {1, 3, 6, 1, 4, 1, 705, 1, 9, 3, -1}; __UNUSED__ static int upsmgTestBatterySchedule[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 1, -1}; __UNUSED__ static int upsmgTestDiagnostics[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 2, -1}; __UNUSED__ static int upsmgTestDiagResult[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 3, -1}; __UNUSED__ static int upsmgTestBatteryCalibration[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 4, -1}; __UNUSED__ static int upsmgTestLastCalibration[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 5, -1}; __UNUSED__ static int upsmgTestIndicators[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 6, -1}; __UNUSED__ static int upsmgTestCommandLine[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 7, -1}; __UNUSED__ static int upsmgTestCommandReady[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 8, -1}; __UNUSED__ static int upsmgTestResponseLine[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 9, -1}; __UNUSED__ static int upsmgTestResponseReady[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 10, -1}; __UNUSED__ static int upsmgTestBatteryResult[] = {1, 3, 6, 1, 4, 1, 705, 1, 10, 11, -1}; __UNUSED__ static int upsmgAgentIpaddress[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 1, -1}; __UNUSED__ static int upsmgAgentSubnetMask[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 2, -1}; __UNUSED__ static int upsmgAgentDefGateway[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 3, -1}; __UNUSED__ static int upsmgAgentBaudRate[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 4, -1}; __UNUSED__ static int upsmgAgentPollRate[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 5, -1}; __UNUSED__ static int upsmgAgentType[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 6, -1}; __UNUSED__ static int upsmgAgentTrapAlarmDelay[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 7, -1}; __UNUSED__ static int upsmgAgentTrapAlarmRetry[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 8, -1}; __UNUSED__ static int upsmgAgentReset[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 9, -1}; __UNUSED__ static int upsmgAgentFactReset[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 10, -1}; __UNUSED__ static int upsmgAgentMibVersion[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 11, -1}; __UNUSED__ static int upsmgAgentFirmwareVersion[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 12, -1}; __UNUSED__ static int upsmgAgentCommUPS[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 13, -1}; __UNUSED__ static int upsmgAgentTrapAck[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 14, -1}; __UNUSED__ static int upsmgAgentAutoLearning[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 15, -1}; __UNUSED__ static int upsmgAgentBootP[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 16, -1}; __UNUSED__ static int upsmgAgentTFTP[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 17, -1}; __UNUSED__ static int upsmgAgentTrapSignature[] = {1, 3, 6, 1, 4, 1, 705, 1, 12, 18, -1}; __UNUSED__ static int upsmgRemoteOnBattery[] = {1, 3, 6, 1, 4, 1, 705, 1, 13, 1, -1}; __UNUSED__ static int upsmgRemoteIpAddress[] = {1, 3, 6, 1, 4, 1, 705, 1, 13, 2, -1}; #endif apcupsd-3.14.14/src/drivers/snmplite/mibs.cpp000066400000000000000000000017741274230402600210720ustar00rootroot00000000000000/* * mibs.c * * MIBs for SNMP Lite driver */ /* * Copyright (C) 2010 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "mibs.h" extern struct MibStrategy ApcMibStrategy; extern struct MibStrategy Rfc1628MibStrategy; extern struct MibStrategy MGEMibStrategy; struct MibStrategy *MibStrategies[] = { &ApcMibStrategy, &Rfc1628MibStrategy, &MGEMibStrategy, NULL }; apcupsd-3.14.14/src/drivers/snmplite/mibs.h000066400000000000000000000026351274230402600205340ustar00rootroot00000000000000/* * apc-mib.h * * Public header for the APC MIB strategy */ /* * Copyright (C) 2010 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __MIBS_H_ #define __MIBS_H_ #include "snmp.h" #include "asn.h" // Mapping from CI to SNMP OID and type struct CiOidMap { int ci; // CI int *oid; // SNMP OID Asn::Identifier type; // ASN type for this OID bool dynamic; // True if dynamic parameter, false if static }; // Associates a MIB with processing functions for that MIB struct MibStrategy { const char *name; CiOidMap *mib; void (*update_ci_func)(UPSINFO*, int, Snmp::Variable &); int (*killpower_func)(Snmp::SnmpEngine *snmp); int (*shutdown_func)(Snmp::SnmpEngine *snmp); }; extern struct MibStrategy *MibStrategies[]; #endif apcupsd-3.14.14/src/drivers/snmplite/rfc1628-mib.cpp000066400000000000000000000246411274230402600217760ustar00rootroot00000000000000/* * mib.cpp * * CI -> OID mapping for SNMP Lite UPS driver */ /* * Copyright (C) 2010 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "snmplite-common.h" #include "mibs.h" #include "rfc1628-oids.h" using namespace Asn; static struct CiOidMap Rfc1628CiOidMap[] = { // CI OID type dynamic? {CI_UPSMODEL, upsIdentModel, OCTETSTRING, false}, {CI_IDEN, upsIdentName, OCTETSTRING, false}, {CI_REVNO, upsIdentUPSSoftwareVersion, OCTETSTRING, false}, // {CI_MANDAT, upsAdvIdentDateOfManufacture, OCTETSTRING, false}, // {CI_BATTDAT, upsBasicBatteryLastReplaceDate, OCTETSTRING, false}, // {CI_NOMBATTV, upsAdvBatteryNominalVoltage, INTEGER, false}, {CI_NOMOUTV, upsConfigOutputVoltage, INTEGER, false}, {CI_NOMINV, upsConfigInputVoltage, INTEGER, false}, {CI_NOMPOWER, upsConfigOutputPower, INTEGER, false}, {CI_LTRANS, upsConfigLowVoltageTransferPoint, INTEGER, false}, {CI_HTRANS, upsConfigHighVoltageTransferPoint, INTEGER, false}, // {CI_DWAKE, upsAdvConfigReturnDelay, TIMETICKS, false}, {CI_DALARM, upsConfigAudibleStatus, INTEGER, false}, {CI_DLBATT, upsConfigLowBattTime, INTEGER, false}, // {CI_DSHUTD, upsAdvConfigShutoffDelay, TIMETICKS, false}, // {CI_RETPCT, upsAdvConfigMinReturnCapacity, INTEGER, false}, // {CI_SENS, upsAdvConfigSensitivity, INTEGER, false}, // {CI_EXTBATTS, upsAdvBatteryNumOfBattPacks, INTEGER, false}, // {CI_STESTI, upsAdvTestDiagnosticSchedule, INTEGER, false}, {CI_VLINE, upsInputTableInputVoltage, SEQUENCE, true }, {CI_VOUT, upsOutputTableOutputVoltage, SEQUENCE, true }, {CI_VBATT, upsBatteryVoltage, INTEGER, true }, {CI_FREQ, upsInputTableInputFrequency, SEQUENCE, true }, {CI_LOAD, upsOutputTableOutputPercentLoad, SEQUENCE, true }, {CI_ITEMP, upsBatteryTemperature, INTEGER, true }, // {CI_ATEMP, mUpsEnvironAmbientTemperature, GAUGE, true }, // {CI_HUMID, mUpsEnvironRelativeHumidity, GAUGE, true }, {CI_ST_STAT, upsTestResultsSummary, INTEGER, true }, {CI_BATTLEV, upsEstimatedChargeRemaining, INTEGER, true }, {CI_RUNTIM, upsEstimatedMinutesRemaining, INTEGER, true }, // {CI_WHY_BATT, upsAdvInputLineFailCause, INTEGER, true }, // {CI_BADBATTS, upsAdvBatteryNumOfBadBattPacks, INTEGER, true }, // {CI_VMIN, upsAdvInputMinLineVoltage, GAUGE, true }, // {CI_VMAX, upsAdvInputMaxLineVoltage, GAUGE, true }, {CI_STATUS, upsOutputSource, INTEGER, true }, {CI_LowBattery, upsBatteryStatus, INTEGER, true }, {-1, NULL, false} /* END OF TABLE */ }; static void rfc1628_update_ci(UPSINFO *ups, int ci, Snmp::Variable &data) { switch (ci) { case CI_VLINE: // We just take the voltage from the first input line and ignore the rest Dmsg(80, "Got CI_VLINE: %d\n", data.seq.begin()->u32); ups->LineVoltage = data.seq.begin()->u32; break; case CI_VOUT: // We just take the voltage from the first input line and ignore the rest Dmsg(80, "Got CI_VOUT: %d\n", data.seq.begin()->u32); ups->OutputVoltage = data.seq.begin()->u32; break; case CI_VBATT: Dmsg(80, "Got CI_VBATT: %d\n", data.u32); ups->BattVoltage = ((double)data.u32) / 10; break; case CI_FREQ: // We just take the freq from the first input line and ignore the rest Dmsg(80, "Got CI_FREQ: %d\n", data.seq.begin()->u32); ups->LineFreq = ((double)data.seq.begin()->u32) / 10; break; case CI_LOAD: // MIB defines this as "The percentage of the UPS power capacity // presently being used on this output line" so we should be able to // add all these up to get a total load for the UPS as a whole. // HOWEVER, manufacturers seem to actually be returning either the same // value in each slot (APC implementation of RFC1628) or percent of // power the line is capable of (Generex CS121 SNMP/WEB Adapter on a // Newave Conceptpower DPA UPS). So we will average the values and hope // for the best. ups->UPSLoad = 0; for (alist::iterator iter = data.seq.begin(); iter != data.seq.end(); ++iter) { Dmsg(80, "Got CI_LOAD: %d\n", iter->u32); ups->UPSLoad += iter->u32; } ups->UPSLoad /= data.seq.size(); break; case CI_ITEMP: Dmsg(80, "Got CI_ITEMP: %d\n", data.u32); ups->UPSTemp = data.u32; break; case CI_NOMOUTV: Dmsg(80, "Got CI_NOMOUTV: %d\n", data.u32); ups->NomOutputVoltage = data.u32; break; case CI_NOMINV: Dmsg(80, "Got CI_NOMINV: %d\n", data.u32); ups->NomInputVoltage = data.u32; break; case CI_NOMPOWER: Dmsg(80, "Got CI_NOMPOWER: %d\n", data.u32); ups->NomPower = data.u32; break; case CI_LTRANS: Dmsg(80, "Got CI_LTRANS: %d\n", data.u32); ups->lotrans = data.u32; break; case CI_HTRANS: Dmsg(80, "Got CI_HTRANS: %d\n", data.u32); ups->hitrans = data.u32; break; case CI_ST_STAT: Dmsg(80, "Got CI_ST_STAT: %d\n", data.u32); switch (data.u32) { case 1: /* Passed */ ups->testresult = TEST_PASSED; break; case 2: /* Warning */ ups->testresult = TEST_WARNING; break; case 3: /* Error */ ups->testresult = TEST_FAILED; break; case 5: /* Test in progress */ ups->testresult = TEST_INPROGRESS; break; case 4: /* Aborted */ case 6: /* No test initiated */ ups->testresult = TEST_NONE; break; default: ups->testresult = TEST_UNKNOWN; break; } break; case CI_DALARM: Dmsg(80, "Got CI_DALARM: %d\n", data.u32); switch (data.u32) { case 1: // Disabled ("None") strlcpy(ups->beepstate, "N", sizeof(ups->beepstate)); break; case 2: // Enabled (T = 30 seconds...just a guess) case 3: // Muted (but enabled) default: strlcpy(ups->beepstate, "T", sizeof(ups->beepstate)); break; } break; case CI_UPSMODEL: Dmsg(80, "Got CI_UPSMODEL: %s\n", data.str.str()); strlcpy(ups->upsmodel, data.str, sizeof(ups->upsmodel)); break; case CI_BATTLEV: Dmsg(80, "Got CI_BATTLEV: %d\n", data.u32); ups->BattChg = data.u32; break; case CI_RUNTIM: Dmsg(80, "Got CI_RUNTIM: %d\n", data.u32); ups->TimeLeft = data.u32; break; case CI_IDEN: Dmsg(80, "Got CI_IDEN: %s\n", data.str.str()); strlcpy(ups->upsname, data.str, sizeof(ups->upsname)); break; case CI_STATUS: Dmsg(80, "Got CI_STATUS: %d\n", data.u32); /* Clear the following flags: only one status will be TRUE */ ups->clear_online(); ups->clear_onbatt(); ups->clear_boost(); ups->clear_trim(); switch (data.u32) { case 3: ups->set_online(); break; case 5: ups->set_onbatt(); break; case 6: ups->set_online(); ups->set_boost(); break; case 7: ups->set_online(); ups->set_trim(); break; case 1: /* other */ case 2: /* output turned off */ case 4: /* bypass */ default: /* unknown */ break; } break; case CI_LowBattery: Dmsg(80, "Got CI_LowBattery: %d\n", data.u32); switch (data.u32) { default: case 1: // Unknown case 2: // Normal ups->clear_battlow(); break; case 3: // Low case 4: // Depleted ups->set_battlow(); break; } break; case CI_REVNO: Dmsg(80, "Got CI_REVNO: %s\n", data.str.str()); strlcpy(ups->firmrev, data.str, sizeof(ups->firmrev)); break; case CI_DLBATT: Dmsg(80, "Got CI_DLBATT: %d\n", data.u32); ups->dlowbatt = data.u32; break; } } static int rfc1628_killpower(Snmp::SnmpEngine *snmp) { // Configure UPS to turn off output only (not entire UPS) Snmp::Variable shutdownType(Asn::INTEGER, 1); snmp->Set(upsShutdownType, &shutdownType); // Configure UPS to automatically restart when power is restored Snmp::Variable autoRestart(Asn::INTEGER, 1); snmp->Set(upsAutoRestart, &autoRestart); // Instruct UPS to turn off after 60 secs Snmp::Variable shutdownDelay(Asn::INTEGER, 60); snmp->Set(upsShutdownAfterDelay, &shutdownDelay); return 0; } static int rfc1628_shutdown(Snmp::SnmpEngine *snmp) { // Configure UPS to turn off entire system Snmp::Variable shutdownType(Asn::INTEGER, 2); snmp->Set(upsShutdownType, &shutdownType); // Configure UPS to NOT automatically restart when power is restored Snmp::Variable autoRestart(Asn::INTEGER, 2); snmp->Set(upsAutoRestart, &autoRestart); // Instruct UPS to turn off after 60 secs Snmp::Variable shutdownDelay(Asn::INTEGER, 60); snmp->Set(upsShutdownAfterDelay, &shutdownDelay); return 0; } // Export strategy to snmplite.cpp struct MibStrategy Rfc1628MibStrategy = { "RFC", Rfc1628CiOidMap, rfc1628_update_ci, rfc1628_killpower, rfc1628_shutdown, }; apcupsd-3.14.14/src/drivers/snmplite/rfc1628-oids.h000066400000000000000000000126141274230402600216270ustar00rootroot00000000000000#ifndef __RFC1628_OIDS_H_ #define __RFC1628_OIDS_H_ /* * rfc1628-oids.h * * UPS-related OIDs from RFC1628 MIB * * Generated from rfc1628.mib * */ #ifdef __GNUC__ #define __UNUSED__ __attribute__((unused)) #else #define __UNUSED__ #endif // // Note that because these are all declared static, the compiler will eliminate // those that we do not reference. It will warn about it, however, so need to // suppress that where possible. // __UNUSED__ static int upsIdentManufacturer[] = {1, 3, 6, 1, 2, 1, 33, 1, 1, 1, -1}; __UNUSED__ static int upsIdentModel[] = {1, 3, 6, 1, 2, 1, 33, 1, 1, 2, -1}; __UNUSED__ static int upsIdentUPSSoftwareVersion[] = {1, 3, 6, 1, 2, 1, 33, 1, 1, 3, -1}; __UNUSED__ static int upsIdentAgentSoftwareVersion[] = {1, 3, 6, 1, 2, 1, 33, 1, 1, 4, -1}; __UNUSED__ static int upsIdentName[] = {1, 3, 6, 1, 2, 1, 33, 1, 1, 5, -1}; __UNUSED__ static int upsIdentAttachedDevices[] = {1, 3, 6, 1, 2, 1, 33, 1, 1, 6, -1}; __UNUSED__ static int upsBatteryStatus[] = {1, 3, 6, 1, 2, 1, 33, 1, 2, 1, -1}; __UNUSED__ static int upsSecondsOnBattery[] = {1, 3, 6, 1, 2, 1, 33, 1, 2, 2, -1}; __UNUSED__ static int upsEstimatedMinutesRemaining[] = {1, 3, 6, 1, 2, 1, 33, 1, 2, 3, -1}; __UNUSED__ static int upsEstimatedChargeRemaining[] = {1, 3, 6, 1, 2, 1, 33, 1, 2, 4, -1}; __UNUSED__ static int upsBatteryVoltage[] = {1, 3, 6, 1, 2, 1, 33, 1, 2, 5, -1}; __UNUSED__ static int upsBatteryCurrent[] = {1, 3, 6, 1, 2, 1, 33, 1, 2, 6, -1}; __UNUSED__ static int upsBatteryTemperature[] = {1, 3, 6, 1, 2, 1, 33, 1, 2, 7, -1}; __UNUSED__ static int upsInputLineBads[] = {1, 3, 6, 1, 2, 1, 33, 1, 3, 1, -1}; __UNUSED__ static int upsInputNumLines[] = {1, 3, 6, 1, 2, 1, 33, 1, 3, 2, -1}; __UNUSED__ static int upsInputTableInputLineIndex[] = {1, 3, 6, 1, 2, 1, 33, 1, 3, 3, 1, 1, -1}; __UNUSED__ static int upsInputTableInputFrequency[] = {1, 3, 6, 1, 2, 1, 33, 1, 3, 3, 1, 2, -1}; __UNUSED__ static int upsInputTableInputVoltage[] = {1, 3, 6, 1, 2, 1, 33, 1, 3, 3, 1, 3, -1}; __UNUSED__ static int upsInputTableInputCurrent[] = {1, 3, 6, 1, 2, 1, 33, 1, 3, 3, 1, 4, -1}; __UNUSED__ static int upsInputTableInputTruePower[] = {1, 3, 6, 1, 2, 1, 33, 1, 3, 3, 1, 5, -1}; __UNUSED__ static int upsOutputSource[] = {1, 3, 6, 1, 2, 1, 33, 1, 4, 1, -1}; __UNUSED__ static int upsOutputFrequency[] = {1, 3, 6, 1, 2, 1, 33, 1, 4, 2, -1}; __UNUSED__ static int upsOutputNumLines[] = {1, 3, 6, 1, 2, 1, 33, 1, 4, 3, -1}; __UNUSED__ static int upsOutputTableOutputLineIndex[] = {1, 3, 6, 1, 2, 1, 33, 1, 4, 4, 1, 1, -1}; __UNUSED__ static int upsOutputTableOutputVoltage[] = {1, 3, 6, 1, 2, 1, 33, 1, 4, 4, 1, 2, -1}; __UNUSED__ static int upsOutputTableOutputCurrent[] = {1, 3, 6, 1, 2, 1, 33, 1, 4, 4, 1, 3, -1}; __UNUSED__ static int upsOutputTableOutputPower[] = {1, 3, 6, 1, 2, 1, 33, 1, 4, 4, 1, 4, -1}; __UNUSED__ static int upsOutputTableOutputPercentLoad[] = {1, 3, 6, 1, 2, 1, 33, 1, 4, 4, 1, 5, -1}; __UNUSED__ static int upsBypassFrequency[] = {1, 3, 6, 1, 2, 1, 33, 1, 5, 1, -1}; __UNUSED__ static int upsBypassNumLines[] = {1, 3, 6, 1, 2, 1, 33, 1, 5, 2, -1}; __UNUSED__ static int upsBypassLineIndex[] = {1, 3, 6, 1, 2, 1, 33, 1, 5, 3, 1, 1, -1}; __UNUSED__ static int upsBypassVoltage[] = {1, 3, 6, 1, 2, 1, 33, 1, 5, 3, 1, 2, -1}; __UNUSED__ static int upsBypassCurrent[] = {1, 3, 6, 1, 2, 1, 33, 1, 5, 3, 1, 3, -1}; __UNUSED__ static int upsBypassPower[] = {1, 3, 6, 1, 2, 1, 33, 1, 5, 3, 1, 4, -1}; __UNUSED__ static int upsAlarmsPresent[] = {1, 3, 6, 1, 2, 1, 33, 1, 6, 1, -1}; __UNUSED__ static int upsAlarmId[] = {1, 3, 6, 1, 2, 1, 33, 1, 6, 2, 1, 1, -1}; __UNUSED__ static int upsAlarmDescr[] = {1, 3, 6, 1, 2, 1, 33, 1, 6, 2, 1, 2, -1}; __UNUSED__ static int upsAlarmTime[] = {1, 3, 6, 1, 2, 1, 33, 1, 6, 2, 1, 3, -1}; __UNUSED__ static int upsTestId[] = {1, 3, 6, 1, 2, 1, 33, 1, 7, 1, -1}; __UNUSED__ static int upsTestSpinLock[] = {1, 3, 6, 1, 2, 1, 33, 1, 7, 2, -1}; __UNUSED__ static int upsTestResultsSummary[] = {1, 3, 6, 1, 2, 1, 33, 1, 7, 3, -1}; __UNUSED__ static int upsTestResultsDetail[] = {1, 3, 6, 1, 2, 1, 33, 1, 7, 4, -1}; __UNUSED__ static int upsTestStartTime[] = {1, 3, 6, 1, 2, 1, 33, 1, 7, 5, -1}; __UNUSED__ static int upsTestElapsedTime[] = {1, 3, 6, 1, 2, 1, 33, 1, 7, 6, -1}; __UNUSED__ static int upsShutdownType[] = {1, 3, 6, 1, 2, 1, 33, 1, 8, 1, -1}; __UNUSED__ static int upsShutdownAfterDelay[] = {1, 3, 6, 1, 2, 1, 33, 1, 8, 2, -1}; __UNUSED__ static int upsStartupAfterDelay[] = {1, 3, 6, 1, 2, 1, 33, 1, 8, 3, -1}; __UNUSED__ static int upsRebootWithDuration[] = {1, 3, 6, 1, 2, 1, 33, 1, 8, 4, -1}; __UNUSED__ static int upsAutoRestart[] = {1, 3, 6, 1, 2, 1, 33, 1, 8, 5, -1}; __UNUSED__ static int upsConfigInputVoltage[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 1, -1}; __UNUSED__ static int upsConfigInputFreq[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 2, -1}; __UNUSED__ static int upsConfigOutputVoltage[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 3, -1}; __UNUSED__ static int upsConfigOutputFreq[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 4, -1}; __UNUSED__ static int upsConfigOutputVA[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 5, -1}; __UNUSED__ static int upsConfigOutputPower[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 6, -1}; __UNUSED__ static int upsConfigLowBattTime[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 7, -1}; __UNUSED__ static int upsConfigAudibleStatus[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 8, -1}; __UNUSED__ static int upsConfigLowVoltageTransferPoint[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 9, -1}; __UNUSED__ static int upsConfigHighVoltageTransferPoint[] = {1, 3, 6, 1, 2, 1, 33, 1, 9, 10, -1}; #endif apcupsd-3.14.14/src/drivers/snmplite/snmp.cpp000066400000000000000000000434501274230402600211120ustar00rootroot00000000000000/* * snmp.cpp * * SNMP client interface */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "snmp.h" #include "asn.h" #ifdef __WIN32__ #define close(x) closesocket(x) #endif using namespace Snmp; SnmpEngine::SnmpEngine() : _socket(INVALID_SOCKET), _trapsock(INVALID_SOCKET), _reqid(0) { } SnmpEngine::~SnmpEngine() { Close(); } bool SnmpEngine::Open(const char *host, unsigned short port, const char *comm) { // In case we are already open Close(); // Remember new community name _community = comm; // Generate starting request id struct timeval now; gettimeofday(&now, NULL); _reqid = now.tv_usec; // Look up destination address memset(&_destaddr, 0, sizeof(_destaddr)); _destaddr.sin_family = AF_INET; _destaddr.sin_port = htons(port); _destaddr.sin_addr.s_addr = inet_addr(host); if (_destaddr.sin_addr.s_addr == INADDR_NONE) { struct hostent he; char *tmphstbuf = NULL; size_t hstbuflen = 0; struct hostent *hp = gethostname_re(host, &he, &tmphstbuf, &hstbuflen); if (!hp || hp->h_length != sizeof(_destaddr.sin_addr.s_addr) || hp->h_addrtype != AF_INET) { free(tmphstbuf); return false; } memcpy(&_destaddr.sin_addr.s_addr, hp->h_addr, sizeof(_destaddr.sin_addr.s_addr)); free(tmphstbuf); } // Get a UDP socket _socket = socket_cloexec(PF_INET, SOCK_DGRAM, 0); if (_socket == INVALID_SOCKET) { perror("socket"); return false; } // Bind to rx on any interface struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr.s_addr = INADDR_ANY; int rc = bind(_socket, (struct sockaddr*)&addr, sizeof(addr)); if (rc == -1) { perror("bind"); close(_socket); _socket = INVALID_SOCKET; return false; } return true; } bool SnmpEngine::EnableTraps() { _trapsock = socket_cloexec(PF_INET, SOCK_DGRAM, 0); if (_trapsock == INVALID_SOCKET) { perror("socket"); return false; } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(SNMP_TRAP_PORT); addr.sin_addr.s_addr = INADDR_ANY; int rc = bind(_trapsock, (struct sockaddr*)&addr, sizeof(addr)); if (rc == -1) { perror("bind"); close(_trapsock); _trapsock = INVALID_SOCKET; return false; } return true; } void SnmpEngine::Close() { if (_socket != INVALID_SOCKET) { close(_socket); _socket = INVALID_SOCKET; } if (_trapsock != INVALID_SOCKET) { close(_trapsock); _trapsock = INVALID_SOCKET; } } bool SnmpEngine::Set(const int oid[], Variable *data) { // Send the request VbListMessage req(Asn::SET_REQ_PDU, _community, _reqid++); req.Append(oid, data); if (!issue(&req)) return false; // Wait for a response VbListMessage *rsp = (VbListMessage*)rspwait(1000); if (!rsp) return false; // Check error status if (rsp->ErrorStatus()) { delete rsp; return false; } delete rsp; return true; } bool SnmpEngine::Get(const int oid[], Variable *data) { OidVar oidvar; oidvar.oid = oid; oidvar.data = *data; alist oids; oids.append(oidvar); bool ret = Get(oids); if (ret) *data = (*oids.begin()).data; return ret; } bool SnmpEngine::Get(alist &oids) { // First, fetch all scalar (i.e. non-sequence) OIDs using a single // SNMP GETNEXT-REQUEST. Note we use GETNEXT instead of GET since all // OIDs omit the trailing 0. // Start with a request with no varbinds VbListMessage getreq(Asn::GETNEXT_REQ_PDU, _community, _reqid++); // Append one varbind for each oidvar from the caller alist::iterator iter; for (iter = oids.begin(); iter != oids.end(); ++iter) { if (iter->data.type != Asn::SEQUENCE) getreq.Append(iter->oid); // Also use this loop as an opportunity to initialize all variables // to invalid. They will be set to valid below as we fill in results. iter->data.valid = false; } // Perform request if we put at least one OID in it if (getreq.Size() > 0) { // Send request & await response VbListMessage *rsp = perform(&getreq); if (!rsp) return false; // Verify response varbind size is same as request // (i.e. agent provided a response for each varbind we requested) if (rsp->Size() != getreq.Size()) { delete rsp; return false; } // Copy response data into caller's oidvars. Although I believe the SNMP // spec requires the GET-RESPONSE to give the var-bind-list in the same // order as the GET-REQUEST, we're not going to count on that. A little // CPU time spent searching is ok to ensure widest compatiblity in case // we encounter a weak SNMP agent implementation. VbListMessage &response = *rsp; for (unsigned int i = 0; i < response.Size(); i++) { for (iter = oids.begin(); iter != oids.end(); ++iter) { if (response[i].Oid().IsChildOf(iter->oid)) { response[i].Extract(&iter->data); break; } } } // Done with response delete rsp; } // Now process sequences. For each sequence we issue a series of // SNMP GETNEXT-REQUESTs until we detect the end of the sequence. for (iter = oids.begin(); iter != oids.end(); ++iter) { if (iter->data.type == Asn::SEQUENCE) { Asn::ObjectId nextoid = iter->oid; while (1) { // Create a GET-NEXT request VbListMessage nextreq(Asn::GETNEXT_REQ_PDU, _community, _reqid++); // Request a single OID nextreq.Append(nextoid); // Perform the request VbListMessage *rspmsg = perform(&nextreq); // If request failed, we're done (possibly at end of MIB so we // don't consider this an error) if (!rspmsg) break; // If result OID is not a child of the top-level OID we're fetching // it means we've run off the end of the sequence so we're done VarBind &result = (*rspmsg)[0]; if (!result.Oid().IsChildOf(iter->oid)) { delete rspmsg; break; } // Extract data and append to sequence Variable tmp; result.Extract(&tmp); iter->data.seq.append(tmp); iter->data.valid = true; // Save returned OID for next iteration nextoid = result.Oid(); delete rspmsg; } } } return true; } VbListMessage *SnmpEngine::perform(VbListMessage *req) { // Send the request if (!issue(req)) return NULL; // Wait for a response VbListMessage *rsp = (VbListMessage*)rspwait(2000); if (rsp && rsp->ErrorStatus()) { delete rsp; return NULL; } return rsp; } TrapMessage *SnmpEngine::TrapWait(unsigned int msec) { if (_trapsock == INVALID_SOCKET) return NULL; return (TrapMessage*)rspwait(msec, true); } bool SnmpEngine::issue(Message *msg) { // Marshal the data unsigned char data[8192]; unsigned int buflen = sizeof(data); unsigned char *buffer = data; if (!msg->Marshal(buffer, buflen)) return false; // Send data to destination int datalen = buffer - data; int rc = sendto(_socket, (char*)data, datalen, 0, (struct sockaddr*)&_destaddr, sizeof(_destaddr)); if (rc != datalen) { perror("sendto"); return false; } return true; } Message *SnmpEngine::rspwait(unsigned int msec, bool trap) { static unsigned char data[8192]; struct sockaddr_in fromaddr; sock_t sock = trap ? _trapsock : _socket; // Calculate exit time struct timeval exittime; gettimeofday(&exittime, NULL); exittime.tv_usec += msec * 1000; while (exittime.tv_usec >= 1000000) { exittime.tv_usec -= 1000000; exittime.tv_sec++; } while(1) { // See if we've run out of time struct timeval now; gettimeofday(&now, NULL); if (now.tv_sec > exittime.tv_sec || (now.tv_sec == exittime.tv_sec && now.tv_usec >= exittime.tv_usec)) return NULL; // Calculate new timeout struct timeval timeout; timeout.tv_sec = exittime.tv_sec - now.tv_sec; timeout.tv_usec = exittime.tv_usec - now.tv_usec; while (timeout.tv_usec < 0) { timeout.tv_usec += 1000000; timeout.tv_sec--; } // Wait for a datagram to arrive fd_set fds; FD_ZERO(&fds); FD_SET(sock, &fds); int rc = select(sock+1, &fds, NULL, NULL, &timeout); if (rc == -1) { if (errno == EAGAIN || errno == EINTR) continue; return NULL; } // Timeout if (rc == 0) return NULL; // Read datagram socklen_t fromlen = sizeof(fromaddr); rc = recvfrom(sock, (char*)data, sizeof(data), 0, (struct sockaddr*)&fromaddr, &fromlen); if (rc == -1) { if (errno == EAGAIN || errno == EINTR) continue; return NULL; } // Ignore packet if it's not from our agent if (fromaddr.sin_addr.s_addr != _destaddr.sin_addr.s_addr) continue; // Got a packet from our agent: decode it unsigned char *buffer = data; unsigned int buflen = rc; Message *msg = Message::Demarshal(buffer, buflen); if (!msg) continue; // Check message type if (trap && msg->Type() == Asn::TRAP_PDU) { return msg; } else if (!trap && msg->Type() == Asn::GET_RSP_PDU && ((VbListMessage *)msg)->RequestId() == _reqid-1) { return msg; } else { printf("Unhandled SNMP message type: %02x\n", msg->Type()); } // Throw it out and try again delete msg; } } // ***************************************************************************** // VarBind // ***************************************************************************** VarBind::VarBind(const Asn::ObjectId &oid, Variable *data) { _oid = new Asn::ObjectId(oid); if (data) { switch (data->type) { case Asn::INTEGER: _data = new Asn::Integer(data->type); *(_data->AsInteger()) = data->i32; break; case Asn::TIMETICKS: case Asn::COUNTER: case Asn::GAUGE: _data = new Asn::Integer(data->type); *(_data->AsInteger()) = data->u32; break; case Asn::OCTETSTRING: _data = new Asn::OctetString(data->str); break; case Asn::NULLL: default: _data = new Asn::Null(); break; } } else { _data = new Asn::Null(); } } VarBind::VarBind(Asn::Sequence &seq) { if (seq.Size() == 2 && seq[0]->IsObjectId()) { _oid = seq[0]->copy()->AsObjectId(); _data = seq[1]->copy(); } else { _oid = new Asn::ObjectId(); _data = new Asn::Null(); } } VarBind::~VarBind() { delete _data; delete _oid; } bool VarBind::Extract(Variable *out) { out->type = _data->Type(); if (_data->IsInteger()) { out->i32 = _data->AsInteger()->IntValue(); out->u32 = _data->AsInteger()->UintValue(); out->valid = true; } else if (_data->IsOctetString()) { out->str = *_data->AsOctetString(); out->valid = true; } else { printf("Unsupported Asn::Object::AsnType: %d\n", _data->Type()); return false; } return true; } Asn::Sequence *VarBind::GetAsn() { Asn::Sequence *seq = new Asn::Sequence(); seq->Append(_oid->copy()); seq->Append(_data->copy()); return seq; } // ***************************************************************************** // VarBindList // ***************************************************************************** VarBindList::VarBindList(Asn::Sequence &seq) { for (unsigned int i = 0; i < seq.Size(); i++) { if (seq[i]->IsSequence()) _vblist.append(new VarBind(*seq[i]->AsSequence())); } } VarBindList::~VarBindList() { for (unsigned int i = 0; i < _vblist.size(); i++) delete _vblist[i]; } void VarBindList::Append(const Asn::ObjectId &oid, Variable *data) { _vblist.append(new VarBind(oid, data)); } Asn::Sequence *VarBindList::GetAsn() { Asn::Sequence *seq = new Asn::Sequence(); for (unsigned int i = 0; i < _vblist.size(); i++) seq->Append(_vblist[i]->GetAsn()); return seq; } // ***************************************************************************** // VbListMessage // ***************************************************************************** VbListMessage *VbListMessage::CreateFromSequence( Asn::Identifier type, const char *community, Asn::Sequence &seq) { // Verify format: We should have 4 parts. if (seq.Size() != 4 || !seq[0]->IsInteger() || // request-id !seq[1]->IsInteger() || // error-status !seq[2]->IsInteger() || // error-index !seq[3]->IsSequence()) // variable-bindings return NULL; // Extract data return new VbListMessage(type, community, seq); } VbListMessage::VbListMessage( Asn::Identifier type, const char *community, Asn::Sequence &seq) : Message(type, community) { // Format was already verified in CreateFromSequence() _reqid = seq[0]->AsInteger()->IntValue(); _errstatus = seq[1]->AsInteger()->IntValue(); _errindex = seq[2]->AsInteger()->IntValue(); _vblist = new VarBindList(*seq[3]->AsSequence()); } VbListMessage::VbListMessage( Asn::Identifier type, const char *community, int reqid) : Message(type, community), _reqid(reqid), _errstatus(0), _errindex(0), _vblist(new VarBindList()) { } void VbListMessage::Append(const Asn::ObjectId &oid, Variable *data) { _vblist->Append(oid, data); } Asn::Sequence *VbListMessage::GetAsn() { Asn::Sequence *seq = new Asn::Sequence(_type); seq->Append(new Asn::Integer(_reqid)); seq->Append(new Asn::Integer(_errstatus)); seq->Append(new Asn::Integer(_errindex)); seq->Append(_vblist->GetAsn()); return seq; } // ***************************************************************************** // Message // ***************************************************************************** Message *Message::Demarshal(unsigned char *&buffer, unsigned int &buflen) { Message *ret = NULL; astring community; Asn::Identifier type; Asn::Object *obj = Asn::Object::Demarshal(buffer, buflen); if (!obj) return NULL; // Data demarshalled okay. Now walk the object tree to parse the message. // Top-level object should be a sequence of length 3 Asn::Sequence &seq = *(Asn::Sequence*)obj; if (!obj->IsSequence() || seq.Size() != 3) goto error; // First item in sequence is an integer specifying SNMP version if (!seq[0]->IsInteger() || seq[0]->AsInteger()->IntValue() != SNMP_VERSION_1) goto error; // Second item is the community string if (!seq[1]->IsOctetString()) goto error; community = *seq[1]->AsOctetString(); // Third is another sequence containing the PDU type = seq[2]->Type(); switch (type) { case Asn::GET_REQ_PDU: case Asn::GETNEXT_REQ_PDU: case Asn::GET_RSP_PDU: ret = VbListMessage::CreateFromSequence( type, community, *seq[2]->AsSequence()); break; case Asn::TRAP_PDU: ret = TrapMessage::CreateFromSequence( type, community, *seq[2]->AsSequence()); break; default: break; } error: delete obj; return ret; } bool Message::Marshal(unsigned char *&buffer, unsigned int &buflen) { Asn::Sequence *seq = new Asn::Sequence(); seq->Append(new Asn::Integer(SNMP_VERSION_1)); seq->Append(new Asn::OctetString(_community)); seq->Append(GetAsn()); bool ret = seq->Marshal(buffer, buflen); delete seq; return ret; } // ***************************************************************************** // TrapMessage // ***************************************************************************** TrapMessage *TrapMessage::CreateFromSequence( Asn::Identifier type, const char *community, Asn::Sequence &seq) { // Verify format: We should have 6 parts. if (seq.Size() != 6 || !seq[0]->IsObjectId() || // enterprise !seq[1]->IsOctetString() || // agent-addr !seq[2]->IsInteger() || // generic-trap !seq[3]->IsInteger() || // specific-trap !seq[4]->IsInteger() || // time-stamp !seq[5]->IsSequence()) // variable-bindings return NULL; // Extract data return new TrapMessage(type, community, seq); } TrapMessage::TrapMessage( Asn::Identifier type, const char *community, Asn::Sequence &seq) : Message(type, community) { // Format was already verified in CreateFromSequence() _enterprise = seq[0]->copy()->AsObjectId(); _generic = seq[2]->AsInteger()->IntValue(); _specific = seq[3]->AsInteger()->IntValue(); _timestamp = seq[4]->AsInteger()->UintValue(); _vblist = new VarBindList(*seq[5]->AsSequence()); } apcupsd-3.14.14/src/drivers/snmplite/snmp.h000066400000000000000000000150211274230402600205500ustar00rootroot00000000000000/* * snmp.h * * SNMP client interface */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __SNMP_H #define __SNMP_H #include "apc.h" #include "astring.h" #include "aarray.h" #include "alist.h" #include "asn.h" namespace Snmp { // ************************************************************************** // Types // ************************************************************************** struct Variable { Variable() : valid(false) {} Variable(Asn::Identifier t, unsigned int i) : valid (true), type(t), i32(i), u32(i) {} bool valid; Asn::Identifier type; int i32; unsigned int u32; astring str; alist seq; }; // ************************************************************************** // VarBind // ************************************************************************** class VarBind { public: VarBind(const Asn::ObjectId &oid, Variable *data = NULL); VarBind(Asn::Sequence &seq); ~VarBind(); bool Extract(Variable *data); Asn::ObjectId &Oid() { return *_oid; } Asn::Sequence *GetAsn(); private: Asn::ObjectId *_oid; Asn::Object *_data; VarBind(const VarBind &rhs); VarBind &operator=(const VarBind &rhs); }; // ************************************************************************** // VarBindList // ************************************************************************** class VarBindList { public: VarBindList() {} VarBindList(Asn::Sequence &seq); ~VarBindList(); void Append(const Asn::ObjectId &oid, Variable *data = NULL); unsigned int Size() const { return _vblist.size(); } VarBind *operator[](unsigned int idx) { return _vblist[idx]; } Asn::Sequence *GetAsn(); private: aarray _vblist; VarBindList(const VarBindList &rhs); VarBindList &operator=(const VarBindList &rhs); }; // ************************************************************************** // Message // ************************************************************************** class Message { public: virtual ~Message() {} Asn::Identifier Type() const { return _type; } astring Community() const { return _community; } static Message *Demarshal(unsigned char *&buffer, unsigned int &buflen); bool Marshal(unsigned char *&buffer, unsigned int &buflen); protected: Message() {} Message(Asn::Identifier type, const char *community) : _type(type), _community(community) {} static const int SNMP_VERSION_1 = 0; virtual Asn::Sequence *GetAsn() = 0; Asn::Identifier _type; astring _community; }; // ************************************************************************** // VbListMessage // ************************************************************************** class VbListMessage: public Message { public: VbListMessage(Asn::Identifier type, const char *community, int reqid); virtual ~VbListMessage() { delete _vblist; } int RequestId() const { return _reqid; } int ErrorStatus() const { return _errstatus; } int ErrorIndex() const { return _errindex; } void Append(const Asn::ObjectId &oid, Variable *data = NULL); unsigned int Size() const { return _vblist->Size(); } VarBind &operator[](unsigned int idx) { return *((*_vblist)[idx]); } static VbListMessage *CreateFromSequence( Asn::Identifier type, const char *community, Asn::Sequence &seq); protected: VbListMessage( Asn::Identifier type, const char *community, Asn::Sequence &seq); virtual Asn::Sequence *GetAsn(); int _reqid; int _errstatus; int _errindex; VarBindList *_vblist; }; // ************************************************************************** // TrapMessage // ************************************************************************** class TrapMessage: public Message { public: virtual ~TrapMessage() { delete _vblist; } int Generic() const { return _generic; } int Specific() const { return _specific; } unsigned int Timestamp() const { return _timestamp; } static TrapMessage *CreateFromSequence( Asn::Identifier type, const char *community, Asn::Sequence &seq); protected: TrapMessage(Asn::Identifier type, const char *community, Asn::Sequence &seq); virtual Asn::Sequence *GetAsn() { return NULL; } Asn::ObjectId *_enterprise; int _generic; int _specific; unsigned int _timestamp; VarBindList *_vblist; }; // ************************************************************************** // SnmpEngine // ************************************************************************** class SnmpEngine { public: SnmpEngine(); ~SnmpEngine(); bool Open(const char *host, unsigned short port = SNMP_AGENT_PORT, const char *comm = "public"); bool EnableTraps(); void Close(); struct OidVar { const int *oid; Variable data; }; bool Get(const int oid[], Variable *data); bool Get(alist &oids); void GetSequence(const int oid[], Variable *data); bool Set(const int oid[], Variable *data); TrapMessage *TrapWait(unsigned int msec); void SetCommunity(const char *comm) { _community = comm; } private: bool issue(Message *pdu); Message *rspwait(unsigned int msec, bool trap = false); VbListMessage *perform(VbListMessage *req); static const unsigned short SNMP_TRAP_PORT = 162; static const unsigned short SNMP_AGENT_PORT = 161; sock_t _socket; sock_t _trapsock; int _reqid; astring _community; struct sockaddr_in _destaddr; }; }; #endif apcupsd-3.14.14/src/drivers/snmplite/snmplite-common.h000066400000000000000000000017211274230402600227160ustar00rootroot00000000000000/* * snmplite-common.h * * Public header for the SNMP Lite UPS driver */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _SNMPLITE_COMMON_H #define _SNMPLITE_COMMON_H #include "apc.h" #include "snmp.h" // For use by MIB strategies void snmplite_trap_wait(UPSINFO *ups); #endif /* _SNMPLITE_COMMON_H */ apcupsd-3.14.14/src/drivers/snmplite/snmplite.cpp000066400000000000000000000271371274230402600217740ustar00rootroot00000000000000/* * snmp.c * * SNMP Lite UPS driver */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "snmplite.h" #include "snmplite-common.h" #include "snmp.h" #include "mibs.h" SnmpLiteUpsDriver::SnmpLiteUpsDriver(UPSINFO *ups) : UpsDriver(ups), _host(NULL), _port(0), _vendor(NULL), _community(NULL), _snmp(NULL), _error_count(0), _commlost_time(0), _strategy(NULL), _traps(false) { memset(_device, 0, sizeof(_device)); } const char *SnmpLiteUpsDriver::snmplite_probe_community() { const int sysDescrOid[] = {1, 3, 6, 1, 2, 1, 1, 1, -1}; const char *communityList[] = { "private", "public", NULL }; Dmsg(80, "Performing community autodetection\n"); for (unsigned int i = 0; communityList[i]; i++) { Dmsg(80, "Probing community: \"%s\"\n", communityList[i]); _snmp->SetCommunity(communityList[i]); Snmp::Variable result; result.type = Asn::OCTETSTRING; if (_snmp->Get(sysDescrOid, &result) && result.valid) return communityList[i]; } return NULL; } const MibStrategy *SnmpLiteUpsDriver::snmplite_probe_mib() { Dmsg(80, "Performing MIB autodetection\n"); // Every MIB strategy should have a CI_STATUS mapping in its OID map. // The generic probe method is simply to query for this OID and assume // we have found a supported MIB if the query succeeds. for (unsigned int i = 0; MibStrategies[i]; i++) { Dmsg(80, "Probing MIB: \"%s\"\n", MibStrategies[i]->name); for (unsigned int j = 0; MibStrategies[i]->mib[j].ci != -1; j++) { if (MibStrategies[i]->mib[j].ci == CI_STATUS) { Snmp::Variable result; result.type = MibStrategies[i]->mib[j].type; if (_snmp->Get(MibStrategies[i]->mib[j].oid, &result) && result.valid) return MibStrategies[i]; } } } return NULL; } bool SnmpLiteUpsDriver::Open() { _port = 161; _community = NULL; // autodetect _vendor = NULL; // autodetect _traps = true; if (*_ups->device == '\0') { log_event(_ups, LOG_ERR, "snmplite Missing hostname"); exit(1); } strlcpy(_device, _ups->device, sizeof(_device)); /* * Split the DEVICE statement and assign pointers to the various parts. * The DEVICE statement syntax in apcupsd.conf is: * * DEVICE address[:port[:vendor[:community]]] * * vendor can be "APC", "RFC", "MGE" or "*_NOTRAP". */ char *cp = _device; _host = _device; cp = strchr(cp, ':'); if (cp) { *cp++ = '\0'; if (*cp != ':') { _port = atoi(cp); if (_port == 0) { log_event(_ups, LOG_ERR, "snmplite Bad port number"); exit(1); } } cp = strchr(cp, ':'); if (cp) { *cp++ = '\0'; if (*cp != ':') _vendor = cp; cp = strchr(cp, ':'); if (cp) { *cp++ = '\0'; if (*cp) _community = cp; } } } // If user supplied a vendor, check for and remove "NOTRAP" and // optional underscore. Underscore is optional to allow use of vendor // "NOTRAP" to get autodetect with trap catching disabled. if (_vendor) { char *ptr = strstr((char*)_vendor, "NOTRAP"); if (ptr) { // Trap catching is disabled _traps = false; // Remove "NOTRAP" from vendor string *ptr-- = '\0'; // Remove optional underscore if (ptr >= _vendor && *ptr == '_') *ptr = '\0'; // If nothing left, kill vendor to enable autodetect if (*_vendor == '\0') _vendor = NULL; } } Dmsg(80, "Trap catching: %sabled\n", _traps ? "En" : "Dis"); // Create SNMP engine _snmp = new Snmp::SnmpEngine(); if (!_snmp->Open(_host, _port, "dummy")) { log_event(_ups, LOG_ERR, "snmplite Unable to initialize SNMP"); exit(1); } // Enable trap catching if user requested it if (_traps && !_snmp->EnableTraps()) { // Failure to enable trap catching is not fatal. Probably just means // SNMP trap port is already in use by snmptrapd or another instance // of apcupsd. Warn user and continue. log_event(_ups, LOG_WARNING, "snmplite Failed to enable traps"); _traps = false; } // If user did not specify a community, probe for one if (!_community) { _community = snmplite_probe_community(); if (!_community) { log_event(_ups, LOG_ERR, "snmplite Unable to detect community"); exit(1); } } _snmp->SetCommunity(_community); Dmsg(80, "Selected community: \"%s\"\n", _community); // If user supplied a vendor, search for a matching MIB strategy, // otherwise attempt to autodetect if (_vendor) { for (unsigned int i = 0; MibStrategies[i]; i++) { if (strcasecmp(MibStrategies[i]->name, _vendor) == 0) { _strategy = MibStrategies[i]; break; } } } else { _strategy = snmplite_probe_mib(); } if (!_strategy) { log_event(_ups, LOG_ERR, "snmplite Invalid vendor or unsupported MIB"); exit(1); } Dmsg(80, "Selected MIB: \"%s\"\n", _strategy->name); return true; } bool SnmpLiteUpsDriver::Close() { write_lock(_ups); _snmp->Close(); delete _snmp; write_unlock(_ups); return true; } bool snmplite_ups_check_ci(int ci, Snmp::Variable &data) { // Sanity check a few values that SNMP UPSes claim to report but seem // to always come back as zeros. switch (ci) { // SmartUPS 1000 is returning 0 or -1 for this via SNMP so screen it out // in case this is a common issue. Expected values would be 12/24/48 but // allow up to 120 for a really large UPS. case CI_NOMBATTV: return data.i32 > 0 && data.i32 <= 120; // SmartUPS 1000 is returning -1 for this. case CI_BADBATTS: return data.i32 > -1; // Generex CS121 SNMP/WEB Adapter using RFC1628 MIB is returning zero for // these values on a Newave Conceptpower DPA UPS. case CI_LTRANS: case CI_HTRANS: case CI_NOMOUTV: case CI_NOMINV: case CI_NOMPOWER: return data.i32 > 0; } return true; } bool SnmpLiteUpsDriver::get_capabilities() { write_lock(_ups); // Walk the OID map, issuing an SNMP query for each item, one at a time. // If the query succeeds, sanity check the returned value and set the // capabilities flag. CiOidMap *mib = _strategy->mib; for (unsigned int i = 0; mib[i].ci != -1; i++) { Snmp::Variable data; data.type = mib[i].type; _ups->UPS_Cap[mib[i].ci] = _snmp->Get(mib[i].oid, &data) && data.valid && snmplite_ups_check_ci(mib[i].ci, data); } write_unlock(_ups); // Succeed if we found CI_STATUS return _ups->UPS_Cap[CI_STATUS]; } bool SnmpLiteUpsDriver::kill_power() { if (_strategy->killpower_func) return _strategy->killpower_func(_snmp); return false; } bool SnmpLiteUpsDriver::shutdown() { if (_strategy->shutdown_func) return _strategy->shutdown_func(_snmp); return false; } bool SnmpLiteUpsDriver::check_state() { if (_traps) { // Simple trap handling: Any valid trap causes us to return and thus // new data will be fetched from the UPS. Snmp::TrapMessage *trap = _snmp->TrapWait(_ups->wait_time * 1000); if (trap) { Dmsg(80, "Got TRAP: generic=%d, specific=%d\n", trap->Generic(), trap->Specific()); delete trap; } } else sleep(_ups->wait_time); return true; } bool SnmpLiteUpsDriver::update_cis(bool dynamic) { CiOidMap *mib = _strategy->mib; // Walk OID map and build a query for all parameters we have that // match the requested 'dynamic' setting Snmp::SnmpEngine::OidVar oidvar; alist oids; for (unsigned int i = 0; mib[i].ci != -1; i++) { if (_ups->UPS_Cap[mib[i].ci] && mib[i].dynamic == dynamic) { oidvar.oid = mib[i].oid; oidvar.data.type = mib[i].type; oids.append(oidvar); } } // Issue the query, bail if it fails if (!_snmp->Get(oids)) return false; // Walk the OID map again to correlate results with CIs and invoke the // update function to set the values. alist::iterator iter = oids.begin(); for (unsigned int i = 0; mib[i].ci != -1; i++) { if (_ups->UPS_Cap[mib[i].ci] && mib[i].dynamic == dynamic && (*iter).data.valid && ((*iter).data.type != Asn::SEQUENCE || // Skip update if sequence (*iter).data.seq.size() != 0)) // is empty { _strategy->update_ci_func(_ups, mib[i].ci, (*iter).data); ++iter; } } return true; } bool SnmpLiteUpsDriver::read_volatile_data() { write_lock(_ups); int ret = update_cis(true); time_t now = time(NULL); if (ret) { // Successful query _error_count = 0; _ups->poll_time = now; /* save time stamp */ // If we were commlost, we're not any more if (_ups->is_commlost()) { _ups->clear_commlost(); generate_event(_ups, CMDCOMMOK); } } else { // Query failed. Close and reopen SNMP to help recover. _snmp->Close(); _snmp->Open(_host, _port, _community); if (_traps) _snmp->EnableTraps(); if (_ups->is_commlost()) { // We already know we're commlost. // Log an event every 10 minutes. if ((now - _commlost_time) >= 10*60) { _commlost_time = now; log_event(_ups, event_msg[CMDCOMMFAILURE].level, event_msg[CMDCOMMFAILURE].msg); } } else { // Check to see if we've hit enough errors to declare commlost. // If we have, set commlost flag and log an event. if (++_error_count >= 3) { _commlost_time = now; _ups->set_commlost(); generate_event(_ups, CMDCOMMFAILURE); } } } write_unlock(_ups); return ret; } bool SnmpLiteUpsDriver::read_static_data() { write_lock(_ups); int ret = update_cis(false); write_unlock(_ups); return ret; } bool SnmpLiteUpsDriver::entry_point(int command, void *data) { switch (command) { case DEVICE_CMD_CHECK_SELFTEST: Dmsg(80, "Checking self test.\n"); /* Reason for last transfer to batteries */ if (_ups->UPS_Cap[CI_WHY_BATT] && update_cis(true)) { Dmsg(80, "Transfer reason: %d\n", _ups->lastxfer); /* See if this is a self test rather than power failure */ if (_ups->lastxfer == XFER_SELFTEST) { /* * set Self Test start time */ _ups->SelfTest = time(NULL); Dmsg(80, "Self Test time: %s", ctime(&_ups->SelfTest)); } } break; case DEVICE_CMD_GET_SELFTEST_MSG: default: return FAILURE; } return SUCCESS; } apcupsd-3.14.14/src/drivers/snmplite/snmplite.h000066400000000000000000000061421274230402600214320ustar00rootroot00000000000000/* * snmplite.h * * Public header for the SNMP Lite UPS driver */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _SNMPLITE_H #define _SNMPLITE_H //#include "snmp.h" namespace Snmp { class SnmpEngine; struct Variable; }; // Forward declarations struct MibStrategy; class SnmpLiteUpsDriver: public UpsDriver { public: SnmpLiteUpsDriver(UPSINFO *ups); virtual ~SnmpLiteUpsDriver() {} static UpsDriver *Factory(UPSINFO *ups) { return new SnmpLiteUpsDriver(ups); } virtual bool get_capabilities(); virtual bool read_volatile_data(); virtual bool read_static_data(); virtual bool kill_power(); virtual bool check_state(); virtual bool Open(); virtual bool Close(); virtual bool entry_point(int command, void *data); virtual bool shutdown(); private: const char *snmplite_probe_community(); const MibStrategy *snmplite_probe_mib(); bool update_cis(bool dynamic); static bool check_ci(int ci, Snmp::Variable &data); char _device[MAXSTRING]; /* Copy of ups->device */ const char *_host; /* hostname|IP of peer */ unsigned short _port; /* Remote port, usually 161 */ const char *_vendor; /* SNMP vendor: APC or APC_NOTRAP */ const char *_community; /* Community name */ Snmp::SnmpEngine *_snmp; /* SNMP engine instance */ int _error_count; /* Number of consecutive SNMP network errors */ time_t _commlost_time; /* Time at which we declared COMMLOST */ const MibStrategy *_strategy; /* MIB strategy to use */ bool _traps; /* true if catching SNMP traps */ }; /*********************************************************************/ /* Public Function ProtoTypes */ /*********************************************************************/ extern int snmplite_ups_get_capabilities(UPSINFO *ups); extern int snmplite_ups_read_volatile_data(UPSINFO *ups); extern int snmplite_ups_read_static_data(UPSINFO *ups); extern int snmplite_ups_kill_power(UPSINFO *ups); extern int snmplite_ups_shutdown(UPSINFO *ups); extern int snmplite_ups_check_state(UPSINFO *ups); extern int snmplite_ups_open(UPSINFO *ups); extern int snmplite_ups_close(UPSINFO *ups); extern int snmplite_ups_setup(UPSINFO *ups); extern int snmplite_ups_program_eeprom(UPSINFO *ups, int command, const char *data); extern int snmplite_ups_entry_point(UPSINFO *ups, int command, void *data); #endif /* _SNMPLITE_H */ apcupsd-3.14.14/src/drivers/snmplite/traps.h000066400000000000000000000107441274230402600207330ustar00rootroot00000000000000/* * traps.h * * Mappings for APC UPS SNMP trap ids */ #ifndef __TRAPS_H_ #define __TRAPS_H_ #define TRAP_COMMUNICATIONLOST 1 #define TRAP_UPSOVERLOAD 2 #define TRAP_UPSDIAGNOSTICSFAILED 3 #define TRAP_UPSDISCHARGED 4 #define TRAP_UPSONBATTERY 5 #define TRAP_SMARTBOOSTON 6 #define TRAP_LOWBATTERY 7 #define TRAP_COMMUNICATIONESTABLISHED 8 #define TRAP_POWERRESTORED 9 #define TRAP_UPSDIAGNOSTICSPASSED 10 #define TRAP_RETURNFROMLOWBATTERY 11 #define TRAP_UPSTURNEDOFF 12 #define TRAP_UPSSLEEPING 13 #define TRAP_UPSWOKEUP 14 #define TRAP_UPSREBOOTSTARTED 15 #define TRAP_UPSDIPSWITCHCHANGED 16 #define TRAP_UPSBATTERYNEEDSREPLACEMENT 17 #define TRAP_CONTACTFAULT 18 #define TRAP_CONTACTFAULTRESOLVED 19 #define TRAP_HARDWAREFAILUREBYPASS 20 #define TRAP_SOFTWAREBYPASS 21 #define TRAP_SWITCHEDBYPASS 22 #define TRAP_RETURNFROMBYPASS 23 #define TRAP_BYPASSPOWERSUPPLYFAILURE 24 #define TRAP_BASEFANFAILURE 25 #define TRAP_BATTERYPACKCOMMLOST 26 #define TRAP_BATTERYPACKCOMMESTABLISHED 27 #define TRAP_CALIBRATIONSTART 28 #define TRAP_RESTARTAGENT 29 #define TRAP_UPSTURNEDON 30 #define TRAP_SMARTAVRREDUCING 31 #define TRAP_CODEAUTHENTICATIONDONE 32 #define TRAP_UPSOVERLOADCLEARED 33 #define TRAP_SMARTBOOSTOFF 34 #define TRAP_SMARTAVRREDUCINGOFF 35 #define TRAP_UPSBATTERYREPLACED 36 #define TRAP_CALIBRATIONEND 37 #define TRAP_DISCHARGECLEARED 38 #define TRAP_GRACEFULLSHUTDOWN 39 #define TRAP_OUTLETON 41 #define TRAP_OUTLETOFF 42 #define TRAP_OUTLETREBOOT 43 #define TRAP_CONFIGCHANGESNMP 44 #define TRAP_CONFIGCHANGEOUTLET 45 #define TRAP_ACCESSVIOLATIONCONSOLE 46 #define TRAP_ACCESSVIOLATIONHTTP 47 #define TRAP_PASSWORDCHANGE 48 #define TRAP_BADVOLTAGE 49 #define TRAP_BADVOLTAGECLEARED 50 #define TRAP_CHARGERFAILURE 51 #define TRAP_CHARGERFAILURECLEARED 52 #define TRAP_BATTERYOVERTEMPERATURE 53 #define TRAP_BATTERYOVERTEMPERATURECLEARED 54 #define TRAP_SMARTRELAYFAULT 55 #define TRAP_SMARTRELAYFAULTCLEARED 56 #define TRAP_HUMIDITYTHRESHOLDVIOLATION1 57 #define TRAP_HUMIDITYTHRESHOLDVIOLATIONCLEARED1 58 #define TRAP_TEMPERATURETHRESHOLDVIOLATION1 59 #define TRAP_TEMPERATURETHRESHOLDVIOLATIONCLEARED1 60 #define TRAP_HUMIDITYTHRESHOLDVIOLATION2 61 #define TRAP_HUMIDITYTHRESHOLDVIOLATIONCLEARED2 62 #define TRAP_TEMPERATURETHRESHOLDVIOLATION2 63 #define TRAP_TEMPERATURETHRESHOLDVIOLATIONCLEARED2 64 #define TRAP_MUPSCOMMUNICATIONESTABLISHED 65 #define TRAP_MUPSCOMMUNICATIONLOST 66 #define TRAP_BATTERYINCREASE 67 #define TRAP_BATTERYDECREASE 68 #define TRAP_POWERMODULEINCREASE 69 #define TRAP_POWERMODULEDECREASE 70 #define TRAP_INTELLIGENCEMODULEINSERTED 71 #define TRAP_INTELLIGENCEMODULEREMOVED 72 #define TRAP_RINTELLIGENCEMODULEINSERTED 73 #define TRAP_RINTELLIGENCEMODULEREMOVED 74 #define TRAP_EXTBATTERYFRAMEINCEASE 75 #define TRAP_EXTBATTERYFRAMEDECREASE 76 #define TRAP_ABNORMALCONDITION 77 #define TRAP_ABNORMALCONDITIONCLEARED 78 #define TRAP_DEVICESTATUSCHANGE 79 #define TRAP_NOBATTERIES 80 #define TRAP_NOBATTERIESCLEARED 81 #define TRAP_USERADDED 82 #define TRAP_USERDELETED 83 #define TRAP_USERMODIFIED 84 #endif apcupsd-3.14.14/src/drivers/test/000077500000000000000000000000001274230402600165475ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/test/Makefile000066400000000000000000000002671274230402600202140ustar00rootroot00000000000000topdir:=../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) all-targets: libtestdrv.a libtestdrv.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/test/testdriver.c000066400000000000000000000100141274230402600211020ustar00rootroot00000000000000/* * testdriver.c * * Interface for apcupsd to the Test driver. */ /* * Copyright (C) 2001-2006 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "testdriver.h" TestUpsDriver::TestUpsDriver(UPSINFO *ups) : UpsDriver(ups) { } /* */ bool TestUpsDriver::open_test_device() { _ups->fd = 1; return true; } /* * Read UPS events. I.e. state changes. */ bool TestUpsDriver::check_state() { return true; } /* * Open test port */ bool TestUpsDriver::Open() { write_lock(_ups); if (!open_test_device()) Error_abort("Cannot open UPS device %s\n", _ups->device); _ups->clear_slave(); write_unlock(_ups); return true; } bool TestUpsDriver::Close() { write_lock(_ups); /* Seems that there is nothing to do. */ _ups->fd = -1; write_unlock(_ups); return true; } /* * Setup capabilities structure for UPS */ bool TestUpsDriver::get_capabilities() { int k; write_lock(_ups); for (k = 0; k <= CI_MAX_CAPS; k++) _ups->UPS_Cap[k] = TRUE; write_unlock(_ups); return true; } /* * Read UPS info that remains unchanged -- e.g. transfer * voltages, shutdown delay, ... * * This routine is called once when apcupsd is starting */ bool TestUpsDriver::read_static_data() { write_lock(_ups); /* UPS_NAME */ /* model, firmware */ strlcpy(_ups->upsmodel, "Test Driver", sizeof(_ups->upsmodel)); strlcpy(_ups->firmrev, "Rev 1.0", sizeof(_ups->firmrev)); strlcpy(_ups->selftest, "336", sizeof(_ups->selftest)); /* WAKEUP_DELAY */ _ups->dwake = 2 * 60; /* SLEEP_DELAY */ _ups->dshutd = 2 * 60; /* LOW_TRANSFER_LEVEL */ _ups->lotrans = 190; /* HIGH_TRANSFER_LEVEL */ _ups->hitrans = 240; /* UPS_BATT_CAP_RETURN */ _ups->rtnpct = 15; /* LOWBATT_SHUTDOWN_LEVEL */ _ups->dlowbatt = 2; /* UPS_MANUFACTURE_DATE */ strlcpy(_ups->birth, "2001-09-21", sizeof(_ups->birth)); /* Last UPS_BATTERY_REPLACE */ strlcpy(_ups->battdat, "2001-09-21", sizeof(_ups->battdat)); /* UPS_SERIAL_NUMBER */ strlcpy(_ups->serial, "NO-123456", sizeof(_ups->serial)); /* Nominal output voltage when on batteries */ _ups->NomOutputVoltage = 230; /* Nominal battery voltage */ _ups->nombattv = (double)12; write_unlock(_ups); return true; } /* * Read UPS info that changes -- e.g. Voltage, temperature, ... * * This routine is called once every 5 seconds to get * a current idea of what the UPS is doing. */ bool TestUpsDriver::read_volatile_data() { /* save time stamp */ time(&_ups->poll_time); write_lock(_ups); /* UPS_STATUS -- this is the most important status for apcupsd */ /* No APC Status value, well, fabricate one */ _ups->Status = 0; _ups->set_online(); /* LINE_VOLTAGE */ _ups->LineVoltage = 229.5; _ups->LineMin = 225.0; _ups->LineMax = 230.0; /* OUTPUT_VOLTAGE */ _ups->OutputVoltage = 228.5; /* BATT_FULL Battery level percentage */ _ups->BattChg = 100; /* BATT_VOLTAGE */ _ups->BattVoltage = 12.5; /* UPS_LOAD */ _ups->UPSLoad = 40.5; /* LINE_FREQ */ _ups->LineFreq = 50; /* UPS_RUNTIME_LEFT */ _ups->TimeLeft = ((double)20 * 60); /* seconds */ /* UPS_TEMP */ _ups->UPSTemp = 32.4; /* Humidity percentage */ _ups->humidity = 50.1; /* Ambient temperature */ _ups->ambtemp = 22.5; /* Self test results */ _ups->testresult = TEST_PASSED; write_unlock(_ups); return true; } apcupsd-3.14.14/src/drivers/test/testdriver.h000066400000000000000000000024041274230402600211130ustar00rootroot00000000000000/* * testdriver.h * * Public header file for the test driver. */ /* * Copyright (C) 2001-2006 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _TESTDRIVER_H #define _TESTDRIVER_H class TestUpsDriver: public UpsDriver { public: TestUpsDriver(UPSINFO *ups); virtual ~TestUpsDriver() {} static UpsDriver *Factory(UPSINFO *ups) { return new TestUpsDriver(ups); } virtual bool get_capabilities(); virtual bool read_volatile_data(); virtual bool read_static_data(); virtual bool check_state(); virtual bool Open(); virtual bool Close(); private: bool open_test_device(); }; #endif /* _TEST_DRIVER_H */ apcupsd-3.14.14/src/drivers/usb/000077500000000000000000000000001274230402600163615ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/usb/Makefile000066400000000000000000000004631274230402600200240ustar00rootroot00000000000000topdir:=../../.. SUBDIRS = $(USBTYPE) include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) OBJS += $(call SRC2OBJ,$(wildcard $(USBTYPE)/*.c)) OBJS += $(call SRC2OBJ,$(wildcard $(USBTYPE)/*.cpp)) all-targets: libusbdrv.a libusbdrv.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/usb/bsd/000077500000000000000000000000001274230402600171315ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/usb/bsd/Makefile000066400000000000000000000002221274230402600205650ustar00rootroot00000000000000topdir:=../../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) all-targets: $(OBJS) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/usb/bsd/bsd-usb.c000066400000000000000000000533001274230402600206350ustar00rootroot00000000000000/* * bsd-usb.c * * Platform-specific USB module for *BSD ugen USB driver. * * Based on linux-usb.c by Kerb Sibbald. */ /* * Copyright (C) 2004-2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "hidutils.h" #include "bsd-usb.h" #include #include /* Compatibility cruft for FreeBSD <= 4.7 */ #ifndef USB_MAX_DEVNAMES #define USB_MAX_DEVNAMES MAXDEVNAMES #endif #ifndef USB_MAX_DEVNAMELEN #define USB_MAX_DEVNAMELEN MAXDEVNAMELEN #endif UpsDriver *UsbUpsDriver::Factory(UPSINFO *ups) { return new BsdUsbUpsDriver(ups); } BsdUsbUpsDriver::BsdUsbUpsDriver(UPSINFO *ups) : UsbUpsDriver(ups), _fd(-1), _intfd(-1), _linkcheck(false) { memset(_orig_device, 0, sizeof(_orig_device)); memset(&_rdesc, 0, sizeof(_rdesc)); memset(_info, 0, sizeof(_info)); } void BsdUsbUpsDriver::reinitialize_private_structure() { int k; Dmsg(200, "Reinitializing private structure.\n"); /* * We are being reinitialized, so clear the Cap * array, and release previously allocated memory. */ for (k = 0; k <= CI_MAXCI; k++) { _ups->UPS_Cap[k] = false; if (_info[k] != NULL) { free(_info[k]); _info[k] = NULL; } } } /* * Initializes the USB device by fetching its report descriptor * and making sure we can drive the device. */ bool BsdUsbUpsDriver::init_device(const char *devname) { int fd, rc, rdesclen; struct usb_device_info devinfo; unsigned char *rdesc; char intdevname[USB_MAX_DEVNAMELEN + 5 + 3 + 1]; fd = open(devname, O_RDWR | O_NOCTTY | O_CLOEXEC); if (fd == -1) return false; memset(&devinfo, 0, sizeof(devinfo)); rc = ioctl(fd, USB_GET_DEVICEINFO, &devinfo); if (rc) { close(fd); Dmsg(100, "Unable to get device info.\n"); return false; } /* Fetch the report descritor */ rdesc = hidu_fetch_report_descriptor(fd, &rdesclen); if (!rdesc) { close(fd); Dmsg(100, "Unable to fetch report descriptor.\n"); return false; } /* Initialize hid parser with this descriptor */ _rdesc = hid_use_report_desc(rdesc, rdesclen); if (!_rdesc) { free(rdesc); close(fd); Dmsg(100, "Unable to init parser with report descriptor.\n"); return false; } free(rdesc); /* Does this device have an UPS application collection? */ if (!hidu_locate_item( _rdesc, UPS_USAGE, /* Match usage code */ -1, /* Don't care about application */ -1, /* Don't care about physical usage */ -1, /* Don't care about logical */ HID_KIND_COLLECTION, /* Match collection type */ NULL)) { hid_dispose_report_desc(_rdesc); close(fd); Dmsg(100, "Device does not have an UPS application collection.\n"); return false; } _fd = fd; /* Open the interrupt pipe */ strlcpy(intdevname, devname, sizeof(intdevname)); #ifdef HAVE_FREEBSD_OS /* ugen0 -> ugen0.1 */ strlcat(intdevname, ".1", sizeof(intdevname)); #else /* ugen0.00 -> ugen0.01 */ intdevname[strlen(intdevname) - 1] = '1'; #endif fd = open(intdevname, O_RDONLY | O_NOCTTY | O_CLOEXEC); if (fd == -1) { Dmsg(100, "Unable to open interrupt pipe %s: %s\n", intdevname, strerror(errno)); hid_dispose_report_desc(_rdesc); close(_fd); _fd = -1; return false; } _intfd = fd; return true; } /* * Internal routine to open the device and ensure that there is a UPS * application on the line. This routine may be called many times * because the device may be unplugged and plugged back in -- the * joys of USB devices. */ bool BsdUsbUpsDriver::open_usb_device() { int i, j, k, fd, rc; char busname[] = "/dev/usbN"; char devname[USB_MAX_DEVNAMELEN + 5 + 1]; struct usb_device_info devinfo; /* * Note, we set _ups->fd here so the "core" of apcupsd doesn't * think we are a slave, which is what happens when it is -1. * (ADK: Actually this only appears to be true for apctest as * apcupsd proper uses the UPS_slave flag.) * Internally, we use the fd in our own private space */ _ups->fd = 1; /* * If no device location specified, we go autodetect it * by searching known places. */ if (_ups->device[0] == 0) goto auto_detect; if (_orig_device[0] == 0) strlcpy(_orig_device, _ups->device, sizeof(_orig_device)); /* * No range support yet... Name the device specifically or we will * search them all. */ for (i = 0; i < 10; i++) { if (init_device(_ups->device)) return true; sleep(1); } /* * If the above device specified by the user fails, * fall through here and look in predefined places * for the device. */ auto_detect: /* * We could just start trying to open the /dev/ugenN devices, * one after another, but BSD gives us a decent way to enumerate * them. We might as well be polite and use it. */ /* Max of 10 USB busses */ for (i = 0; i < 10; i++) { busname[8] = '0' + i; fd = open(busname, O_RDWR | O_NOCTTY | O_CLOEXEC); if (fd == -1) continue; Dmsg(200, "Found bus %s.\n", busname); /* Max 127 devices per bus */ for (j = 0; j < 127; j++) { memset(&devinfo, 0, sizeof(devinfo)); devinfo.udi_addr = j; rc = ioctl(fd, USB_DEVICEINFO, &devinfo); if (rc) continue; /* See if this device is bound to ugen driver */ for (k = 0; k < USB_MAX_DEVNAMES; k++) if (strncmp(devinfo.udi_devnames[k], "ugen", 4) == 0) break; if (k < USB_MAX_DEVNAMES) { strlcpy(devname, "/dev/", sizeof(devname)); strlcat(devname, devinfo.udi_devnames[k], sizeof(devname)); #if defined(HAVE_OPENBSD_OS) || defined(HAVE_NETBSD_OS) strlcat(devname, ".00", sizeof(devname)); #endif Dmsg(200, "Trying device %s.\n", devname); if (init_device(devname)) { strlcpy(_ups->device, devname, sizeof(_ups->device)); return true; } } } close(fd); } _ups->device[0] = 0; return false; } /* * Called if there is an ioctl() or read() error, we close() and * re open() the port since the device was probably unplugged. */ bool BsdUsbUpsDriver::usb_link_check() { bool comm_err = true; int tlog; bool once = true; if (_linkcheck) return false; _linkcheck = true; /* prevent recursion */ _ups->set_commlost(); Dmsg(200, "link_check comm lost\n"); /* Don't warn until we try to get it at least 2 times and fail */ for (tlog = LINK_RETRY_INTERVAL * 2; comm_err; tlog -= (LINK_RETRY_INTERVAL)) { if (tlog <= 0) { tlog = 10 * 60; /* notify every 10 minutes */ log_event(_ups, event_msg[CMDCOMMFAILURE].level, event_msg[CMDCOMMFAILURE].msg); if (once) { /* execute script once */ execute_command(_ups, ups_event[CMDCOMMFAILURE]); once = false; } } /* Retry every LINK_RETRY_INTERVAL seconds */ sleep(LINK_RETRY_INTERVAL); if (_fd >= 0) { close(_fd); _fd = -1; close(_intfd); _intfd = -1; hid_dispose_report_desc(_rdesc); reinitialize_private_structure(); } if (open_usb_device() && get_capabilities() && read_static_data()) { comm_err = false; } else { continue; } } if (!comm_err) { generate_event(_ups, CMDCOMMOK); _ups->clear_commlost(); Dmsg(200, "link check comm OK.\n"); } _linkcheck = false; return true; } bool BsdUsbUpsDriver::pusb_ups_get_capabilities() { int i, input, feature, ci, phys, logi; hid_item_t input_item, feature_item, item; USB_INFO *info; write_lock(_ups); for (i = 0; _known_info[i].usage_code; i++) { ci = _known_info[i].ci; phys = _known_info[i].physical; logi = _known_info[i].logical; if (ci != CI_NONE && !_info[ci]) { /* Try to find an INPUT report containing this usage */ input = hidu_locate_item( _rdesc, _known_info[i].usage_code, /* Match usage code */ -1, /* Don't care about application */ (phys == P_ANY) ? -1 : phys, /* Match physical usage */ (logi == P_ANY) ? -1 : logi, /* Match logical usage */ HID_KIND_INPUT, /* Match feature type */ &input_item); /* Try to find a FEATURE report containing this usage */ feature = hidu_locate_item( _rdesc, _known_info[i].usage_code, /* Match usage code */ -1, /* Don't care about application */ (phys == P_ANY) ? -1 : phys, /* Match physical usage */ (logi == P_ANY) ? -1 : logi, /* Match logical usage */ HID_KIND_FEATURE, /* Match feature type */ &feature_item); /* * Choose which report to use. We prefer FEATURE since some UPSes * have broken INPUT reports, but we will fall back on INPUT if * FEATURE is not available. */ if (feature) item = feature_item; else if (input) item = input_item; else continue; // No valid report, bail _ups->UPS_Cap[ci] = true; _ups->UPS_Cmd[ci] = _known_info[i].usage_code; info = (USB_INFO *)malloc(sizeof(USB_INFO)); if (!info) { write_unlock(_ups); Error_abort("Out of memory.\n"); } // Populate READ report data _info[ci] = info; memset(info, 0, sizeof(*info)); info->ci = ci; info->usage_code = item.usage; info->unit_exponent = item.unit_exponent; info->unit = item.unit; info->data_type = _known_info[i].data_type; info->item = item; info->report_len = hid_report_size( /* +1 for report id */ _rdesc, item.kind, item.report_ID) + 1; Dmsg(200, "Got READ ci=%d, rpt=%d (len=%d), usage=0x%x (len=%d), kind=0x%02x\n", ci, item.report_ID, info->report_len, _known_info[i].usage_code, item.report_size, item.kind); // If we have a FEATURE report, use that as the writable report if (feature) { info->witem = item; Dmsg(200, "Got WRITE ci=%d, rpt=%d (len=%d), usage=0x%x (len=%d), kind=0x%02x\n", ci, item.report_ID, info->report_len, _known_info[i].usage_code, item.report_size, item.kind); } } } _ups->UPS_Cap[CI_STATUS] = true; /* we always have status flag */ write_unlock(_ups); return 1; } bool BsdUsbUpsDriver::populate_uval(USB_INFO *info, unsigned char *data, USB_VALUE *uval) { const char *str; int exponent; USB_VALUE val; /* data+1 skips the report tag byte */ info->value = hid_get_data(data+1, &info->item); exponent = info->unit_exponent; if (exponent > 7) exponent = exponent - 16; if (info->data_type == T_INDEX) { /* get string */ if (info->value == 0) return false; str = hidu_get_string(_fd, info->value); if (!str) return false; strlcpy(val.sValue, str, sizeof(val.sValue)); val.value_type = V_STRING; Dmsg(200, "Def val=%d exp=%d sVal=\"%s\" ci=%d\n", info->value, exponent, val.sValue, info->ci); } else if (info->data_type == T_UNITS) { val.value_type = V_DOUBLE; switch (info->unit) { case 0x00F0D121: val.UnitName = "Volts"; exponent -= 7; /* remove bias */ break; case 0x00100001: exponent += 2; /* remove bias */ val.UnitName = "Amps"; break; case 0xF001: val.UnitName = "Hertz"; break; case 0x1001: val.UnitName = "Seconds"; break; case 0xD121: exponent -= 7; /* remove bias */ val.UnitName = "Watts"; break; case 0x010001: val.UnitName = "Degrees K"; break; case 0x0101001: val.UnitName = "AmpSecs"; if (exponent == 0) val.dValue = info->value; else val.dValue = ((double)info->value) * pow_ten(exponent); break; default: val.UnitName = ""; val.value_type = V_INTEGER; val.iValue = info->value; break; } if (exponent == 0) val.dValue = info->value; else val.dValue = ((double)info->value) * pow_ten(exponent); // Store a (possibly truncated) copy of the floating point value in the // integer field as well. val.iValue = (int)val.dValue; Dmsg(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info->value, exponent, val.dValue, info->ci); } else { /* should be T_NONE */ val.UnitName = ""; val.value_type = V_INTEGER; val.iValue = info->value; if (exponent == 0) val.dValue = info->value; else val.dValue = ((double)info->value) * pow_ten(exponent); Dmsg(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info->value, exponent, val.dValue, info->ci); } memcpy(uval, &val, sizeof(*uval)); return true; } /* * Get a field value */ bool BsdUsbUpsDriver::pusb_get_value(int ci, USB_VALUE *uval) { USB_INFO *info = _info[ci]; unsigned char data[20]; int len; /* * Note we need to check info since CI_STATUS is always true * even when the UPS doesn't directly support that CI. */ if (!UPS_HAS_CAP(ci) || !info) return false; /* UPS does not have capability */ /* * Clear the destination buffer. In the case of a short transfer (see * below) this will increase the likelihood of extracting the correct * value in spite of the missing data. */ memset(data, 0, sizeof(data)); /* Fetch the proper report */ len = hidu_get_report(_fd, &info->item, data, info->report_len); if (len == -1) return false; /* * Some UPSes seem to have broken firmware that sends a different number * of bytes (usually fewer) than the report descriptor specifies. On * UHCI controllers under *BSD, this can lead to random lockups. To * reduce the likelihood of a lockup, we adjust our expected length to * match the actual as soon as a mismatch is detected, so future * transfers will have the proper lengths from the outset. NOTE that * the data returned may not be parsed properly (since the parsing is * necessarily based on the report descriptor) but given that HID * reports are in little endian byte order and we cleared the buffer * above, chances are good that we will actually extract the right * value in spite of the UPS's brokenness. */ if (info->report_len != len) { Dmsg(100, "Report length mismatch, fixing " "(id=%d, ci=%d, expected=%d, actual=%d)\n", info->item.report_ID, ci, info->report_len, len); info->report_len = len; } /* Populate a uval struct using the raw report data */ return populate_uval(info, data, uval); } /* * Read UPS events. I.e. state changes. */ bool BsdUsbUpsDriver::check_state() { int i, ci; int retval, value; unsigned char buf[100]; struct timespec now, exit; struct timeval tv; fd_set rfds; USB_VALUE uval; bool done = false; /* Figure out when we need to exit by */ clock_gettime(CLOCK_REALTIME, &exit); exit.tv_sec += _ups->wait_time; while (!done) { /* Figure out how long until we have to exit */ clock_gettime(CLOCK_REALTIME, &now); if (now.tv_sec > exit.tv_sec || (now.tv_sec == exit.tv_sec && now.tv_nsec / 1000 >= exit.tv_nsec / 1000)) { /* Done already? How time flies... */ return 0; } tv.tv_sec = exit.tv_sec - now.tv_sec; tv.tv_usec = (exit.tv_nsec - now.tv_nsec) / 1000; if (tv.tv_usec < 0) { tv.tv_sec--; /* Normalize */ tv.tv_usec += 1000000; } FD_ZERO(&rfds); FD_SET(_intfd, &rfds); retval = select((_intfd) + 1, &rfds, NULL, NULL, &tv); switch (retval) { case 0: /* No chars available in TIMER seconds. */ return 0; case -1: if (errno == EINTR || errno == EAGAIN) /* assume SIGCHLD */ continue; Dmsg(200, "select error: ERR=%s\n", strerror(errno)); usb_link_check(); /* link is down, wait */ return 0; default: break; } do { retval = read(_intfd, buf, sizeof(buf)); } while (retval == -1 && (errno == EAGAIN || errno == EINTR)); if (retval < 0) { /* error */ Dmsg(200, "read error: ERR=%s\n", strerror(errno)); usb_link_check(); /* notify that link is down, wait */ return 0; } if (debug_level >= 300) { logf("Interrupt data: "); for (i = 0; i < retval; i++) logf("%02x, ", buf[i]); logf("\n"); } write_lock(_ups); /* * Iterate over all CIs, firing off events for any that are * affected by this report. */ for (ci=0; ciUPS_Cap[ci] && _info[ci] && _info[ci]->item.report_ID == buf[0]) { /* * Check if we received fewer bytes of data from the UPS than we * should have. If so, ignore the report since we can't process it * reliably. If we go ahead and try to process it we may get * sporradic bad readings. UPSes we've seen this issue on so far * include: * * "Back-UPS CS 650 FW:817.v7 .I USB FW:v7" * "Back-UPS CS 500 FW:808.q8.I USB FW:q8" */ if (_info[ci]->report_len != retval) { Dmsg(100, "Report length mismatch, ignoring " "(id=%d, ci=%d, expected=%d, actual=%d)\n", _info[ci]->item.report_ID, ci, _info[ci]->report_len, retval); break; /* don't continue since other CIs will be just as wrong */ } /* Ignore this event if the value has not changed */ value = hid_get_data(buf+1, &_info[ci]->item); if (_info[ci]->value == value) { Dmsg(200, "Ignoring unchanged value (ci=%d, rpt=%d, val=%d)\n", ci, buf[0], value); continue; } Dmsg(200, "Processing changed value (ci=%d, rpt=%d, val=%d)\n", ci, buf[0], value); /* Populate a uval and report it to the upper layer */ populate_uval(_info[ci], buf, &uval); if (usb_report_event(ci, &uval)) { /* * The upper layer considers this an important event, * so we will return after processing any remaining * CIs for this report. */ done = true; } } } write_unlock(_ups); } return true; } /* * Open usb port * * This is called once by the core code and is the first * routine called. */ bool BsdUsbUpsDriver::Open() { write_lock(_ups); if (_orig_device[0] == 0) strlcpy(_orig_device, _ups->device, sizeof(_orig_device)); bool rc = open_usb_device(); _ups->clear_slave(); write_unlock(_ups); return rc; } /* * This is the last routine called from apcupsd core code */ bool BsdUsbUpsDriver::Close() { /* Should we be politely closing fds here or anything? */ return 1; } int BsdUsbUpsDriver::read_int_from_ups(int ci, int *value) { USB_VALUE val; if (!pusb_get_value(ci, &val)) return false; *value = val.iValue; return true; } int BsdUsbUpsDriver::write_int_to_ups(int ci, int value, const char *name) { USB_INFO *info; int old_value, new_value; unsigned char rpt[20]; if (_ups->UPS_Cap[ci] && _info[ci] && _info[ci]->witem.report_ID) { info = _info[ci]; /* point to our info structure */ if (hidu_get_report(_fd, &info->item, rpt, info->report_len) < 1) { Dmsg(000, "get_report for kill power function %s failed.\n", name); return false; } old_value = hid_get_data(rpt + 1, &info->item); hid_set_data(rpt + 1, &info->witem, value); if (!hidu_set_report(_fd, &info->witem, rpt, info->report_len)) { Dmsg(000, "set_report for kill power function %s failed.\n", name); return false; } if (hidu_get_report(_fd, &info->item, rpt, info->report_len) < 1) { Dmsg(000, "get_report for kill power function %s failed.\n", name); return false; } new_value = hid_get_data(rpt + 1, &info->item); Dmsg(100, "function %s ci=%d value=%d OK.\n", name, ci, value); Dmsg(100, "%s before=%d set=%d after=%d\n", name, old_value, value, new_value); return true; } Dmsg(000, "function %s ci=%d not available in this UPS.\n", name, ci); return false; } apcupsd-3.14.14/src/drivers/usb/bsd/bsd-usb.h000066400000000000000000000054761274230402600206550ustar00rootroot00000000000000/* * bsd-usb.h * * Platform-specific USB module for *BSD ugen USB driver. * * Based on linux-usb.c by Kerb Sibbald. */ /* * Copyright (C) 2004-2012 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _BSDUSB_H #define _BSDUSB_H #include "../usb.h" class BsdUsbUpsDriver: public UsbUpsDriver { public: BsdUsbUpsDriver(UPSINFO *ups); virtual ~BsdUsbUpsDriver() {} // Inherited from UpsDriver virtual bool Open(); virtual bool Close(); virtual bool check_state(); // Inherited from UsbUpsDriver virtual int write_int_to_ups(int ci, int value, char const* name); virtual int read_int_from_ups(int ci, int *value); protected: // Inherited from UsbUpsDriver virtual bool pusb_ups_get_capabilities(); virtual bool pusb_get_value(int ci, USB_VALUE *uval); private: /* * When we are traversing the USB reports given by the UPS and we find * an entry corresponding to an entry in the known_info table above, * we make the following USB_INFO entry in the info table of our * private data. */ typedef struct s_usb_info { unsigned usage_code; /* usage code wanted */ unsigned unit_exponent; /* exponent */ unsigned unit; /* units */ int data_type; /* data type */ hid_item_t item; /* HID item (read) */ hid_item_t witem; /* HID item (write) */ int report_len; /* Length of containing report */ int ci; /* which CI does this usage represent? */ int value; /* Previous value of this item */ } USB_INFO; void reinitialize_private_structure(); bool init_device(const char *devname); bool open_usb_device(); bool usb_link_check(); bool populate_uval(USB_INFO *info, unsigned char *data, USB_VALUE *uval); int _fd; /* Our UPS control pipe fd when open */ int _intfd; /* Interrupt pipe fd */ char _orig_device[MAXSTRING]; /* Original port specification */ report_desc_t _rdesc; /* Device's report descrptor */ USB_INFO *_info[CI_MAXCI + 1]; /* Info pointers for each command */ bool _linkcheck; }; #endif apcupsd-3.14.14/src/drivers/usb/bsd/hidutils.c000066400000000000000000000270401274230402600211250ustar00rootroot00000000000000/* * hidutils.c * * Utility functions for interfacing with the libusbhid userspace * HID parsing library. */ /* * Copyright (C) 2004-2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "hidutils.h" #include #include #define MAX_SANE_DESCRIPTOR_LEN 4096 /* * Fetch the report descriptor from the device given an fd for the * device's control endpoint. Descriptor length is written to the * rlen out paramter and a pointer to a malloc'ed buffer containing * the descriptor is returned. Returns NULL on failure. */ unsigned char *hidu_fetch_report_descriptor(int fd, int *rlen) { int rc, i, rdesclen; struct usb_config_desc cdesc; struct usb_full_desc fdesc; struct usb_ctl_request req; int len; unsigned char *ptr; /* * In order to fetch the report descriptor we need to first * determine that descriptor's length. Unlike the other std * descriptors, report descriptors are not prefixed with their * length. We must instead look in the HID descriptor. This is * made especially painful because for some reason we cannot * request the HID descriptor directly. The length bytes come * back munged when we do that (bad, FreeBSD, bad!). So instead * we ask for the set of all top level descriptors and dig the * HID descriptor out of there. Then we can *finally* go about * asking for the report descriptor itself. */ /* * First, get the CONFIG descriptor alone so we can look up * the length of the full descriptor set. */ cdesc.ucd_config_index = USB_CURRENT_CONFIG_INDEX; rc = ioctl(fd, USB_GET_CONFIG_DESC, &cdesc); if (rc) { Dmsg(100, "Unable to get USB CONFIG descriptor.\n"); return NULL; } len = UGETW(cdesc.ucd_desc.wTotalLength); if (!len || len > MAX_SANE_DESCRIPTOR_LEN) { Dmsg(100, "Unreasonable length %d.\n", len); return NULL; } /* * Now get the full set of descriptors (does not include * report descriptor). */ fdesc.ufd_size = len; fdesc.ufd_data = (u_char*)malloc(len); fdesc.ufd_config_index = USB_CURRENT_CONFIG_INDEX; rc = ioctl(fd, USB_GET_FULL_DESC, &fdesc); if (rc) { Dmsg(100, "Unable to get full descriptors.\n"); free(fdesc.ufd_data); return NULL; } Dmsg(300, "Full descriptors:\n"); hex_dump(300, fdesc.ufd_data, len); /* Search for the HID descriptor */ for (ptr = fdesc.ufd_data, i = 0; i < len; i += ptr[0], ptr += ptr[0]) if (ptr[1] == UDESC_HID) break; if (i >= len) { Dmsg(100, "Unable to locate HID descriptor.\n"); free(fdesc.ufd_data); return NULL; } /* We expect the first additional descriptor type to be report */ if (ptr[6] != UDESC_REPORT) { Dmsg(100, "First extra descriptor not report.\n"); free(fdesc.ufd_data); return NULL; } /* Finally! The report descriptor's length! */ rdesclen = ptr[8] << 8 | ptr[7]; Dmsg(200, "Report desc len=0x%04x (%d)\n", rdesclen, rdesclen); /* That's all we needed from the buffer */ free(fdesc.ufd_data); if (!rdesclen || rdesclen > MAX_SANE_DESCRIPTOR_LEN) { Dmsg(100, "Unreasonable rdesclen %d.\n", rdesclen); return NULL; } /* * Now fetch the report descriptor itself. We use a raw USB request * for this because the report descriptor is a class specific item. */ req.ucr_flags = 0; req.ucr_actlen = 0; req.ucr_addr = 0; req.ucr_data = malloc(rdesclen); req.ucr_request.bmRequestType = UT_READ_INTERFACE; req.ucr_request.bRequest = UR_GET_DESCRIPTOR; USETW(req.ucr_request.wValue, UDESC_REPORT << 8); USETW(req.ucr_request.wIndex, 0); USETW(req.ucr_request.wLength, rdesclen); rc = ioctl(fd, USB_DO_REQUEST, &req); if (rc) { Dmsg(100, "Unable to read report descriptor.\n"); free(req.ucr_data); return NULL; } Dmsg(300, "Report descriptor:\n"); hex_dump(300, req.ucr_data, rdesclen); *rlen = rdesclen; return (unsigned char *)req.ucr_data; } /* Push a value onto the collection stack */ #define PUSH_COLLECTION(c, v) \ do \ { \ if (c##_idx= 0) \ c##_idx--; \ } while(0) /* Get the topmost item on the stack */ #define TOP_COLLECTION(c) \ ((c##_idx == -1) ? -1 : c##_stack[c##_idx]) /* Collection types */ #define HIDCOL_PHYSICAL 0 #define HIDCOL_APPLICATION 1 #define HIDCOL_LOGICAL 2 #define MAX_COLLECTION_NESTING 10 /* For pretty printing... */ #define KIND_TO_CHAR(x) \ ((x) == hid_input) ? 'I' : \ ((x) == hid_output) ? 'O' : \ ((x) == hid_feature) ? 'F' : \ ((x) == hid_collection) ? 'C' : \ ((x) == hid_endcollection) ? 'E' : '?' #define COLLECTION_TO_CHAR(x) \ ((x) == 0) ? 'P' : /* Physical */ \ ((x) == 1) ? 'A' : /* Application */ \ ((x) == 2) ? 'L' : /* Logical */ \ ((x) == 3) ? 'R' : /* Report */ \ ((x) == 4) ? 'N' : /* Named Array */ \ ((x) == 5) ? 'S' : /* Usage Switch */ \ ((x) == 6) ? 'M' : '?' /* Usage Modifier */ \ /* * Locate an item matching the given parameters. If found, the * item is copied to the supplied buffer. Returns true on success, * false on failure. Any of usage, app, phys, logical, and kind * may be set to -1 for "don't care". */ int hidu_locate_item(report_desc_t rdesc, int usage, int app, int phys, int logical, int kind, hid_item_t *outitem) { int rc; hid_data_t cookie; hid_item_t item; int phys_stack[MAX_COLLECTION_NESTING]; int app_stack[MAX_COLLECTION_NESTING]; int logical_stack[MAX_COLLECTION_NESTING]; int phys_idx = -1, app_idx = -1, logical_idx = -1; cookie = hid_start_parse(rdesc, HID_KIND_ALL, -1); if (!cookie) { Dmsg(100, "Unable to start hid parser\n"); return 0; } while ((rc = hid_get_item(cookie, &item)) > 0) { if (item.kind == hid_collection) { if (item.collection == HIDCOL_PHYSICAL) PUSH_COLLECTION(phys, item.usage); else if (item.collection == HIDCOL_LOGICAL) PUSH_COLLECTION(logical, item.usage); else if (item.collection == HIDCOL_APPLICATION) PUSH_COLLECTION(app, item.usage); } if (usage != -1 && (unsigned int)usage != item.usage) goto next; if (app != -1 && app != TOP_COLLECTION(app)) goto next; if (phys != -1 && phys != TOP_COLLECTION(phys)) goto next; if (logical != -1 && logical != TOP_COLLECTION(logical)) goto next; if (kind != -1 && ((1 << item.kind) & kind) == 0) goto next; if (outitem) memcpy(outitem, &item, sizeof(item)); hid_end_parse(cookie); return 1; next: if (item.kind == hid_endcollection) { if (item.collection == HIDCOL_PHYSICAL) POP_COLLECTION(phys); else if (item.collection == HIDCOL_LOGICAL) POP_COLLECTION(logical); else if (item.collection == HIDCOL_APPLICATION) POP_COLLECTION(app); } } hid_end_parse(cookie); return 0; } /* * Fetch a report from a device given an fd for the device's control * endpoint, the populated item structure describing the report, a * data buffer in which to store the result, and the report length. * Returns actual report length (in bytes) on success and -1 on failure. */ int hidu_get_report(int fd, hid_item_t *item, unsigned char *data, int len) { int rc; struct usb_ctl_request req; Dmsg(200, "get_report: id=0x%02x, kind=%d, length=%d pos=%d\n", item->report_ID, item->kind, len, item->pos); req.ucr_flags = USBD_SHORT_XFER_OK; req.ucr_actlen = 0; req.ucr_addr = 0; req.ucr_data = data; req.ucr_request.bmRequestType = UT_READ_CLASS_INTERFACE; req.ucr_request.bRequest = UR_GET_REPORT; USETW(req.ucr_request.wValue, ((item->kind + 1) << 8) | item->report_ID); USETW(req.ucr_request.wIndex, 0); USETW(req.ucr_request.wLength, len); Dmsg(200, "get_report: wValue=0x%04x, wLength=%d\n", UGETW(req.ucr_request.wValue), UGETW(req.ucr_request.wLength)); rc = ioctl(fd, USB_DO_REQUEST, &req); if (rc) { Dmsg(100, "Error getting report: %s\n", strerror(errno)); return -1; } hex_dump(300, data, req.ucr_actlen); return req.ucr_actlen; } /* * Send a report to the device given an fd for the device's control * endpoint, the populated item structure, the data to send, and the * report length. Returns true on success, false on failure. */ int hidu_set_report(int fd, hid_item_t *item, unsigned char *data, int len) { int rc; struct usb_ctl_request req; Dmsg(200, "set_report: id=0x%02x, kind=%d, length=%d pos=%d\n", item->report_ID, item->kind, len, item->pos); hex_dump(300, data, len); req.ucr_flags = 0; req.ucr_actlen = 0; req.ucr_addr = 0; req.ucr_data = data; req.ucr_request.bmRequestType = UT_WRITE_CLASS_INTERFACE; req.ucr_request.bRequest = UR_SET_REPORT; USETW(req.ucr_request.wValue, ((item->kind + 1) << 8) | item->report_ID); USETW(req.ucr_request.wIndex, 0); USETW(req.ucr_request.wLength, len); Dmsg(200, "set_report: wValue=0x%04x, wLength=%d\n", UGETW(req.ucr_request.wValue), UGETW(req.ucr_request.wLength)); rc = ioctl(fd, USB_DO_REQUEST, &req); if (rc) { Dmsg(100, "Error setting report: (%d) %s\n", errno, strerror(errno)); return 0; } return 1; } /* * Fetch a string descriptor from the device given an fd for the * device's control endpoint and the string index. Returns a pointer * to a static buffer containing the NUL-terminated string or NULL * on failure. */ const char *hidu_get_string(int fd, int index) { int rc, i; struct usb_string_desc sd; static char string[128]; sd.usd_string_index = index; sd.usd_language_id = 0; rc = ioctl(fd, USB_GET_STRING_DESC, &sd); if (rc) { Dmsg(100, "Error fetching string descriptor: %s\n", strerror(errno)); return NULL; } Dmsg(200, "Got string of length=%d\n", sd.usd_desc.bLength); /* * Convert from wide chars to bytes...just assume it's ASCII. * Length is in bytes although structure is arranged as words * and there always seems to be a byte of garbage on the end. * (Not sure if the garbage is an APC bug, a kernel bug, or a * bug in my understanding.) */ for (i = 0; i < sd.usd_desc.bLength / 2 - 1 && i < (int)sizeof(string) - 1; i++) string[i] = UGETW(sd.usd_desc.bString[i]); string[i] = '\0'; return string; } apcupsd-3.14.14/src/drivers/usb/bsd/hidutils.h000066400000000000000000000060511274230402600211310ustar00rootroot00000000000000/* * hidutils.h * * Utility functions for interfacing with the libusbhid userspace * HID parsing library. */ /* * Copyright (C) 2004-2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _HIDUTILS_H #define _HIDUTILS_H #include "usbhid.h" #define HID_KIND_INPUT (1 << hid_input) #define HID_KIND_OUTPUT (1 << hid_output) #define HID_KIND_FEATURE (1 << hid_feature) #define HID_KIND_COLLECTION (1 << hid_collection) #define HID_KIND_ENDCOLLECTION (1 << hid_endcollection) #define HID_KIND_ALL (HID_KIND_INPUT | \ HID_KIND_OUTPUT | \ HID_KIND_FEATURE | \ HID_KIND_COLLECTION | \ HID_KIND_ENDCOLLECTION | \ HID_KIND_OUTPUT) /* * Fetch the report descriptor from the device given an fd for the * device's control endpoint. Descriptor length is written to the * rlen out paramter and a pointer to a malloc'ed buffer containing * the descriptor is returned. Returns NULL on failure. */ unsigned char *hidu_fetch_report_descriptor(int fd, int *rlen); /* * Locate an item matching the given parameters. If found, the * item is copied to the supplied buffer. Returns true on success, * false on failure. Any of usage, app, phys, logical, and kind * may be set to -1 for "don't care". */ int hidu_locate_item(report_desc_t rdesc, int usage, int app, int phys, int logical, int kind, hid_item_t *outitem); /* * Fetch a report from a device given an fd for the device's control * endpoint, the populated item structure describing the report, a * data buffer in which to store the result, and the report length. * Returns actual report length (in bytes) on success and -1 on failure. */ int hidu_get_report(int fd, hid_item_t *item, unsigned char *data, int len); /* * Send a report to the device given an fd for the device's control * endpoint, the populated item structure, the data to send, and the * report length. Returns true on success, false on failure. */ int hidu_set_report(int fd, hid_item_t *item, unsigned char *data, int len); /* * Fetch a string descriptor from the device given an fd for the * device's control endpoint and the string index. Returns a pointer * to a static buffer containing the NUL-terminated string or NULL * on failure. */ const char *hidu_get_string(int fd, int index); #endif apcupsd-3.14.14/src/drivers/usb/generic/000077500000000000000000000000001274230402600177755ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/usb/generic/Makefile000066400000000000000000000002221274230402600214310ustar00rootroot00000000000000topdir:=../../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) all-targets: $(OBJS) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/usb/generic/generic-usb.c000066400000000000000000000373011274230402600223500ustar00rootroot00000000000000/* * generic-usb.c * * Generic USB module for libusb. */ /* * Copyright (C) 2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "astring.h" #include "generic-usb.h" UpsDriver *UsbUpsDriver::Factory(UPSINFO *ups) { return new GenericUsbUpsDriver(ups); } GenericUsbUpsDriver::GenericUsbUpsDriver(UPSINFO *ups) : UsbUpsDriver(ups), _linkcheck(false) { memset(_info, 0, sizeof(_info)); } bool GenericUsbUpsDriver::pusb_ups_get_capabilities() { int i, input, feature, ci, phys, logi; hid_item_t input_item, feature_item, item; USB_INFO *info; write_lock(_ups); for (i = 0; _known_info[i].usage_code; i++) { ci = _known_info[i].ci; phys = _known_info[i].physical; logi = _known_info[i].logical; if (ci != CI_NONE && !_info[ci]) { /* Try to find an INPUT report containing this usage */ input = _hidups.LocateItem( _known_info[i].usage_code, /* Match usage code */ -1, /* Don't care about application */ (phys == P_ANY) ? -1 : phys, /* Match physical usage */ (logi == P_ANY) ? -1 : logi, /* Match logical usage */ HID_KIND_INPUT, /* Match feature type */ &input_item); /* Try to find a FEATURE report containing this usage */ feature = _hidups.LocateItem( _known_info[i].usage_code, /* Match usage code */ -1, /* Don't care about application */ (phys == P_ANY) ? -1 : phys, /* Match physical usage */ (logi == P_ANY) ? -1 : logi, /* Match logical usage */ HID_KIND_FEATURE, /* Match feature type */ &feature_item); /* * Choose which report to use. We prefer FEATURE since some UPSes * have broken INPUT reports, but we will fall back on INPUT if * FEATURE is not available. */ if (feature) item = feature_item; else if (input) item = input_item; else continue; // No valid report, bail _ups->UPS_Cap[ci] = true; _ups->UPS_Cmd[ci] = _known_info[i].usage_code; info = (USB_INFO *)malloc(sizeof(USB_INFO)); if (!info) { write_unlock(_ups); Error_abort("Out of memory.\n"); } // Populate READ report data _info[ci] = info; memset(info, 0, sizeof(*info)); info->ci = ci; info->usage_code = item.usage; info->unit_exponent = item.unit_exponent; info->unit = item.unit; info->data_type = _known_info[i].data_type; info->item = item; info->report_len = _hidups.GetReportSize( /* +1 for report id */ item.kind, item.report_ID) + 1; Dmsg(200, "Got READ ci=%d, rpt=%d (len=%d), usage=0x%x (len=%d), kind=0x%02x\n", ci, item.report_ID, info->report_len, _known_info[i].usage_code, item.report_size, item.kind); // If we have a FEATURE report, use that as the writable report if (feature) { info->witem = item; Dmsg(200, "Got WRITE ci=%d, rpt=%d (len=%d), usage=0x%x (len=%d), kind=0x%02x\n", ci, item.report_ID, info->report_len, _known_info[i].usage_code, item.report_size, item.kind); } } } _ups->UPS_Cap[CI_STATUS] = true; /* we always have status flag */ write_unlock(_ups); return 1; } bool GenericUsbUpsDriver::populate_uval(USB_INFO *info, unsigned char *data, USB_VALUE *uval) { const char *str; int exponent; USB_VALUE val; /* data+1 skips the report tag byte */ info->value = hid_get_data(data+1, &info->item); exponent = info->unit_exponent; if (exponent > 7) exponent = exponent - 16; if (info->data_type == T_INDEX) { /* get string */ if (info->value == 0) return false; str = _hidups.GetString(info->value); if (!str) return false; strlcpy(val.sValue, str, sizeof(val.sValue)); val.value_type = V_STRING; Dmsg(200, "Def val=%d exp=%d sVal=\"%s\" ci=%d\n", info->value, exponent, val.sValue, info->ci); } else if (info->data_type == T_UNITS) { val.value_type = V_DOUBLE; switch (info->unit) { case 0x00F0D121: val.UnitName = "Volts"; exponent -= 7; /* remove bias */ break; case 0x00100001: exponent += 2; /* remove bias */ val.UnitName = "Amps"; break; case 0xF001: val.UnitName = "Hertz"; break; case 0x1001: val.UnitName = "Seconds"; break; case 0xD121: exponent -= 7; /* remove bias */ val.UnitName = "Watts"; break; case 0x010001: val.UnitName = "Degrees K"; break; case 0x0101001: val.UnitName = "AmpSecs"; if (exponent == 0) val.dValue = info->value; else val.dValue = ((double)info->value) * pow_ten(exponent); break; default: val.UnitName = ""; val.value_type = V_INTEGER; val.iValue = info->value; break; } if (exponent == 0) val.dValue = info->value; else val.dValue = ((double)info->value) * pow_ten(exponent); // Store a (possibly truncated) copy of the floating point value in the // integer field as well. val.iValue = (int)val.dValue; Dmsg(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info->value, exponent, val.dValue, info->ci); } else { /* should be T_NONE */ val.UnitName = ""; val.value_type = V_INTEGER; val.iValue = info->value; if (exponent == 0) val.dValue = info->value; else val.dValue = ((double)info->value) * pow_ten(exponent); Dmsg(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info->value, exponent, val.dValue, info->ci); } memcpy(uval, &val, sizeof(*uval)); return true; } /* * Get a field value */ bool GenericUsbUpsDriver::pusb_get_value(int ci, USB_VALUE *uval) { USB_INFO *info = _info[ci]; unsigned char data[20]; int len; /* * Note we need to check info since CI_STATUS is always true * even when the UPS doesn't directly support that CI. */ if (!UPS_HAS_CAP(ci) || !info) return false; /* UPS does not have capability */ /* * Clear the destination buffer. In the case of a short transfer (see * below) this will increase the likelihood of extracting the correct * value in spite of the missing data. */ memset(data, 0, sizeof(data)); /* Fetch the proper report */ len = _hidups.GetReport(&info->item, data, info->report_len); if (len == -1) return false; /* * Some UPSes seem to have broken firmware that sends a different number * of bytes (usually fewer) than the report descriptor specifies. On * UHCI controllers under *BSD, this can lead to random lockups. To * reduce the likelihood of a lockup, we adjust our expected length to * match the actual as soon as a mismatch is detected, so future * transfers will have the proper lengths from the outset. NOTE that * the data returned may not be parsed properly (since the parsing is * necessarily based on the report descriptor) but given that HID * reports are in little endian byte order and we cleared the buffer * above, chances are good that we will actually extract the right * value in spite of the UPS's brokenness. */ if (info->report_len != len) { Dmsg(100, "Report length mismatch, fixing " "(id=%d, ci=%d, expected=%d, actual=%d)\n", info->item.report_ID, ci, info->report_len, len); info->report_len = len; } /* Populate a uval struct using the raw report data */ return populate_uval(info, data, uval); } void GenericUsbUpsDriver::reinitialize_private_structure() { int k; Dmsg(200, "Reinitializing private structure.\n"); /* * We are being reinitialized, so clear the Cap * array, and release previously allocated memory. */ for (k = 0; k <= CI_MAXCI; k++) { _ups->UPS_Cap[k] = false; if (_info[k] != NULL) { free(_info[k]); _info[k] = NULL; } } } /* * Called if there is an ioctl() or read() error, we close() and * re open() the port since the device was probably unplugged. */ bool GenericUsbUpsDriver::usb_link_check() { bool comm_err = true; int tlog; bool once = true; if (_linkcheck) return false; _linkcheck = true; /* prevent recursion */ _ups->set_commlost(); Dmsg(200, "link_check comm lost\n"); /* Don't warn until we try to get it at least 2 times and fail */ for (tlog = LINK_RETRY_INTERVAL * 2; comm_err; tlog -= (LINK_RETRY_INTERVAL)) { if (tlog <= 0) { tlog = 10 * 60; /* notify every 10 minutes */ log_event(_ups, event_msg[CMDCOMMFAILURE].level, event_msg[CMDCOMMFAILURE].msg); if (once) { /* execute script once */ execute_command(_ups, ups_event[CMDCOMMFAILURE]); once = false; } } /* Retry every LINK_RETRY_INTERVAL seconds */ sleep(LINK_RETRY_INTERVAL); _hidups.Close(); reinitialize_private_structure(); if (_hidups.Open(_ups->device) && get_capabilities() && read_static_data()) { comm_err = false; } else { continue; } } if (!comm_err) { generate_event(_ups, CMDCOMMOK); _ups->clear_commlost(); Dmsg(200, "link check comm OK.\n"); } _linkcheck = false; return true; } bool GenericUsbUpsDriver::check_state() { int i, ci; int retval, value; unsigned char buf[20]; struct timeval now, exit; int timeout; USB_VALUE uval; bool done = false; /* Figure out when we need to exit by */ gettimeofday(&exit, NULL); exit.tv_sec += _ups->wait_time; while (!done) { /* Figure out how long until we have to exit */ gettimeofday(&now, NULL); timeout = TV_DIFF_MS(now, exit); if (timeout <= 0) { /* Done already? How time flies... */ return 0; } Dmsg(200, "Timeout=%d\n", timeout); retval = _hidups.InterruptRead(USB_ENDPOINT_IN|1, (char*)buf, sizeof(buf), timeout); if (retval == 0 || retval == -ETIMEDOUT) { /* No events available in _ups->wait_time seconds. */ return 0; } else if (retval == -EINTR || retval == -EAGAIN) { /* assume SIGCHLD */ continue; } else if (retval < 0) { /* Hard error */ Dmsg(200, "usb_interrupt_read error: (%d) %s\n", retval, strerror(-retval)); usb_link_check(); /* link is down, wait */ return 0; } if (debug_level >= 300) { logf("Interrupt data: "); for (i = 0; i < retval; i++) logf("%02x, ", buf[i]); logf("\n"); } write_lock(_ups); /* * Iterate over all CIs, firing off events for any that are * affected by this report. */ for (ci=0; ciUPS_Cap[ci] && _info[ci] && _info[ci]->item.report_ID == buf[0]) { /* * Check if we received fewer bytes of data from the UPS than we * should have. If so, ignore the report since we can't process it * reliably. If we go ahead and try to process it we may get * sporradic bad readings. UPSes we've seen this issue on so far * include: * * "Back-UPS CS 650 FW:817.v7 .I USB FW:v7" * "Back-UPS CS 500 FW:808.q8.I USB FW:q8" */ if (_info[ci]->report_len != retval) { Dmsg(100, "Report length mismatch, ignoring " "(id=%d, ci=%d, expected=%d, actual=%d)\n", _info[ci]->item.report_ID, ci, _info[ci]->report_len, retval); break; /* don't continue since other CIs will be just as wrong */ } /* Ignore this event if the value has not changed */ value = hid_get_data(buf+1, &_info[ci]->item); if (_info[ci]->value == value) { Dmsg(200, "Ignoring unchanged value (ci=%d, rpt=%d, val=%d)\n", ci, buf[0], value); continue; } Dmsg(200, "Processing changed value (ci=%d, rpt=%d, val=%d)\n", ci, buf[0], value); /* Populate a uval and report it to the upper layer */ populate_uval(_info[ci], buf, &uval); if (usb_report_event(ci, &uval)) { /* * The upper layer considers this an important event, * so we will return after processing any remaining * CIs for this report. */ done = true; } } } write_unlock(_ups); } return true; } /* * Open usb port * * This is called once by the core code and is the first * routine called. */ bool GenericUsbUpsDriver::Open() { write_lock(_ups); bool rc = _hidups.Open(_ups->device); /* * Note, we set _ups->fd here so the "core" of apcupsd doesn't * think we are a slave, which is what happens when it is -1. * (ADK: Actually this only appears to be true for apctest as * apcupsd proper uses the UPS_slave flag.) * Internally, we use the fd in our own private space */ _ups->fd = 1; _ups->clear_slave(); write_unlock(_ups); return rc; } bool GenericUsbUpsDriver::Close() { _hidups.Close(); return 1; } int GenericUsbUpsDriver::read_int_from_ups(int ci, int *value) { USB_VALUE val; if (!pusb_get_value(ci, &val)) return false; *value = val.iValue; return true; } int GenericUsbUpsDriver::write_int_to_ups(int ci, int value, const char *name) { USB_INFO *info; int old_value, new_value; unsigned char rpt[20]; if (_ups->UPS_Cap[ci] && _info[ci] && _info[ci]->witem.report_ID) { info = _info[ci]; /* point to our info structure */ if (_hidups.GetReport(&info->item, rpt, info->report_len) < 1) { Dmsg(000, "get_report for kill power function %s failed.\n", name); return false; } old_value = hid_get_data(rpt + 1, &info->item); hid_set_data(rpt + 1, &info->witem, value); if (!_hidups.SetReport(&info->witem, rpt, info->report_len)) { Dmsg(000, "set_report for kill power function %s failed.\n", name); return false; } if (_hidups.GetReport(&info->item, rpt, info->report_len) < 1) { Dmsg(000, "get_report for kill power function %s failed.\n", name); return false; } new_value = hid_get_data(rpt + 1, &info->item); Dmsg(100, "function %s ci=%d value=%d OK.\n", name, ci, value); Dmsg(100, "%s before=%d set=%d after=%d\n", name, old_value, value, new_value); return true; } Dmsg(000, "function %s ci=%d not available in this UPS.\n", name, ci); return false; } apcupsd-3.14.14/src/drivers/usb/generic/generic-usb.h000066400000000000000000000050461274230402600223560ustar00rootroot00000000000000/* * generic-usb.c * * Generic USB module for libusb. */ /* * Copyright (C) 2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _GENERICUSB_H #define _GENERICUSB_H #include "../usb.h" #include "libusb.h" #include "HidUps.h" class GenericUsbUpsDriver: public UsbUpsDriver { public: GenericUsbUpsDriver(UPSINFO *ups); virtual ~GenericUsbUpsDriver() {} // Inherited from UpsDriver virtual bool Open(); virtual bool Close(); virtual bool check_state(); // Inherited from UsbUpsDriver virtual int write_int_to_ups(int ci, int value, char const* name); virtual int read_int_from_ups(int ci, int *value); protected: // Inherited from UsbUpsDriver virtual bool pusb_ups_get_capabilities(); virtual bool pusb_get_value(int ci, USB_VALUE *uval); private: /* * When we are traversing the USB reports given by the UPS and we * find an entry corresponding to an entry in the known_info table * above, we make the following USB_INFO entry in the info table * of our private data. */ typedef struct s_usb_info { unsigned usage_code; /* usage code wanted */ unsigned unit_exponent; /* exponent */ unsigned unit; /* units */ int data_type; /* data type */ hid_item_t item; /* HID item (for read) */ hid_item_t witem; /* HID item (for write) */ int report_len; /* Length of containing report */ int ci; /* which CI does this usage represent? */ int value; /* Previous value of this item */ } USB_INFO; void reinitialize_private_structure(); bool open_usb_device(); bool usb_link_check(); bool populate_uval(USB_INFO *info, unsigned char *data, USB_VALUE *uval); USB_INFO *_info[CI_MAXCI + 1]; /* Info pointers for each command */ bool _linkcheck; HidUps _hidups; }; #endif apcupsd-3.14.14/src/drivers/usb/linux/000077500000000000000000000000001274230402600175205ustar00rootroot00000000000000apcupsd-3.14.14/src/drivers/usb/linux/Makefile000066400000000000000000000002221274230402600211540ustar00rootroot00000000000000topdir:=../../../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) all-targets: $(OBJS) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/drivers/usb/linux/linux-usb.c000066400000000000000000000621061274230402600216170ustar00rootroot00000000000000/* * linux-usb.c * * Platform-specific interface to Linux hiddev USB HID driver. * * Parts of this code (especially the initialization and walking * the reports) were derived from a test program hid-ups.c by: * Vojtech Pavlik * Paul Stewart */ /* * Copyright (C) 2001-2004 Kern Sibbald * Copyright (C) 2004-2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ /* * The following is a work around for a problem in 2.6 kernel * linux/hiddev.h file that is fixed in 2.6.9 */ #define HID_MAX_USAGES 1024 #include "apc.h" #include "linux-usb.h" #include #include /* RHEL has an out-of-date hiddev.h */ #ifndef HIDIOCGFLAG # define HIDIOCSFLAG _IOW('H', 0x0F, int) #endif #ifndef HIDDEV_FLAG_UREF # define HIDDEV_FLAG_UREF 0x1 #endif /* Enable this to force Linux 2.4 compatability mode */ #define FORCE_COMPAT24 false UpsDriver *UsbUpsDriver::Factory(UPSINFO *ups) { return new LinuxUsbUpsDriver(ups); } LinuxUsbUpsDriver::LinuxUsbUpsDriver(UPSINFO *ups) : UsbUpsDriver(ups), _fd(-1), _compat24(false), _linkcheck(false) { memset(_orig_device, 0, sizeof(_orig_device)); memset(_info, 0, sizeof(_info)); } void LinuxUsbUpsDriver::reinitialize_private_structure() { int k; Dmsg(200, "Reinitializing private structure.\n"); /* * We are being reinitialized, so clear the Cap * array, and release previously allocated memory. */ for (k = 0; k <= CI_MAXCI; k++) { _ups->UPS_Cap[k] = false; if (_info[k] != NULL) { free(_info[k]); _info[k] = NULL; } } } /* * Internal routine to attempt device open. */ int LinuxUsbUpsDriver::open_device(const char *dev) { int flaguref = HIDDEV_FLAG_UREF; int fd, ret, i; Dmsg(200, "Attempting to open \"%s\"\n", dev); /* Open the device port */ fd = open(dev, O_RDWR | O_NOCTTY | O_CLOEXEC); if (fd >= 0) { /* Check for the UPS application HID usage */ for (i = 0; (ret = ioctl(fd, HIDIOCAPPLICATION, i)) > 0; i++) { if ((ret & 0xffff000) == (UPS_USAGE & 0xffff0000)) { /* Request full uref reporting from read() */ if (FORCE_COMPAT24 || ioctl(fd, HIDIOCSFLAG, &flaguref)) { Dmsg(100, "HIDIOCSFLAG failed; enabling linux-2.4 " "compatibility mode\n"); _compat24 = true; } /* Successfully opened the device */ Dmsg(200, "Successfully opened \"%s\"\n", dev); return fd; } } close(fd); } /* Failed to open the device */ return -1; } /* * Routine to request that kernel driver attach to any APC USB UPSes */ void LinuxUsbUpsDriver::bind_upses() { #ifdef USBDEVFS_CONNECT // Find all USB devices in usbfs glob_t g; if (glob("/proc/bus/usb/[0-9][0-9][0-9]/[0-9][0-9][0-9]", 0, NULL, &g) && glob("/dev/bus/usb/[0-9][0-9][0-9]/[0-9][0-9][0-9]", 0, NULL, &g)) { return; } // Iterate over all USB devices... for (size_t i = 0; i < g.gl_pathc; ++i) { // Open the device in usbfs int fd = open(g.gl_pathv[i], O_RDWR|O_CLOEXEC); if (fd == -1) continue; struct usb_device_descriptor { uint8_t bLength; uint8_t bDescriptorType; uint16_t bcdUSB; uint8_t bDeviceClass; uint8_t bDeviceSubClass; uint8_t bDeviceProtocol; uint8_t bMaxPacketSize0; uint16_t idVendor; uint16_t idProduct; uint16_t bcdDevice; uint8_t iManufacturer; uint8_t iProduct; uint8_t iSerialNumber; uint8_t bNumConfigurations; } __attribute__ ((packed)) dd; // Fetch device descriptor, then verify device VID/PID are supported and // no kernel driver is currently attached struct usbdevfs_getdriver getdrv = {0}; if (read(fd, &dd, sizeof(dd)) == sizeof(dd) && MatchVidPid(dd.idVendor, dd.idProduct) && ioctl(fd, USBDEVFS_GETDRIVER, &getdrv)) { // APC device with no kernel driver attached // Issue command to attach kernel driver struct usbdevfs_ioctl command = {0}; command.ioctl_code = USBDEVFS_CONNECT; int rc = ioctl(fd, USBDEVFS_IOCTL, &command); // Hard to tell if this succeeded because the return value of the // ioctl was changed. In linux 2.4.37, 0 means success but in 3.4 it // means failure. So...we're screwed. The only thing we know for sure // is <0 is definitely failure. if (rc >= 0) { Dmsg(100, "Reattached kernel driver to %s\n", g.gl_pathv[i]); } else { Dmsg(0, "Failed to attach kernel driver to %s (%d)\n", g.gl_pathv[i], rc); } } close(fd); } globfree(&g); #endif // USBDEVFS_CONNECT } /* * Internal routine to open the device and ensure that there is * a UPS application on the line. This routine may be called * many times because the device may be unplugged and plugged * back in -- the joys of USB devices. */ bool LinuxUsbUpsDriver::open_usb_device() { char devname[MAXSTRING]; const char *hiddev[] = { "/dev/usb/hiddev", "/dev/usb/hid/hiddev", "/dev/hiddev", NULL }; int i, j, k; /* * Ensure any APC UPSes are utilizing the usbhid/hiddev kernel driver. * This is necessary if they were detached from the kernel driver in order * to use libusb (the apcupsd 'generic' USB driver). */ bind_upses(); /* * Note, we set _ups->fd here so the "core" of apcupsd doesn't * think we are a slave, which is what happens when it is -1. * (ADK: Actually this only appears to be true for apctest as * apcupsd proper uses the UPS_slave flag.) * Internally, we use the fd in our own private space */ _ups->fd = 1; /* * If no device locating specified, we go autodetect it * by searching known places. */ if (_ups->device[0] == 0) goto auto_detect; /* * Also if specified device includes deprecated '[]' notation, * just use the automatic search. */ if (strchr(_ups->device, '[') && strchr(_ups->device, ']')) { _orig_device[0] = 0; goto auto_detect; } /* * If we get here we know the user specified a device or we are * trying to re-open a device that previously was open. */ /* Retry 10 times */ for (i = 0; i < 10; i++) { _fd = open_device(_ups->device); if (_fd != -1) return true; sleep(1); } /* * If user-specified device could not be opened, fail. */ if (_orig_device[0] != 0) return false; /* * If we get here we failed to re-open a previously auto-detected * device. We will fall thru and restart autodetection... */ auto_detect: for (i = 0; i < 10; i++) { /* try 10 times */ for (j = 0; hiddev[j]; j++) { /* loop over known device names */ for (k = 0; k < 16; k++) { /* loop over devices */ asnprintf(devname, sizeof(devname), "%s%d", hiddev[j], k); _fd = open_device(devname); if (_fd != -1) { /* Successful open, save device name and return */ strlcpy(_ups->device, devname, sizeof(_ups->device)); return true; } } } sleep(1); } _ups->device[0] = '\0'; return false; } /* * Called if there is an ioctl() or read() error, we close() and * re open() the port since the device was probably unplugged. */ bool LinuxUsbUpsDriver::usb_link_check() { bool comm_err = true; int tlog; bool once = true; if (_linkcheck) return false; _linkcheck = true; /* prevent recursion */ _ups->set_commlost(); Dmsg(200, "link_check comm lost\n"); /* Don't warn until we try to get it at least 2 times and fail */ for (tlog = LINK_RETRY_INTERVAL * 2; comm_err; tlog -= (LINK_RETRY_INTERVAL)) { if (tlog <= 0) { tlog = 10 * 60; /* notify every 10 minutes */ log_event(_ups, event_msg[CMDCOMMFAILURE].level, event_msg[CMDCOMMFAILURE].msg); if (once) { /* execute script once */ execute_command(_ups, ups_event[CMDCOMMFAILURE]); once = false; } } /* Retry every LINK_RETRY_INTERVAL seconds */ sleep(LINK_RETRY_INTERVAL); if (_fd >= 0) { close(_fd); _fd = -1; reinitialize_private_structure(); } if (open_usb_device() && get_capabilities() && read_static_data()) { comm_err = false; } else { continue; } } if (!comm_err) { generate_event(_ups, CMDCOMMOK); _ups->clear_commlost(); Dmsg(200, "link check comm OK.\n"); } _linkcheck = false; return true; } bool LinuxUsbUpsDriver::populate_uval(USB_INFO *info, USB_VALUE *uval) { struct hiddev_string_descriptor sdesc; USB_VALUE val; int exponent; exponent = info->unit_exponent; if (exponent > 7) exponent = exponent - 16; if (info->data_type == T_INDEX) { /* get string */ if (info->uref.value == 0) return false; sdesc.index = info->uref.value; if (ioctl(_fd, HIDIOCGSTRING, &sdesc) < 0) return false; strlcpy(val.sValue, sdesc.value, sizeof(val.sValue)); val.value_type = V_STRING; Dmsg(200, "Def val=%d exp=%d sVal=\"%s\" ci=%d\n", info->uref.value, exponent, val.sValue, info->ci); } else if (info->data_type == T_UNITS) { val.value_type = V_DOUBLE; switch (info->unit) { case 0x00F0D121: val.UnitName = "Volts"; exponent -= 7; /* remove bias */ break; case 0x00100001: exponent += 2; /* remove bias */ val.UnitName = "Amps"; break; case 0xF001: val.UnitName = "Hertz"; break; case 0x1001: val.UnitName = "Seconds"; break; case 0xD121: exponent -= 7; /* remove bias */ val.UnitName = "Watts"; break; case 0x010001: val.UnitName = "Degrees K"; break; case 0x0101001: val.UnitName = "AmpSecs"; break; default: val.UnitName = ""; val.value_type = V_INTEGER; val.iValue = info->uref.value; break; } if (exponent == 0) val.dValue = info->uref.value; else val.dValue = ((double)info->uref.value) * pow_ten(exponent); // Store a (possibly truncated) copy of the floating point value in the // integer field as well. val.iValue = (int)val.dValue; Dmsg(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info->uref.value, exponent, val.dValue, info->ci); } else { /* should be T_NONE */ val.UnitName = ""; val.value_type = V_INTEGER; val.iValue = info->uref.value; if (exponent == 0) val.dValue = info->uref.value; else val.dValue = ((double)info->uref.value) * pow_ten(exponent); Dmsg(200, "Def val=%d exp=%d dVal=%f ci=%d\n", info->uref.value, exponent, val.dValue, info->ci); } memcpy(uval, &val, sizeof(*uval)); return true; } /* * Get a field value */ bool LinuxUsbUpsDriver::pusb_get_value(int ci, USB_VALUE *uval) { struct hiddev_report_info rinfo; USB_INFO *info; if (!_ups->UPS_Cap[ci] || !_info[ci]) return false; /* UPS does not have capability */ /* Fetch the new value from the UPS */ info = _info[ci]; /* point to our info structure */ rinfo.report_type = info->uref.report_type; rinfo.report_id = info->uref.report_id; if (ioctl(_fd, HIDIOCGREPORT, &rinfo) < 0) /* update Report */ return false; if (ioctl(_fd, HIDIOCGUSAGE, &info->uref) < 0) /* update UPS value */ return false; /* Process the updated value */ return populate_uval(info, uval); } /* * Find the USB_INFO structure used for tracking a given usage. Searching * by usage_code alone is insufficient since the same usage may appear in * multiple reports or even multiple times in the same report. */ LinuxUsbUpsDriver::USB_INFO *LinuxUsbUpsDriver::find_info_by_uref( struct hiddev_usage_ref *uref) { int i; for (i=0; iUPS_Cap[i] && _info[i] && _info[i]->uref.report_id == uref->report_id && _info[i]->uref.field_index == uref->field_index && _info[i]->uref.usage_index == uref->usage_index && _info[i]->uref.usage_code == uref->usage_code) { return _info[i]; } } return NULL; } /* * Same as find_info_by_uref() but only checks the usage code. This is * not entirely reliable, but it's the best we have on linux-2.4. */ LinuxUsbUpsDriver::USB_INFO *LinuxUsbUpsDriver::find_info_by_ucode( unsigned int ucode) { int i; for (i=0; iUPS_Cap[i] && _info[i] && _info[i]->uref.usage_code == ucode) { return _info[i]; } } return NULL; } /* * Read UPS events. I.e. state changes. */ bool LinuxUsbUpsDriver::check_state() { int retval; bool done = false; struct hiddev_usage_ref uref; struct hiddev_event hev; USB_INFO* info; USB_VALUE uval; struct timeval tv; tv.tv_sec = _ups->wait_time; tv.tv_usec = 0; while (!done) { fd_set rfds; FD_ZERO(&rfds); FD_SET(_fd, &rfds); retval = select(_fd + 1, &rfds, NULL, NULL, &tv); /* * Note: We are relying on select() adjusting tv to the amount * of time NOT waited. This is a Linux-specific feature but * shouldn't be a problem since the driver is only intended for * for Linux. */ switch (retval) { case 0: /* No chars available in TIMER seconds. */ return false; case -1: if (errno == EINTR || errno == EAGAIN) /* assume SIGCHLD */ continue; Dmsg(200, "select error: ERR=%s\n", strerror(errno)); usb_link_check(); /* link is down, wait */ return false; default: break; } if (!_compat24) { /* This is >= linux-2.6, so we can read a uref directly */ do { retval = read(_fd, &uref, sizeof(uref)); } while (retval == -1 && (errno == EAGAIN || errno == EINTR)); if (retval < 0) { /* error */ Dmsg(200, "read error: ERR=%s\n", strerror(errno)); usb_link_check(); /* notify that link is down, wait */ return false; } if (retval == 0 || retval < (int)sizeof(uref)) return false; /* Ignore events we don't recognize */ if ((info = find_info_by_uref(&uref)) == NULL) { Dmsg(200, "Unrecognized usage (rpt=%d, usg=0x%08x, val=%d)\n", uref.report_id, uref.usage_code, uref.value); continue; } } else { /* * We're in linux-2.4 compatibility mode, so we read a * hiddev_event and use it to construct a uref. */ do { retval = read(_fd, &hev, sizeof(hev)); } while (retval == -1 && (errno == EAGAIN || errno == EINTR)); if (retval < 0) { /* error */ Dmsg(200, "read error: ERR=%s\n", strerror(errno)); usb_link_check(); /* notify that link is down, wait */ return false; } if (retval == 0 || retval < (int)sizeof(hev)) return false; /* Ignore events we don't recognize */ if ((info = find_info_by_ucode(hev.hid)) == NULL) { Dmsg(200, "Unrecognized usage (usg=0x%08x, val=%d)\n", hev.hid, hev.value); continue; } /* * ADK FIXME: The info-> struct we have now is not guaranteed to * actually be the right one, because linux-2.4 does not give us * enough data in the event to make a positive match. We may need * to filter out ambiguous usages here or manually fetch each CI * that matches the given usage. */ /* Copy the stored uref, replacing its value */ uref = info->uref; uref.value = hev.value; } write_lock(_ups); /* Ignore events whose value is unchanged */ if (info->uref.value == uref.value) { Dmsg(200, "Ignoring unchanged value (rpt=%d, usg=0x%08x, val=%d)\n", uref.report_id, uref.usage_code, uref.value); write_unlock(_ups); continue; } /* Update tracked value */ Dmsg(200, "Processing changed value (rpt=%d, usg=0x%08x, val=%d)\n", uref.report_id, uref.usage_code, uref.value); info->uref.value = uref.value; /* Populate a uval and report it to the upper layer */ populate_uval(info, &uval); if (usb_report_event(info->ci, &uval)) { /* * The upper layer considers this an important event, * so we will return immediately. */ done = true; } write_unlock(_ups); } return true; } /* * Open usb port * This is called once by the core code and is the first routine * called. */ bool LinuxUsbUpsDriver::Open() { write_lock(_ups); if (_orig_device[0] == 0) strlcpy(_orig_device, _ups->device, sizeof(_orig_device)); bool rc = open_usb_device(); _ups->clear_slave(); write_unlock(_ups); return rc; } /* * This is the last routine called from apcupsd core code */ bool LinuxUsbUpsDriver::Close() { return 1; } /* * Setup capabilities structure for UPS */ bool LinuxUsbUpsDriver::pusb_ups_get_capabilities() { int rtype[2] = { HID_REPORT_TYPE_FEATURE, HID_REPORT_TYPE_INPUT }; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; struct hiddev_usage_ref uref; unsigned int i, j, k, n; if (ioctl(_fd, HIDIOCINITREPORT, 0) < 0) Error_abort("Cannot init USB HID report. ERR=%s\n", strerror(errno)); write_lock(_ups); /* * Walk through all available reports and determine * what information we can use. */ for (n = 0; n < sizeof(rtype)/sizeof(*rtype); n++) { rinfo.report_type = rtype[n]; rinfo.report_id = HID_REPORT_ID_FIRST; while (ioctl(_fd, HIDIOCGREPORTINFO, &rinfo) >= 0) { for (i = 0; i < rinfo.num_fields; i++) { memset(&finfo, 0, sizeof(finfo)); finfo.report_type = rinfo.report_type; finfo.report_id = rinfo.report_id; finfo.field_index = i; if (ioctl(_fd, HIDIOCGFIELDINFO, &finfo) < 0) continue; memset(&uref, 0, sizeof(uref)); for (j = 0; j < finfo.maxusage; j++) { uref.report_type = finfo.report_type; uref.report_id = finfo.report_id; uref.field_index = i; uref.usage_index = j; if (ioctl(_fd, HIDIOCGUCODE, &uref) < 0) continue; if (ioctl(_fd, HIDIOCGUSAGE, &uref) < 0) continue; /* * We've got a UPS usage entry, now walk down our * know_info table and see if we have a match. If so, * allocate a new entry for it. */ for (k = 0; _known_info[k].usage_code; k++) { USB_INFO *info; int ci = _known_info[k].ci; if (ci != CI_NONE && uref.usage_code == _known_info[k].usage_code && (_known_info[k].physical == P_ANY || _known_info[k].physical == finfo.physical) && (_known_info[k].logical == P_ANY || _known_info[k].logical == finfo.logical)) { // If we do not have any data saved for this report yet, // allocate an USB_INFO and populate the read uref. info = _info[ci]; if (!info) { _ups->UPS_Cap[ci] = true; info = (USB_INFO *)malloc(sizeof(USB_INFO)); if (!info) { write_unlock(_ups); Error_abort("Out of memory.\n"); } _info[ci] = info; memset(info, 0, sizeof(*info)); info->ci = ci; info->physical = finfo.physical; info->unit_exponent = finfo.unit_exponent; info->unit = finfo.unit; info->data_type = _known_info[k].data_type; memcpy(&info->uref, &uref, sizeof(uref)); Dmsg(200, "Got READ ci=%d, usage=0x%x, rpt=%d\n", ci, _known_info[k].usage_code, uref.report_id); } // If this is a FEATURE report and we haven't set the // write uref yet, place it in the write uref (possibly in // addition to placing it in the read uref above). if (rinfo.report_type == HID_REPORT_TYPE_FEATURE && info->wuref.report_id == 0) { memcpy(&info->wuref, &uref, sizeof(uref)); Dmsg(200, "Got WRITE ci=%d, usage=0x%x, rpt=%d\n", ci, _known_info[k].usage_code, uref.report_id); } break; } } } } rinfo.report_id |= HID_REPORT_ID_NEXT; } } _ups->UPS_Cap[CI_STATUS] = true; /* we have status flag */ write_unlock(_ups); return 1; } int LinuxUsbUpsDriver::read_int_from_ups(int ci, int *value) { USB_VALUE val; if (!pusb_get_value(ci, &val)) return false; *value = val.iValue; return true; } int LinuxUsbUpsDriver::write_int_to_ups(int ci, int value, const char *name) { struct hiddev_report_info rinfo; USB_INFO *info; int old_value, new_value; // Make sure we have a writable uref for this CI if (_ups->UPS_Cap[ci] && _info[ci] && _info[ci]->wuref.report_id) { info = _info[ci]; /* point to our info structure */ rinfo.report_type = info->uref.report_type; rinfo.report_id = info->uref.report_id; /* Get report */ if (ioctl(_fd, HIDIOCGREPORT, &rinfo) < 0) { Dmsg(000, "HIDIOCGREPORT for function %s failed. ERR=%s\n", name, strerror(errno)); return false; } /* Get UPS value */ if (ioctl(_fd, HIDIOCGUSAGE, &info->wuref) < 0) { Dmsg(000, "HIDIOCGUSAGE for function %s failed. ERR=%s\n", name, strerror(errno)); return false; } old_value = info->uref.value; info->wuref.value = value; rinfo.report_type = info->wuref.report_type; rinfo.report_id = info->wuref.report_id; Dmsg(100, "SUSAGE type=%d id=%d index=%d\n", info->wuref.report_type, info->wuref.report_id, info->wuref.field_index); /* Update UPS value */ if (ioctl(_fd, HIDIOCSUSAGE, &info->wuref) < 0) { Dmsg(000, "HIDIOCSUSAGE for function %s failed. ERR=%s\n", name, strerror(errno)); return false; } /* Update Report */ if (ioctl(_fd, HIDIOCSREPORT, &rinfo) < 0) { Dmsg(000, "HIDIOCSREPORT for function %s failed. ERR=%s\n", name, strerror(errno)); return false; } /* * This readback of the report is NOT just for debugging. It * has the effect of flushing the above SET_REPORT to the * device, which is important since we need to make sure it * happens before subsequent reports are sent. */ rinfo.report_type = info->uref.report_type; rinfo.report_id = info->uref.report_id; /* Get report */ if (ioctl(_fd, HIDIOCGREPORT, &rinfo) < 0) { Dmsg(000, "HIDIOCGREPORT for function %s failed. ERR=%s\n", name, strerror(errno)); return false; } /* Get UPS value */ if (ioctl(_fd, HIDIOCGUSAGE, &info->uref) < 0) { Dmsg(000, "HIDIOCGUSAGE for function %s failed. ERR=%s\n", name, strerror(errno)); return false; } new_value = info->uref.value; Dmsg(100, "function %s ci=%d value=%d OK.\n", name, ci, value); Dmsg(100, "%s before=%d set=%d after=%d\n", name, old_value, value, new_value); return true; } Dmsg(000, "function %s ci=%d not available in this UPS.\n", name, ci); return false; } apcupsd-3.14.14/src/drivers/usb/linux/linux-usb.h000066400000000000000000000060201274230402600216150ustar00rootroot00000000000000/* * linux-usb.h * * Platform-specific interface to Linux hiddev USB HID driver. * * Parts of this code (especially the initialization and walking * the reports) were derived from a test program hid-ups.c by: * Vojtech Pavlik * Paul Stewart */ /* * Copyright (C) 2001-2004 Kern Sibbald * Copyright (C) 2004-2012 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _LINUXUSB_H #define _LINUXUSB_H #include "../usb.h" #include #include class LinuxUsbUpsDriver: public UsbUpsDriver { public: LinuxUsbUpsDriver(UPSINFO *ups); virtual ~LinuxUsbUpsDriver() {} // Inherited from UpsDriver virtual bool Open(); virtual bool Close(); virtual bool check_state(); // Inherited from UsbUpsDriver virtual int write_int_to_ups(int ci, int value, char const* name); virtual int read_int_from_ups(int ci, int *value); protected: // Inherited from UsbUpsDriver virtual bool pusb_ups_get_capabilities(); virtual bool pusb_get_value(int ci, USB_VALUE *uval); private: /* * When we are traversing the USB reports given by the UPS and we * find an entry corresponding to an entry in the known_info table * above, we make the following USB_INFO entry in the info table * of our private data. */ typedef struct s_usb_info { unsigned physical; /* physical value wanted */ unsigned unit_exponent; /* exponent */ unsigned unit; /* units */ int data_type; /* data type */ int ci; /* which CI does this usage represent? */ struct hiddev_usage_ref uref; /* usage reference (read) */ struct hiddev_usage_ref wuref; /* usage reference (write) */ } USB_INFO; void reinitialize_private_structure(); int open_device(const char *dev); void bind_upses(); bool open_usb_device(); bool usb_link_check(); bool populate_uval(USB_INFO *info, USB_VALUE *uval); USB_INFO *find_info_by_uref(struct hiddev_usage_ref *uref); USB_INFO *find_info_by_ucode(unsigned int ucode); int _fd; /* Our UPS fd when open */ bool _compat24; /* Linux 2.4 compatibility mode */ char _orig_device[MAXSTRING]; /* Original port specification */ USB_INFO *_info[CI_MAXCI + 1]; /* Info pointers for each command */ bool _linkcheck; }; #endif apcupsd-3.14.14/src/drivers/usb/usb.c000066400000000000000000001276631274230402600173350ustar00rootroot00000000000000/* * usb.c * * Public driver interface for all platform USB drivers. * * Based on linux-usb.c by Kern Sibbald */ /* * Copyright (C) 2001-2004 Kern Sibbald * Copyright (C) 2004-2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "usb.h" #include "usb_common.h" #include /* * A certain semi-ancient BackUPS Pro model breaks the USB spec in a * particularly creative way: Some reports read back in ASCII instead of * binary. And one value that should be in seconds is returned in minutes * instead, just for fun. We detect and work around the breakage. */ #define QUIRK_OLD_BACKUPS_PRO_MODEL_STRING "BackUPS Pro 500 FW:16.3.D USB FW:4" UsbUpsDriver::UsbUpsDriver(UPSINFO *ups) : UpsDriver(ups), _quirk_old_backups_pro(false), _prev_time((struct timeval){0}), _bpcnt(0) { } /* * This table is used when walking through the USB reports to see * what information found in the UPS that we want. If the usage_code * and the physical code match, then we make an entry in the command * index table containing the usage information provided by the UPS * as well as the data type from this table. Entries in the table * with ci == CI_NONE are not used, for the moment, they are * retained just so they are not forgotten. */ const UsbUpsDriver::s_known_info UsbUpsDriver::_known_info[] = { /* Page 0x84 is the Power Device Page */ /* CI USAGE PHYSICAL LOGICAL TYPE VOLATILE? */ {CI_NONE, 0x00840001, P_ANY, P_ANY, T_INDEX, false}, /* iName */ {CI_VLINE, 0x00840030, P_INPUT, P_ANY, T_UNITS, true }, /* Line Voltage */ {CI_VOUT, 0x00840030, P_OUTPUT, P_ANY, T_UNITS, true }, /* Output Voltage */ {CI_VBATT, 0x00840030, P_BATTERY, P_ANY, T_UNITS, true }, /* Battery Voltage */ {CI_VBATT, 0x00840030, P_ANY, P_PWSUM, T_UNITS, true }, /* Battery Voltage (alternative) */ {CI_NONE, 0x00840031, P_ANY, P_ANY, T_UNITS, false}, /* Current */ {CI_FREQ, 0x00840032, P_OUTPUT, P_ANY, T_UNITS, true }, /* Frequency */ {CI_NONE, 0x00840033, P_ANY, P_ANY, T_UNITS, false}, /* ApparentPower */ {CI_NONE, 0x00840034, P_ANY, P_ANY, T_UNITS, false}, /* ActivePower */ {CI_LOAD, 0x00840035, P_ANY, P_ANY, T_UNITS, true }, /* PercentLoad */ {CI_ITEMP, 0x00840036, P_BATTERY, P_ANY, T_UNITS, true }, /* Internal Temperature */ {CI_ATEMP, 0x00840036, P_APC1, P_ANY, T_UNITS, true }, /* Ambient Temperature */ {CI_HUMID, 0x00840037, P_ANY, P_ANY, T_UNITS, true }, /* Humidity */ {CI_NOMBATTV, 0x00840040, P_BATTERY, P_ANY, T_UNITS, false}, /* ConfigVoltage (battery) */ {CI_NOMBATTV, 0x00840040, P_ANY, P_PWSUM, T_UNITS, false}, /* ConfigVoltage (battery, alternate) */ {CI_NOMOUTV, 0x00840040, P_OUTPUT, P_ANY, T_UNITS, false}, /* ConfigVoltage (output) */ {CI_NOMINV, 0x00840040, P_INPUT, P_ANY, T_UNITS, false}, /* ConfigVoltage (input) */ {CI_NONE, 0x00840042, P_ANY, P_ANY, T_UNITS, false}, /* ConfigFrequency */ {CI_NONE, 0x00840043, P_ANY, P_ANY, T_UNITS, false}, /* ConfigApparentPower */ {CI_NOMPOWER, 0x00840044, P_ANY, P_ANY, T_UNITS, false}, /* ConfigActivePower */ {CI_LTRANS, 0x00840053, P_ANY, P_ANY, T_UNITS, false}, /* LowVoltageTransfer */ {CI_HTRANS, 0x00840054, P_ANY, P_ANY, T_UNITS, false}, /* HighVoltageTransfer */ {CI_DelayBeforeReboot, 0x00840055, P_ANY, P_ANY, T_UNITS, false}, /* DelayBeforeReboot */ {CI_DWAKE, 0x00840056, P_ANY, P_ANY, T_UNITS, false}, /* DelayBeforeStartup */ {CI_DelayBeforeShutdown, 0x00840057, P_ANY, P_ANY, T_UNITS, false}, /* DelayBeforeShutdown */ {CI_ST_STAT, 0x00840058, P_ANY, P_ANY, T_NONE, false}, /* Test */ {CI_DALARM, 0x0084005a, P_ANY, P_ANY, T_NONE, true }, /* AudibleAlarmControl */ {CI_NONE, 0x00840061, P_ANY, P_ANY, T_NONE, false}, /* Good */ {CI_IFailure, 0x00840062, P_ANY, P_ANY, T_NONE, false}, /* InternalFailure */ {CI_PWVoltageOOR, 0x00840063, P_ANY, P_ANY, T_NONE, false}, /* Volt out-of-range */ {CI_PWFrequencyOOR, 0x00840064, P_ANY, P_ANY, T_NONE, false}, /* Freq out-of-range */ {CI_Overload, 0x00840065, P_ANY, P_ANY, T_NONE, true }, /* Overload */ {CI_OverCharged, 0x00840066, P_ANY, P_ANY, T_NONE, false}, /* Overcharged */ {CI_OverTemp, 0x00840067, P_ANY, P_ANY, T_NONE, false}, /* Overtemp */ {CI_ShutdownRequested, 0x00840068, P_ANY, P_ANY, T_NONE, false}, /* ShutdownRequested */ {CI_ShutdownImminent, 0x00840069, P_ANY, P_ANY, T_NONE, true }, /* ShutdownImminent */ {CI_NONE, 0x0084006b, P_ANY, P_ANY, T_NONE, false}, /* Switch On/Off */ {CI_NONE, 0x0084006c, P_ANY, P_ANY, T_NONE, false}, /* Switchable */ {CI_Boost, 0x0084006e, P_ANY, P_ANY, T_NONE, true }, /* Boost */ {CI_Trim, 0x0084006f, P_ANY, P_ANY, T_NONE, true }, /* Buck */ {CI_CommunicationLost, 0x00840073, P_ANY, P_ANY, T_NONE, false}, /* CommunicationLost */ {CI_Manufacturer, 0x008400fd, P_ANY, P_ANY, T_INDEX, false}, /* iManufacturer */ {CI_UPSMODEL, 0x008400fe, P_ANY, P_ANY, T_INDEX, false}, /* iProduct */ {CI_SERNO, 0x008400ff, P_ANY, P_ANY, T_INDEX, false}, /* iSerialNumber */ {CI_MANDAT, 0x00850085, P_ANY, P_PWSUM, T_DATE, false}, /* ManufactureDate */ /* Page 0x85 is the Battery System Page */ /* CI USAGE PHYSICAL LOGICAL TYPE VOLATILE? */ {CI_RemCapLimit, 0x00850029, P_ANY, P_ANY, T_CAPACITY, false}, /* RemCapLimit */ {CI_RemTimeLimit, 0x0085002a, P_ANY, P_ANY, T_UNITS, false}, /* RemTimeLimit */ {CI_NONE, 0x0085002c, P_ANY, P_ANY, T_CAPACITY, false}, /* CapacityMode */ {CI_BelowRemCapLimit, 0x00850042, P_ANY, P_ANY, T_NONE, true }, /* BelowRemCapLimit */ {CI_RemTimeLimitExpired, 0x00850043, P_ANY, P_ANY, T_NONE, true }, /* RemTimeLimitExpired */ {CI_Charging, 0x00850044, P_ANY, P_ANY, T_NONE, false}, /* Charging */ {CI_Discharging, 0x00850045, P_ANY, P_ANY, T_NONE , true }, /* Discharging */ {CI_NeedReplacement, 0x0085004b, P_ANY, P_ANY, T_NONE , true }, /* NeedReplacement */ {CI_BATTLEV, 0x00850066, P_ANY, P_ANY, T_CAPACITY, true }, /* RemainingCapacity */ {CI_NONE, 0x00850067, P_ANY, P_ANY, T_CAPACITY, false}, /* FullChargeCapacity */ {CI_RUNTIM, 0x00850068, P_ANY, P_ANY, T_UNITS, true }, /* RunTimeToEmpty */ {CI_CycleCount, 0x0085006b, P_ANY, P_ANY, T_NONE, false}, {CI_BattPackLevel, 0x00850080, P_ANY, P_ANY, T_NONE, false}, /* BattPackLevel */ {CI_NONE, 0x00850083, P_ANY, P_ANY, T_CAPACITY, false}, /* DesignCapacity */ {CI_BATTDAT, 0x00850085, P_BATTERY, P_ANY, T_DATE, false}, /* ManufactureDate */ {CI_IDEN, 0x00850088, P_ANY, P_ANY, T_INDEX, false}, /* iDeviceName */ {CI_NONE, 0x00850089, P_ANY, P_ANY, T_INDEX, false}, /* iDeviceChemistry */ {CI_NONE, 0x0085008b, P_ANY, P_ANY, T_NONE, false}, /* Rechargeable */ {CI_WarningCapacityLimit, 0x0085008c, P_ANY, P_ANY, T_CAPACITY, false}, /* WarningCapacityLimit */ {CI_NONE, 0x0085008d, P_ANY, P_ANY, T_CAPACITY, false}, /* CapacityGranularity1 */ {CI_NONE, 0x0085008e, P_ANY, P_ANY, T_CAPACITY, false}, /* CapacityGranularity2 */ {CI_NONE, 0x0085008f, P_ANY, P_ANY, T_INDEX, false}, /* iOEMInformation */ {CI_ACPresent, 0x008500d0, P_ANY, P_ANY, T_NONE, true }, /* ACPresent */ {CI_BatteryPresent, 0x008500d1, P_ANY, P_ANY, T_NONE, true }, /* BatteryPresent */ {CI_ChargerVoltageOOR, 0x008500d8, P_ANY, P_ANY, T_NONE, false}, /* Volt out-of-range */ {CI_ChargerCurrentOOR, 0x008500d9, P_ANY, P_ANY, T_NONE, false}, /* Current out-of-range */ {CI_CurrentNotRegulated, 0x008500da, P_ANY, P_ANY, T_NONE, false}, /* Current not regulated */ {CI_VoltageNotRegulated, 0x008500db, P_ANY, P_ANY, T_NONE, false}, /* VoltageNotRegulated */ /* Pages 0xFF00 to 0xFFFF are vendor specific */ /* CI USAGE PHYSICAL LOGICAL TYPE VOLATILE? */ {CI_STESTI, 0xFF86001a, P_ANY, P_ANY, T_NONE, false}, /* APCSelfTestInterval */ {CI_STATUS, 0xFF860060, P_ANY, P_ANY, T_BITS, true }, /* APCStatusFlag */ {CI_DSHUTD, 0xFF860076, P_ANY, P_ANY, T_UNITS, false}, /* APCShutdownAfterDelay */ {CI_NONE, 0xFF860005, P_ANY, P_ANY, T_NONE, false}, /* APCGeneralCollection */ {CI_APCForceShutdown, 0xFF86007C, P_ANY, P_ANY, T_NONE, false}, /* APCForceShutdown */ {CI_TESTALARM, 0xFF860072, P_ANY, P_ANY, T_NONE, false}, /* APCTestAlarm */ // Removed the below due to all recent UPSes having the same garbage in this field // {CI_BattReplaceDate, 0xFF860016, P_ANY, P_ANY, T_APCDATE, false}, /* APCBattReplaceDate */ {CI_NONE, 0xFF860042, P_ANY, P_ANY, T_NONE, false}, /* APC_UPS_FirmwareRevision */ {CI_NONE, 0xFF860079, P_ANY, P_ANY, T_NONE, false}, /* APC_USB_FirmwareRevision */ {CI_RETPCT, 0xFF860019, P_ANY, P_ANY, T_CAPACITY, false}, /* APCBattCapBeforeStartup */ {CI_APCDelayBeforeStartup, 0xFF86007E, P_ANY, P_ANY, T_UNITS, false}, /* APCDelayBeforeStartup */ {CI_APCDelayBeforeShutdown, 0xFF86007D, P_ANY, P_ANY, T_UNITS, false}, /* APCDelayBeforeShutdown */ {CI_APCLineFailCause, 0xFF860052, P_ANY, P_ANY, T_NONE, true}, /* APCLineFailCause */ {CI_SENS, 0xFF860061, P_ANY, P_ANY, T_NONE, false}, /* APCSensitivity */ {CI_BUPBattCapBeforeStartup, 0x00860012, P_ANY, P_ANY, T_NONE, false}, /* BUPBattCapBeforeStartup */ {CI_BUPDelayBeforeStartup, 0x00860076, P_ANY, P_ANY, T_NONE, false}, /* BUPDelayBeforeStartup */ {CI_BUPSelfTest, 0x00860010, P_ANY, P_ANY, T_NONE, false}, /* BUPSelfTest */ {CI_BUPHibernate, 0x00850058, P_ANY, P_ANY, T_NONE, false}, /* BUPHibernate */ /* END OF TABLE */ {CI_NONE, 0x00000000, P_ANY, P_ANY, T_NONE, false} /* END OF TABLE */ }; /* * USB USAGE NOTES * * From the NUT project * * 0x860060 == "441HMLL" - looks like a 'capability' string * == locale 4, 4 choices, 1 byte each * == line sensitivity (high, medium, low, low) * NOTE! the above does not seem to correspond to my info * * 0x860013 == 44200155090 - capability again * == locale 4, 4 choices, 2 bytes, 00, 15, 50, 90 * == minimum charge to return online * * 0x860062 == D43133136127130 * == locale D, 4 choices, 3 bytes, 133, 136, 127, 130 * == high transfer voltage * * 0x860064 == D43103100097106 * == locale D, 4 choices, 3 bytes, 103, 100, 097, 106 * == low transfer voltage * * 0x860066 == 441HMLL (see 860060) * * 0x860074 == 4410TLN * == locale 4, 4 choices, 1 byte, 0, T, L, N * == alarm setting (5s, 30s, low battery, none) * * 0x860077 == 443060180300600 * == locale 4, 4 choices, 3 bytes, 060,180,300,600 * == wake-up delay (after power returns) * * * From MGE -- MGE specific items * * TestPeriod 0xffff0045 * RemainingCapacityLimitSetting 0xffff004d * LowVoltageBoostTransfer 0xffff0050 * HighVoltageBoostTransfer 0xffff0051 * LowVoltageBuckTransfer 0xffff0052 * HighVoltageBuckTransfer 0xffff0053 * iModel 0xffff00f0 */ /* Fetch the given CI from the UPS */ #define URB_DELAY_MS 20 bool UsbUpsDriver::usb_get_value(int ci, USB_VALUE *uval) { struct timeval now; struct timespec delay; int diff; /* * Some UPSes (650 CS and 800 RS, possibly others) lock up if * control transfers are issued too quickly, so we throttle a * bit here. */ if (_prev_time.tv_sec) { gettimeofday(&now, NULL); diff = TV_DIFF_MS(_prev_time, now); if (diff >= 0 && diff < URB_DELAY_MS) { delay.tv_sec = 0; delay.tv_nsec = (URB_DELAY_MS-diff)*1000000; nanosleep(&delay, NULL); } } gettimeofday(&_prev_time, NULL); return pusb_get_value(ci, uval); } bool UsbUpsDriver::get_capabilities() { int rc; /* Run platform-specific capabilities code */ rc = pusb_ups_get_capabilities(); if (!rc) return 0; /* * If the hardware supports CI_Discharging, ignore CI_ACPresent. * Some hardware (RS 1500, possibly others) reports confusing * values for these during self test. (Discharging=1 && ACPresent=1) */ if (_ups->UPS_Cap[CI_Discharging]) _ups->UPS_Cap[CI_ACPresent] = false; /* * Disable CI_NOMPOWER if UPS does not report it accurately. * Several models appear to always return 0 for this value. */ USB_VALUE uval; if (_ups->UPS_Cap[CI_NOMPOWER] && (!usb_get_value(CI_NOMPOWER, &uval) || ((int)uval.dValue == 0))) { Dmsg(100, "NOMPOWER disabled due to invalid reading from UPS\n"); _ups->UPS_Cap[CI_NOMPOWER] = false; } /* Detect broken BackUPS Pro model */ _quirk_old_backups_pro = false; if (_ups->UPS_Cap[CI_UPSMODEL] && usb_get_value(CI_UPSMODEL, &uval)) { Dmsg(250, "Checking for BackUPS Pro quirk \"%s\"\n", uval.sValue); if (!strcmp(uval.sValue, QUIRK_OLD_BACKUPS_PRO_MODEL_STRING)) { _quirk_old_backups_pro = true; Dmsg(100, "BackUPS Pro quirk enabled\n"); } } return 1; } /* * Operations which are platform agnostic and therefore can be * implemented here */ /* * Given a CI and a raw uval, update the UPSINFO structure with the * new value. Special handling for certain BackUPS Pro reports. * * Thanks to David Fries for this code. */ bool UsbUpsDriver::usb_process_value_bup(int ci, USB_VALUE* uval) { int val = (int)uval->dValue; char digits[] = { (char)(val>>16), (char)(val>>8), (char)val, 0 }; /* UPS_RUNTIME_LEFT */ if(ci == CI_RUNTIM) { _ups->TimeLeft = uval->dValue; /* already minutes */ Dmsg(200, "TimeLeft = %d\n", (int)_ups->TimeLeft); return true; } /* Bail if this value doesn't look to be ASCII encoded */ if(!isdigit(digits[0]) || !isdigit(digits[1]) || !isdigit(digits[2])) return false; switch(ci) { /* UPS_LOAD */ case CI_LOAD: _ups->UPSLoad = atoi(digits); Dmsg(200, "UPSLoad = %d\n", (int)_ups->UPSLoad); return true; /* LOW_TRANSFER_LEVEL */ case CI_LTRANS: _ups->lotrans = atoi(digits); return true; /* HIGH_TRANSFER_LEVEL */ case CI_HTRANS: _ups->hitrans = atoi(digits); return true; /* LINE_FREQ */ case CI_FREQ: _ups->LineFreq = atoi(digits); return true; default: return false; } } /* * Given a CI and a raw uval, update the UPSINFO structure with the * new value. */ void UsbUpsDriver::usb_process_value(int ci, USB_VALUE* uval) { int v, yy, mm, dd; char *p; /* * If BackUPS Pro quirk is enabled, try special decoding. If special decode * fails, we continue with the normal protocol. */ if (_quirk_old_backups_pro && usb_process_value_bup(ci, uval)) return; /* * ADK FIXME: This switch statement is really excessive. Consider * breaking it into volatile vs. non-volatile or perhaps an array * of function pointers with handler functions for each CI. */ switch(ci) { /* UPS_STATUS -- this is the most important status for apcupsd */ case CI_STATUS: _ups->Status &= ~0xff; _ups->Status |= uval->iValue & 0xff; Dmsg(200, "Status=0x%08x\n", _ups->Status); break; case CI_ACPresent: if (uval->iValue) _ups->set_online(); Dmsg(200, "ACPresent=%d\n", uval->iValue); break; case CI_Discharging: _ups->set_online(!uval->iValue); Dmsg(200, "Discharging=%d\n", uval->iValue); break; case CI_BelowRemCapLimit: if (uval->iValue) _ups->set_battlow(); Dmsg(200, "BelowRemCapLimit=%d\n", uval->iValue); break; case CI_RemTimeLimitExpired: if (uval->iValue) _ups->set_battlow(); Dmsg(200, "RemTimeLimitExpired=%d\n", uval->iValue); break; case CI_ShutdownImminent: if (uval->iValue) _ups->set_battlow(); Dmsg(200, "ShutdownImminent=%d\n", uval->iValue); break; case CI_Boost: if (uval->iValue) _ups->set_boost(); Dmsg(200, "Boost=%d\n", uval->iValue); break; case CI_Trim: if (uval->iValue) _ups->set_trim(); Dmsg(200, "Trim=%d\n", uval->iValue); break; case CI_Overload: if (uval->iValue) _ups->set_overload(); Dmsg(200, "Overload=%d\n", uval->iValue); break; case CI_NeedReplacement: if (uval->iValue) _ups->set_replacebatt(uval->iValue); Dmsg(200, "ReplaceBatt=%d\n", uval->iValue); break; /* LINE_VOLTAGE */ case CI_VLINE: _ups->LineVoltage = uval->dValue; Dmsg(200, "LineVoltage = %d\n", (int)_ups->LineVoltage); break; /* OUTPUT_VOLTAGE */ case CI_VOUT: _ups->OutputVoltage = uval->dValue; Dmsg(200, "OutputVoltage = %d\n", (int)_ups->OutputVoltage); break; /* BATT_FULL Battery level percentage */ case CI_BATTLEV: _ups->BattChg = uval->dValue; Dmsg(200, "BattCharge = %d\n", (int)_ups->BattChg); break; /* BATT_VOLTAGE */ case CI_VBATT: _ups->BattVoltage = uval->dValue; Dmsg(200, "BattVoltage = %d\n", (int)_ups->BattVoltage); break; /* UPS_LOAD */ case CI_LOAD: _ups->UPSLoad = uval->dValue; Dmsg(200, "UPSLoad = %d\n", (int)_ups->UPSLoad); break; /* LINE_FREQ */ case CI_FREQ: _ups->LineFreq = uval->dValue; Dmsg(200, "LineFreq = %d\n", (int)_ups->LineFreq); break; /* UPS_RUNTIME_LEFT */ case CI_RUNTIM: _ups->TimeLeft = uval->dValue / 60; /* convert to minutes */ Dmsg(200, "TimeLeft = %d\n", (int)_ups->TimeLeft); break; /* UPS_TEMP */ case CI_ITEMP: _ups->UPSTemp = uval->dValue - 273.15; /* convert to deg C. */ Dmsg(200, "ITemp = %d\n", (int)_ups->UPSTemp); break; /* Humidity percentage */ case CI_HUMID: _ups->humidity = uval->dValue; Dmsg(200, "Humidity = %d\n", (int)_ups->humidity); break; /* Ambient temperature */ case CI_ATEMP: _ups->ambtemp = uval->dValue - 273.15; /* convert to deg C. */; Dmsg(200, "ATemp = %d\n", (int)_ups->ambtemp); break; /* Self test results */ case CI_ST_STAT: switch (uval->iValue) { case 1: /* Passed */ _ups->testresult = TEST_PASSED; break; case 2: /* Warning */ _ups->testresult = TEST_WARNING; break; case 3: /* Error */ case 4: /* Aborted */ _ups->testresult = TEST_FAILED; break; case 5: /* In progress */ _ups->testresult = TEST_INPROGRESS; break; case 6: /* None */ _ups->testresult = TEST_NONE; break; default: _ups->testresult = TEST_UNKNOWN; break; } break; /* Self test interval */ case CI_STESTI: switch (uval->iValue) { case 0: strlcpy(_ups->selftest, "None", sizeof(_ups->selftest)); break; case 1: strlcpy(_ups->selftest, "Power On", sizeof(_ups->selftest)); break; case 2: strlcpy(_ups->selftest, "7 days", sizeof(_ups->selftest)); break; default: strlcpy(_ups->selftest, "14 days", sizeof(_ups->selftest)); break; } break; /* Reason for last xfer to battery */ case CI_APCLineFailCause: Dmsg(100, "CI_APCLineFailCause=%d\n", uval->iValue); switch (uval->iValue) { case 0: /* No transfers have ocurred */ _ups->lastxfer = XFER_NONE; break; case 2: /* High line voltage */ _ups->lastxfer = XFER_OVERVOLT; break; case 3: /* Ripple */ _ups->lastxfer = XFER_RIPPLE; break; case 1: /* Low line voltage */ case 4: /* notch, spike, or blackout */ case 8: /* Notch or blackout */ case 9: /* Spike or blackout */ _ups->lastxfer = XFER_UNDERVOLT; break; case 6: /* DelayBeforeShutdown or APCDelayBeforeShutdown */ case 10: /* Graceful shutdown by accessories */ _ups->lastxfer = XFER_FORCED; break; case 7: /* Input frequency out of range */ _ups->lastxfer = XFER_FREQ; break; case 5: /* Self Test or Discharge Calibration commanded thru */ /* Test usage, front button, or 2 week self test */ case 11: /* Test usage invoked */ case 12: /* Front button initiated self test */ case 13: /* 2 week self test */ _ups->lastxfer = XFER_SELFTEST; break; default: _ups->lastxfer = XFER_UNKNOWN; break; } break; /* Battery connected/disconnected */ case CI_BatteryPresent: /* * Work around a firmware bug in some models (RS 1500, * possibly others) where BatteryPresent=1 is sporadically * reported while the battery is disconnected. The work- * around is to ignore BatteryPresent=1 until we see it * at least twice in a row. The down side of this approach * is that legitimate BATTATTCH events are unnecessarily * delayed. C'est la vie. */ if (uval->iValue) { if (_bpcnt++) _ups->set_battpresent(); } else { _bpcnt = 0; _ups->clear_battpresent(); } Dmsg(200, "BatteryPresent=%d\n", uval->iValue); break; /* UPS_NAME */ case CI_IDEN: if (_ups->upsname[0] == 0 && uval->sValue[0] != 0) strlcpy(_ups->upsname, uval->sValue, sizeof(_ups->upsname)); break; /* model, firmware */ case CI_UPSMODEL: /* Truncate Firmware info on APC Product string */ if ((p = strstr(uval->sValue, "FW:"))) { *p = '\0'; // Terminate model name p += 3; // Skip "FW:" while (isspace(*p)) // Skip whitespace after "FW:" p++; strlcpy(_ups->firmrev, p, sizeof(_ups->firmrev)); _ups->UPS_Cap[CI_REVNO] = true; } /* Kill leading whitespace on model name */ p = uval->sValue; while (isspace(*p)) p++; strlcpy(_ups->upsmodel, p, sizeof(_ups->upsmodel)); break; /* WAKEUP_DELAY */ case CI_DWAKE: _ups->dwake = (int)uval->dValue; break; /* SLEEP_DELAY */ case CI_DSHUTD: _ups->dshutd = (int)uval->dValue; break; /* LOW_TRANSFER_LEVEL */ case CI_LTRANS: _ups->lotrans = (int)uval->dValue; break; /* HIGH_TRANSFER_LEVEL */ case CI_HTRANS: _ups->hitrans = (int)uval->dValue; break; /* UPS_BATT_CAP_RETURN */ case CI_RETPCT: _ups->rtnpct = (int)uval->dValue; break; /* LOWBATT_SHUTDOWN_LEVEL */ case CI_DLBATT: _ups->dlowbatt = (int)uval->dValue; break; /* UPS_MANUFACTURE_DATE */ case CI_MANDAT: asnprintf(_ups->birth, sizeof(_ups->birth), "%4d-%02d-%02d", (uval->iValue >> 9) + 1980, (uval->iValue >> 5) & 0xF, uval->iValue & 0x1F); break; /* Last UPS_BATTERY_REPLACE */ case CI_BATTDAT: asnprintf(_ups->battdat, sizeof(_ups->battdat), "%4d-%02d-%02d", (uval->iValue >> 9) + 1980, (uval->iValue >> 5) & 0xF, uval->iValue & 0x1F); break; /* APC_BATTERY_DATE */ case CI_BattReplaceDate: v = uval->iValue; yy = ((v >> 4) & 0xF) * 10 + (v & 0xF) + 2000; v >>= 8; dd = ((v >> 4) & 0xF) * 10 + (v & 0xF); v >>= 8; mm = ((v >> 4) & 0xF) * 10 + (v & 0xF); asnprintf(_ups->battdat, sizeof(_ups->battdat), "%4d-%02d-%02d", yy, mm, dd); break; /* UPS_SERIAL_NUMBER */ case CI_SERNO: strlcpy(_ups->serial, uval->sValue, sizeof(_ups->serial)); /* * If serial number has garbage, trash it. */ for (p = _ups->serial; *p; p++) { if (*p < ' ' || *p > 'z') { *_ups->serial = 0; _ups->UPS_Cap[CI_SERNO] = false; } } break; /* Nominal output voltage when on batteries */ case CI_NOMOUTV: _ups->NomOutputVoltage = (int)uval->dValue; while (_ups->NomOutputVoltage > 1000) _ups->NomOutputVoltage /= 10; // Some UPSes get the units wrong break; /* Nominal input voltage */ case CI_NOMINV: _ups->NomInputVoltage = (int)uval->dValue; while (_ups->NomInputVoltage > 1000) _ups->NomInputVoltage /= 10; // Some UPSes get the units wrong break; /* Nominal battery voltage */ case CI_NOMBATTV: _ups->nombattv = uval->dValue; break; /* Nominal power */ case CI_NOMPOWER: _ups->NomPower = (int)uval->dValue; break; /* Sensitivity */ case CI_SENS: switch (uval->iValue) { case 0: strlcpy(_ups->sensitivity, "Low", sizeof(_ups->sensitivity)); break; case 1: strlcpy(_ups->sensitivity, "Medium", sizeof(_ups->sensitivity)); break; case 2: strlcpy(_ups->sensitivity, "High", sizeof(_ups->sensitivity)); break; default: strlcpy(_ups->sensitivity, "Unknown", sizeof(_ups->sensitivity)); break; } break; case CI_DALARM: switch (uval->iValue) { case 1: // Never strlcpy(_ups->beepstate, "N", sizeof(_ups->beepstate)); break; case 2: // 30 seconds default: strlcpy(_ups->beepstate, "T", sizeof(_ups->beepstate)); break; } break; default: break; } } /* Fetch the given CI from the UPS and update the UPSINFO structure */ bool UsbUpsDriver::usb_update_value(int ci) { USB_VALUE uval; if (!usb_get_value(ci, &uval)) return false; usb_process_value(ci, &uval); return true; } /* Process commands from the main loop */ bool UsbUpsDriver::entry_point(int command, void *data) { struct timespec delay = {0, 40000000}; switch (command) { case DEVICE_CMD_CHECK_SELFTEST: Dmsg(80, "Checking self test.\n"); /* * XXX FIXME * * One day we will do this test inside the driver and not as an * entry point. */ /* Reason for last transfer to batteries */ nanosleep(&delay, NULL); /* Give UPS a chance to update the value */ if (usb_update_value(CI_WHY_BATT) || usb_update_value(CI_APCLineFailCause)) { Dmsg(80, "Transfer reason: %d\n", _ups->lastxfer); /* See if this is a self test rather than power failure */ if (_ups->lastxfer == XFER_SELFTEST) { /* * set Self Test start time */ _ups->SelfTest = time(NULL); Dmsg(80, "Self Test time: %s", ctime(&_ups->SelfTest)); } } break; case DEVICE_CMD_GET_SELFTEST_MSG: nanosleep(&delay, NULL); /* Give UPS a chance to update the value */ return usb_update_value(CI_ST_STAT); default: return FAILURE; } return SUCCESS; } /* * Read UPS info that changes -- e.g. voltage, temperature, etc. * * This routine is called once every N seconds to get a current * idea of what the UPS is doing. */ bool UsbUpsDriver::read_volatile_data() { time_t last_poll = _ups->poll_time; time_t now = time(NULL); Dmsg(200, "Enter usb_ups_read_volatile_data\n"); /* * If we are not on batteries, update this maximum once every * MAX_VOLATILE_POLL_RATE seconds. This prevents flailing around * too much if the UPS state is rapidly changing while on mains. */ if (_ups->is_onbatt() && last_poll && (now - last_poll < MAX_VOLATILE_POLL_RATE)) { return 1; } write_lock(_ups); _ups->poll_time = now; /* save time stamp */ /* Clear APC status bits; let the various CIs set them again */ _ups->Status &= ~0xFF; /* Loop through all known data, polling those marked volatile */ for (int i=0; _known_info[i].usage_code; i++) { if (_known_info[i].isvolatile && _known_info[i].ci != CI_NONE) usb_update_value(_known_info[i].ci); } write_unlock(_ups); return 1; } /* * Read UPS info that remains unchanged -- e.g. transfer voltages, * shutdown delay, etc. * * This routine is called once when apcupsd is starting. */ bool UsbUpsDriver::read_static_data() { write_lock(_ups); /* Loop through all known data, polling those marked non-volatile */ for (int i=0; _known_info[i].usage_code; i++) { if (!_known_info[i].isvolatile && _known_info[i].ci != CI_NONE) usb_update_value(_known_info[i].ci); } write_unlock(_ups); return 1; } /* * How long to wait before killing output power. * This value is NOT used on BackUPS Pro models. */ #define SHUTDOWN_DELAY 60 /* * How many seconds of good utility power before turning output back on. * This value is NOT used on BackUPS Pro models. */ #define STARTUP_DELAY 10 /* * What percentage battery charge before turning output back on. * On at least some models this must be a multiple of 15%. * This value is NOT used on BackUPS Pro models. */ #define STARTUP_PERCENT 0 bool UsbUpsDriver::kill_power() { const char *func; int hibernate = 0; int val; Dmsg(200, "Enter usb_ups_kill_power\n"); /* * We try various different ways to put the UPS into hibernation * mode (i.e. killpower). Some of these commands are not supported * on all UPSes, but that should cause no harm. */ /* * First, set required battery capacity before startup to 0 so UPS * will not wait for the battery to charge before turning back on. * Not all UPSes have this capability, so this setting is allowed * to fail. The value we program here should be made configurable * some day. */ if (UPS_HAS_CAP(CI_RETPCT)) { func = "CI_RETPCT"; if (!write_int_to_ups(CI_RETPCT, STARTUP_PERCENT, func)) Dmsg(100, "Unable to set %s (not an error)\n", func); } /* * BackUPS Pro uses an enumerated setting (reads percent in * ASCII). The value advances to the next higher setting by * writing a '1' and to the next lower setting when writing a * '2'. The value wraps around when advanced past the max or min * setting. * * We walk the setting down to the minimum of 0. * * Credit goes to John Zielinski for figuring * this out. */ if (UPS_HAS_CAP(CI_BUPBattCapBeforeStartup)) { if (read_int_from_ups(CI_BUPBattCapBeforeStartup, &val)) { func = "CI_BUPBattCapBeforeStartup"; switch (val) { case 0x3930: /* 90% */ write_int_to_ups(CI_BUPBattCapBeforeStartup, 2, func); /* Falls thru... */ case 0x3630: /* 60% */ write_int_to_ups(CI_BUPBattCapBeforeStartup, 2, func); /* Falls thru... */ case 0x3135: /* 15% */ write_int_to_ups(CI_BUPBattCapBeforeStartup, 2, func); /* Falls thru... */ case 0x3030: /* 00% */ break; default: Dmsg(100, "Unknown BUPBattCapBeforeStartup value (%04x)\n", val); break; } } } /* * Second, set the length of time to wait after power returns * before starting up. We set it to something pretty low, but it * seems the UPS rounds this value up to the nearest multiple of * 60 seconds. Not all UPSes have this capability, so this setting * is allowed to fail. The value we program here should be made * configurable some day. */ if (UPS_HAS_CAP(CI_APCDelayBeforeStartup)) { func = "CI_APCDelayBeforeStartup"; if (!write_int_to_ups(CI_APCDelayBeforeStartup, STARTUP_DELAY, func)) { Dmsg(100, "Unable to set %s (not an error)\n", func); } } /* * BackUPS Pro uses an enumerated setting (reads seconds in ASCII). * The value advances to the next higher setting by writing a '1' * and to the next lower setting when writing a '2'. The value * wraps around when advanced past the max or min setting. * * We walk the setting down to the minimum of 60. * * Credit goes to John Zielinski for figuring * this out. */ if (UPS_HAS_CAP(CI_BUPDelayBeforeStartup)) { if (read_int_from_ups(CI_BUPDelayBeforeStartup, &val)) { func = "CI_BUPDelayBeforeStartup"; switch (val) { case 0x363030: /* 600 sec */ write_int_to_ups(CI_BUPDelayBeforeStartup, 2, func); /* Falls thru... */ case 0x333030: /* 300 sec */ write_int_to_ups(CI_BUPDelayBeforeStartup, 2, func); /* Falls thru... */ case 0x313830: /* 180 sec */ write_int_to_ups(CI_BUPDelayBeforeStartup, 2, func); /* Falls thru... */ case 0x3630: /* 60 sec */ break; default: Dmsg(100, "Unknown CI_BUPDelayBeforeStartup value (%04x)\n", val); break; } } } /* * BackUPS hibernate * * Alternately, if APCDelayBeforeShutdown is available, setting * it will start a countdown after which the UPS will hibernate. */ if (!hibernate && UPS_HAS_CAP(CI_APCDelayBeforeShutdown)) { Dmsg(000, "UPS appears to support BackUPS style hibernate.\n"); func = "CI_APCDelayBeforeShutdown"; if (!write_int_to_ups(CI_APCDelayBeforeShutdown, SHUTDOWN_DELAY, func)) { Dmsg(000, "Kill power function \"%s\" failed.\n", func); } else { hibernate = 1; } } /* * SmartUPS hibernate * * If both DWAKE and DelayBeforeShutdown are available, trigger * a hibernate by writing DWAKE a few seconds longer than * DelayBeforeShutdown. ORDER IS IMPORTANT. The write to * DelayBeforeShutdown starts both timers ticking down and the * UPS will hibernate when DelayBeforeShutdown hits zero. */ if (!hibernate && UPS_HAS_CAP(CI_DWAKE) && UPS_HAS_CAP(CI_DelayBeforeShutdown)) { Dmsg(000, "UPS appears to support SmartUPS style hibernate.\n"); func = "CI_DWAKE"; if (!write_int_to_ups(CI_DWAKE, SHUTDOWN_DELAY + 4, func)) { Dmsg(000, "Kill power function \"%s\" failed.\n", func); } else { func = "CI_DelayBeforeShutdown"; if (!write_int_to_ups(CI_DelayBeforeShutdown, SHUTDOWN_DELAY, func)) { Dmsg(000, "Kill power function \"%s\" failed.\n", func); /* reset prev timer */ write_int_to_ups(CI_DWAKE, -1, "CI_DWAKE"); } else { hibernate = 1; } } } /* * BackUPS Pro shutdown * * Here we see the BackUPS Pro further distinguish itself as * having the most broken firmware of any APC product yet. We have * to trigger two magic boolean flags using APC custom usages. * First we hit BUPHibernate and follow that with a write to * BUPSelfTest (!). * * Credit goes to John Zielinski for figuring * this out. */ if (!hibernate && UPS_HAS_CAP(CI_BUPHibernate) && UPS_HAS_CAP(CI_BUPSelfTest)) { Dmsg(000, "UPS appears to support BackUPS Pro style hibernate.\n"); func = "CI_BUPHibernate"; if (!write_int_to_ups(CI_BUPHibernate, 1, func)) { Dmsg(000, "Kill power function \"%s\" failed.\n", func); } else { func = "CI_BUPSelfTest"; if (!write_int_to_ups(CI_BUPSelfTest, 1, func)) { Dmsg(000, "Kill power function \"%s\" failed.\n", func); write_int_to_ups(CI_BUPHibernate, 0, "CI_BUPHibernate"); } else { hibernate = 1; } } } /* * All UPSes tested so far are covered by one of the above cases. * However, there are a some other ways to hibernate. */ /* * Misc method A * * Writing CI_DelayBeforeReboot starts a countdown timer, after * which the UPS will hibernate. If utility power is out, the UPS * will stay hibernating until power is restored. SmartUPSes seem * to support this method, but PowerChute uses the dual countdown * method above, so we prefer that one. UPSes seem to round the * value up to 90 seconds if it is any lower. Note that the * behavior described here DOES NOT comply with the standard set * out in the HID Usage Tables for Power Devices spec. */ if (!hibernate && UPS_HAS_CAP(CI_DelayBeforeReboot)) { Dmsg(000, "UPS appears to support DelayBeforeReboot style hibernate.\n"); func = "CI_DelayBeforeReboot"; if (!write_int_to_ups(CI_DelayBeforeReboot, SHUTDOWN_DELAY, func)) Dmsg(000, "Kill power function \"%s\" failed.\n", func); else hibernate = 1; } /* * Misc method B * * We can set CI_APCForceShutdown to true (it's a boolean flag). * We have no control over how long the UPS waits before turning * off. Experimentally it seems to be about 60 seconds. Some * BackUPS models support this in addition to the preferred * BackUPS method above. It's included here "just in case". */ if (!hibernate && UPS_HAS_CAP(CI_APCForceShutdown)) { Dmsg(000, "UPS appears to support ForceShutdown style hibernate.\n"); func = "CI_APCForceShutdown"; if (!write_int_to_ups(CI_APCForceShutdown, 1, func)) Dmsg(000, "Kill power function \"%s\" failed.\n", func); else hibernate = 1; } if (!hibernate) { Dmsg(000, "Couldn't put UPS into hibernation mode. Attempting shutdown.\n"); hibernate = shutdown(); } /* * Workaround for UPS firmware bug. Some UPSes have an issue where, after * killpower completes and utility power is restored, they appear to re- * execute the killpower command when the USB is enumerated again. This * happens repeatedly until the USB is disconnected. * * The "Back-UPS RS1000G FW:868.L3 -P.D USB FW:L3 -P" is known to have this * issue. Other Back-UPS models may have it as well. * * As a workaround, we read back a benign status register after sending the * killpower command. This is thought to clear the UPS's command buffer or * at least place a harmless command in it. We use CI_STATUS as that is a * usage any UPS should have. */ (void)read_int_from_ups(CI_STATUS, &val); Dmsg(200, "Leave usb_ups_kill_power\n"); return hibernate; } bool UsbUpsDriver::shutdown() { const char *func; int shutdown = 0; Dmsg(200, "Enter usb_ups_shutdown\n"); /* * Complete shutdown * * This method turns off the UPS off completely after a given delay. * The only way to power the UPS back on is to manually hit the * power button. */ if (!shutdown && UPS_HAS_CAP(CI_DelayBeforeShutdown)) { Dmsg(000, "UPS appears to support DelayBeforeShutdown style shutdown.\n"); func = "CI_DelayBeforeShutdown"; if (!write_int_to_ups(CI_DelayBeforeShutdown, SHUTDOWN_DELAY, func)) Dmsg(000, "Kill power function \"%s\" failed.\n", func); else shutdown = 1; } /* * I give up. */ if (!shutdown) { Dmsg(000, "I don't know how to turn off this UPS...sorry.\n" "Please report this, along with the output from\n" "running examples/hid-ups, to the apcupsd-users\n" "mailing list (apcupsd-users@lists.sourceforge.net).\n"); } /* * Note that there are a couple other CIs that look interesting * for shutdown, but they're not what we want. * * APCShutdownAfterDelay: Tells the UPS how many seconds to wait * after power goes out before asserting ShutdownRequested * (see next item). * * CI_ShutdownRequested: This is an indicator from the UPS to the * server that it would like the server to begin shutting * down. In conjunction with APCShutdownAfterDelay this can be * used to offload the decision of when to shut down the * server to the UPS. */ Dmsg(200, "Leave usb_ups_shutdown\n"); return shutdown; } /* * Helper functions for use by platform specific code */ double UsbUpsDriver::pow_ten(int exponent) { int i; double val = 1; if (exponent < 0) { exponent = -exponent; for (i = 0; i < exponent; i++) val = val / 10; return val; } else { for (i = 0; i < exponent; i++) val = val * 10; } return val; } /* Called by platform-specific code to report an interrupt event */ bool UsbUpsDriver::usb_report_event(int ci, USB_VALUE *uval) { Dmsg(200, "USB driver reported event ci=%d, val=%f\n", ci, uval->dValue); /* Got an event: go process it */ usb_process_value(ci, uval); switch (ci) { /* * Some important usages cause us to abort interrupt waiting * so immediate action can be taken. */ case CI_Discharging: case CI_ACPresent: case CI_BelowRemCapLimit: case CI_BATTLEV: case CI_RUNTIM: case CI_NeedReplacement: case CI_ShutdownImminent: case CI_BatteryPresent: return true; /* * We don't handle these directly, but rather use them as a * signal to go poll the full set of volatile data. */ case CI_IFailure: case CI_Overload: case CI_PWVoltageOOR: case CI_PWFrequencyOOR: case CI_OverCharged: case CI_OverTemp: case CI_CommunicationLost: case CI_ChargerVoltageOOR: case CI_ChargerCurrentOOR: case CI_CurrentNotRegulated: case CI_VoltageNotRegulated: return true; /* * Anything else is relatively unimportant, so we can * keep gathering data until the timeout. */ default: return false; } } /* Constructor for s_usb_value */ UsbUpsDriver::s_usb_value::s_usb_value() : value_type(V_DEFAULT), dValue(0), iValue(0), UnitName("Uninitialized") { strlcpy(sValue, "Uninitialized", sizeof(sValue)); } apcupsd-3.14.14/src/drivers/usb/usb.h000066400000000000000000000103561274230402600173300ustar00rootroot00000000000000/* * usb.h * * Public USB driver interface exposed to the driver management layer. */ /* * Copyright (C) 2001-2004 Kern Sibbald * Copyright (C) 2004-2005 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef _USB_H #define _USB_H #include "usb_common.h" class UsbUpsDriver: public UpsDriver { public: UsbUpsDriver(UPSINFO *ups); virtual ~UsbUpsDriver() {} static UpsDriver *Factory(UPSINFO *ups); // UpsDriver functions impemented in UsbUpsDriver base class virtual bool get_capabilities(); virtual bool read_volatile_data(); virtual bool read_static_data(); virtual bool kill_power(); virtual bool shutdown(); virtual bool entry_point(int command, void *data); // Extra functions exported for use by apctest // Implemented by derived XXXUsbUpsDriver class virtual int write_int_to_ups(int ci, int value, char const* name) = 0; virtual int read_int_from_ups(int ci, int *value) = 0; protected: typedef struct s_usb_value { s_usb_value(); /* Constructor */ int value_type; /* Type of returned value */ double dValue; /* Value if double */ int iValue; /* Integer value */ const char *UnitName; /* Name of units */ char sValue[MAXSTRING]; /* Value if string */ } USB_VALUE; // Helper functions implemented in UsbUpsDriver bool usb_get_value(int ci, USB_VALUE *uval); bool usb_process_value_bup(int ci, USB_VALUE* uval); void usb_process_value(int ci, USB_VALUE* uval); bool usb_update_value(int ci); bool usb_report_event(int ci, USB_VALUE *uval); double pow_ten(int exponent); struct s_known_info { int ci; /* Command index */ unsigned usage_code; /* Usage code */ unsigned physical; /* Physical usage */ unsigned logical; /* Logical usage */ int data_type; /* Data type expected */ bool isvolatile; /* Volatile data item */ }; static const s_known_info _known_info[]; // Functions implemented in derived XXXUsbUpsDriver class virtual bool pusb_ups_get_capabilities() = 0; virtual bool pusb_get_value(int ci, USB_VALUE *uval) = 0; bool _quirk_old_backups_pro; struct timeval _prev_time; int _bpcnt; }; /* Max rate to update volatile data */ #define MAX_VOLATILE_POLL_RATE 5 /* How often to retry the link (seconds) */ #define LINK_RETRY_INTERVAL 5 /* These are the data_type expected for our know_info */ #define T_NONE 0 /* No units */ #define T_INDEX 1 /* String index */ #define T_CAPACITY 2 /* Capacity (usually %) */ #define T_BITS 3 /* Bit field */ #define T_UNITS 4 /* Use units/exponent field */ #define T_DATE 5 /* Date */ #define T_APCDATE 6 /* APC date */ /* These are the resulting value types returned */ #define V_DEFAULT 0 /* Unknown type */ #define V_DOUBLE 1 /* Double */ #define V_STRING 2 /* String pointer */ #define V_INTEGER 3 /* Integer */ /* These are the desired Physical usage values we want */ #define P_ANY 0 /* Any value */ #define P_OUTPUT 0x84001c /* Output values */ #define P_BATTERY 0x840012 /* Battery values */ #define P_INPUT 0x84001a /* Input values */ #define P_PWSUM 0x840024 /* Power summary */ #define P_APC1 0xff860007 /* From AP9612 environmental monitor */ /* No Command Index, don't save this value */ #define CI_NONE -1 /* Check if the UPS has the given capability */ #define UPS_HAS_CAP(ci) (_ups->UPS_Cap[ci]) #endif /* _USB_H */ apcupsd-3.14.14/src/gapcmon/000077500000000000000000000000001274230402600155365ustar00rootroot00000000000000apcupsd-3.14.14/src/gapcmon/ChangeLog000066400000000000000000000312051274230402600173110ustar00rootroot00000000000000gapcmon (0.9.0) stable; urgency=normal * Mon Sep 15 2008 James Scott, Jr. - Housekeeping, applying maintainer patches for FreeBSD & KDE effects - eggtrayicon.c transparency patches by Jason Hale (bsdkaffee) - gapcmon.c sockaddr_in include patch by Jason Hale (bsdkaffee) gapcmon (0.8.9-0) stable; urgency=normal * Fri Aug 8 2008 James Scott, Jr. - Removed GTK_STOCK_CLOSE buttons from all windows in response to a KDE issue, where KDEs window manager has now decided to ignore gtk_window_iconify() api calls. gtk_widget_hide() is being in place of _iconify() however, the close buttons where stranded because using _hide at that level could and did cause one or more window to be hidden with no tasklist or pager entry to restore it with. gapcmon (0.8.8-0) stable; urgency=normal * Sat Jul 12 2008 James Scott, Jr. - Fixed a timing error present on quad cores related to the reuse of sockets. NIS connections would randomly fail if created while another thread was destroying a connection. gapcmon (0.8.7-0) stable; urgency=normal # Tues May 6 2008 James Scott - Fixup tooltip monitor and main monitor to correct the use on NOMPOWER. It is the max scale value for ups wattage reading. gapcmon (0.8.6-0) stable; urgency=normal # Sat Feb 23 2008 James Scott, Jr. - Added ICON_DIR to compiler makefiles to support load_icons ability to find icons at run-time. gapcmon (0.8.5-1) stable; urgency=normal * Tue Sep 25 2007 James Scott, Jr. - Add a new data value to details page: NOMPOWER - A few code structure cleanups in sknet_ namespace gapcmon (0.8.5-0) stable; urgency=normal * Mon Jan 22 2007 James Scott, Jr. - Replace the network routine to use GIOChannels vs gnomeVFS. This was done to improve portability by reducing external packages. gapcmon (0.8.4-0) stable; urgency=normal * Sat Dec 30 2006 James Scott, Jr. - Added gapc_util_manage_events() to replace gtk_widget_hide() functionality. Now when use_systray is checked for control window, app will start up in icon mode. gapcmon (0.8.3-0) stable; urgency=normal * Mon Jul 3 2006 James Scott, Jr. - Added graph color properties page to control.panel notebook. This * Mon Jul 3 2006 James Scott, Jr. - Added graph color properties page to control.panel notebook. This allow user to set the series color for the history chart in the monitor window. gapcmon (0.8.2-1) stable; urgency=normal * Wed May 24 2006 James Scott, Jr. - Correct the sequence of statement in gapcmon.desktop and removed the [en_US] flag where present. This re-enables the menu item in most desktop systems. gapcmon (0.8.2-0) stable; urgency=normal * Mon May 8 2006 James Scott, Jr. - Correct the timestamp recording feature of lg_graph_data_add_value() to append the timestamp rather than prepend it. This corrected the presentation of the timestamp to the user in reverse order. - Constrained the tooltip to present only for actual data points. It was presenting for non-existant data points resulting in time_zero display's ( dec 31, 1970...) gapcmon (0.8.1-0) stable; urgency=normal * Mon May 8 2006 James Scott, Jr. - Rewrite the line_graph code to replace gtkglgraph.c|h. - Added redraw to each draw_tooltip call. gapcmon (0.7.0-0) stable; urgency=normal * Thru Apr 18 2006 James Scott, Jr. - Rewrite to include desktop independant features completed. - This module replace all other interations of gapcmon: including gapc, gpanel, gpanel_apcmon, etc. gapcmon (0.6.2-0) stable; urgency=normal * Thru Apr 6 2006 James Scott, Jr. - Implemented the FreeDesktop.org spec for notification_area icons using modified source from gnome.cvs:libegg. - Added a paned window to help user manage size of icons and notebooks - Attempted to implement true alphabetic sort of icons labels, by adding label text to main.window icons ( not working the why I would like ) - Reviewed gdk_threads_enter() useage and removed duplicates from gtkglgraph.c in response to a user bug ( no x|y-labels on chart-N+1) - Several routine consolidated or parameter-ized. gapcmon (0.6.1-0) stable; urgency=normal * Sat Apr 1 2006 James Scott, Jr. - Implemented the tooltip in line graph history page. Now displays the colored point value under the mouse. - Updated the gapc_monitor_update() in gapcmon_core.c to handle the 0-100 percent scale for charted data points. LINEV uses HITRANS as scale and defaults to 120:230, BATTV uses 12:24 unless NOMBATTV is present, and LOADPCT, TIMELEFT, are inversly related to each other. BCHARGE values are taken as is. - Updated the gapc_util_point_filter_set() in gapcmon_core.c to handle out of range graphing data points by defaulting them to 108 percent or zero percent. gapcmon (0.6.0-0) stable; urgency=normal * Fri Mar 31 2006 James Scott, Jr. - Implemented the sort_icons function to reorder dynamically created monitor icons. - Added gtk_glgraph_unrealize() and gtk_glgraph_destroy() to the gapcmon_gtkglgraph subpackage. To fix multi-threaded operations. - Integrated the source files into a shared arrangement. gapcmon_core.[c|h] gapcmon_gtkglgraph.[c|h] and two anchor files gapcmon.h and gpanel_apcmon.c - Added gtk_glgraph feature to gapcmon replacing the progress bars on the overview page. - Added support for up to eight monitors to gapcmon with the full functionality of gpanel. commandline take one value the instance number, which defaults to zero. - Reordered preferences columns for better presentation. gapcmon (0.5.7-3) stable; urgency=normal * Fri Mar 17 2006 James Scott, Jr. - Pruned gtkglgraph.c|h of un-used and un-needed routines - Implemented the none-enabled and COMMLOST program states gapcmon (0.5.7-2) stable; urgency=normal * Thu Mar 16 2006 James Scott, Jr. - Modified gpanel_apcmon.c to handle an unexpected intial state issue and some stalled Icon updates issue. - none-enabled relates to the very first execution without gconf2 schemas installed to supply defaults. This resulted in no icons or monitor being enabled, and thus no access to the user interface to request one; or a condition where one icon is present but dis-functional. Fixed - stalled icons relate to a state where the user has selected and repeated deseleted a particular monitor. The icon for that monitor will default to OFFLINE and not change until the UPS actually changes state like to charging, or on battery. Fixed. gapcmon (0.5.7-0) stable; urgency=normal * Mon Mar 14 2006 James Scott, Jr. - Modified gp_mon.c to use the GtkGLGraph package for line graphs. Caused two files containing GtkGLGraph to be added; gapcmon_gtkglgraph.c and .h The X11 libs are also needed by the openGL graphics package. - gpanel_apcmon is now the only applet version available gapcmon (0.5.6-0) stable; urgency=normal * Fri Mar 10 2006 James Scott, Jr. - Modified gp_mon to be compiled with and without Gtk+Extra-2.1.1 installed. gpanel_apcmon.c collection has been removed from distribution as gp_mon is a more stable codeset. - GCONF is newly required for gp_mon to compile period. gapcmon (0.5.5-0) stable; urgency=normal ** RPM Release to gapcmon-0.5.5-0.i686.rpm to sourceforge Adding gp_mon an advanced panel applet with a histogram chart displaying a view of the last 400 collections. -- Mon Mar 6 2006 James Scott, Jr. gapcmon (0.5.4-7) stable; urgency=normal ** RPM Release to gapcmon-0.5.4-7.i686.rpm to sourceforge The last one for a while thru the sourceforge project gapcmon -- Tue Feb 14 2006 James Scott, Jr. gapcmon (0.0.7) stable; urgency=normal ** Created a gpanel_apcmon as a GNOME panel Applet ** Merged the codesets of gapcmon and gpanel_apcmon to produce one distribution: This one. -- Mon Feb 13 2006 James Scott, Jr. gapcmon (0.5.3) stable; urgency=normal ** Added Refresh Interval in the Config page to allow users to specify the number of seconds between data refreshes. ** Tweaked the label alignments in the Information page in an attempt to reduce the visual jitter during and data refresh ** Reworked the refresh button logic to reuse the intial timer routine. this garauntees that every button press will be honored even though the network thread may be busy collecting data. The refresh button now retries until successful. -- Tue Jan 31 2006 James Scott, Jr. gapcmon (0.5.2) stable; urgency=normal ** reworked the config file to remove GKeyFile dependancy. Switched to g_io_channel.. functions for configuration functions. -- Sun Jan 29 2006 James Scott, Jr. gapcmon (0.5.1) stable; urgency=urgent ** reworked the chart calc for remaining time to better represent ** tweaked alignment of labels on information page. ** fixed a bug in parse_args that would cause a hard loop if cmdline parms were supplied on program start. ** reworked configuration file routine to use g_key_file... -- Sat Jan 28 2006 James Scott, Jr. gapcmon (0.5.0) stable; urgency=normal ** Reworked configuration file to use g_key_file and g_io_channels ** All fopen and related io routines have been removed. -- Thur Jan 26 2006 James Scott, Jr. gapcmon (0.4.8) stable; urgency=normal ** Reworked network routines to be more portable. ** Now using the GnomeVFS module to handle socket programming functions ** Changed gtk flags in Makefile to add gnome-vfs-module-2.0 support. -- Wed Jan 25 2006 James Scott, Jr. gapcmon (0.4.7) stable; urgency=normal ** Reworked error messages from network routines ** pango_layout_set_markup() added to barchart to support pango markup. -- Fri Jan 20 2006 James Scott, Jr. gapcmon (0.4.6-0) stable; urgency=normal ** Cleanup thread support in timer routines ** Initial Public Release -- Thu Jan 19 2006 James Scott, Jr. gapcmon (0.5.3) stable; urgency=normal ** Added Refresh Interval in the Config page to allow users to specify the number of seconds between data refreshes. ** Tweaked the label alignments in the Information page in an attempt to reduce the visual jitter during and data refresh ** Reworked the refresh button logic to reuse the intial timer routine. this garauntees that every button press will be honored even though the network thread may be busy collecting data. The refresh button now retries until successful. -- Tue Jan 31 2006 James Scott, Jr. gapcmon (0.5.2) stable; urgency=normal ** reworked the config file to remove GKeyFile dependancy. Switched to g_io_channel.. functions for configuration functions. -- Sun Jan 29 2006 James Scott, Jr. gapcmon (0.5.1) stable; urgency=urgent ** reworked the chart calc for remaining time to better represent ** tweaked alignment of labels on information page. ** fixed a bug in parse_args that would cause a hard loop if cmdline parms were supplied on program start. ** reworked configuration file routine to use g_key_file... -- Sat Jan 28 2006 James Scott, Jr. gapcmon (0.5.0) stable; urgency=normal ** Reworked configuration file to use g_key_file and g_io_channels ** All fopen and related io routines have been removed. -- Thur Jan 26 2006 James Scott, Jr. gapcmon (0.4.8) stable; urgency=normal ** Reworked network routines to be more portable. ** Now using the GnomeVFS module to handle socket programming functions ** Changed gtk flags in Makefile to add gnome-vfs-module-2.0 support. -- Wed Jan 25 2006 James Scott, Jr. gapcmon (0.4.7) stable; urgency=normal ** Reworked error messages from network routines ** pango_layout_set_markup() added to barchart to support pango markup. -- Fri Jan 20 2006 James Scott, Jr. ** pango_layout_set_markup gapcmon (0.4.6-0) stable; urgency=normal ** Cleanup thread support in timer routines ** Initial Public Release -- Thu Jan 19 2006 James Scott, Jr. apcupsd-3.14.14/src/gapcmon/Makefile000066400000000000000000000032611274230402600172000ustar00rootroot00000000000000topdir:=../.. include $(topdir)/autoconf/targets.mak SRCS = $(wildcard *.c) # This bit of hackery is because gapcmon has its own CFLAGS and LIBS. # Plus it needs to be built with a C compiler while normally all apcupsd *.c # files are built with a C++ compiler. At some point we'll rename all *.c # files in the rest of the tree to *.cpp and some of this can then go away. CXX = $(CC) CPPFLAGS += $(GAPCMON_CFLAGS) -DICON_DIR=\"$(datadir)\" CXXFLAGS = $(CFLAGS) LIBS := $(GAPCMON_LIBS) $(X_LIBS) -lX11 -lXext $(LIBS) all-targets: gapcmon gapcmon: $(OBJS) $(LINK) all-install: install-gapcmon all-uninstall: uninstall-gapcmon install-gapcmon: $(call MKDIR,$(bindir)) $(call MKDIR,$(datadir)/pixmaps) $(call MKDIR,$(datadir)/applications) $(call INSTPROG,755,gapcmon,$(bindir)/gapcmon) $(call INSTDATA,755,gapcmon.desktop,$(datadir)/applications/gapcmon.desktop) $(call INSTDATA,744,apcupsd.png,$(datadir)/pixmaps/apcupsd.png) $(call INSTDATA,744,online.png,$(datadir)/pixmaps/online.png) $(call INSTDATA,744,onbatt.png,$(datadir)/pixmaps/onbatt.png) $(call INSTDATA,744,charging.png,$(datadir)/pixmaps/charging.png) $(call INSTDATA,744,unplugged.png,$(datadir)/pixmaps/unplugged.png) $(call INSTDATA,744,gapc_prefs.png,$(datadir)/pixmaps/gapc_prefs.png) uninstall-gapcmon: $(call UNINST,$(datadir)/pixmaps/apcupsd.png) $(call UNINST,$(datadir)/pixmaps/unplugged.png) $(call UNINST,$(datadir)/pixmaps/online.png) $(call UNINST,$(datadir)/pixmaps/onbatt.png) $(call UNINST,$(datadir)/pixmaps/charging.png) $(call UNINST,$(datadir)/applications/gapc_prefs.png) $(call UNINST,$(datadir)/applications/gapcmon.desktop) $(call UNINST,$(bindir)/gapcmon) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/gapcmon/README000066400000000000000000000125671274230402600164310ustar00rootroot00000000000000GAPCMON (a.k.a gapcmon, and gpanel_apcmon) A Gtk2/GLib2 GUI application used to monitor UPS devices controlled by the APCUPSD package. The program uses the NIS interface from apcupsd to collect event and status information for display to the end-user. Because of this great (NIS) interface, this program can be executed on any OS supported machine and use the network socket interface to connect back to apcupsd. Of course apcupsd must be compiled with NIS support (i.e. ./configure --enable-nis ). One program is included for your use in this package; gapcmon is a regular gtk+ application. FEATURES: * FreeDesktop.org Spec for Notification Area Icons. * Unlimited support for multiple UPSs. * Historical Graph of five data points are charted. A total of 40 points are maintained on the graph. The data points are LINEV, BATTV, BCHARGE, LOADPCT, and TIMELEFT. * Clicking an notification icon will cause the information window for that monitor to become visible or be hidden, if its already visible. * Monitor tooltips are available when hovering the mouse over the icon, and contain a quick summary of the ups status. * Icons are dynamically added or removed when enabled in preferences. * Icon changes to reflect the operational condition of the UPS. - where state is (online, onbattery, charging, not communicating, no cable) * right click popup menu with "JumpTo" window and "Quit" window menu choices. * Chart support popup tooltip for data point under the mouse pointer, showing dataseries name, color, time, and value. * Configuration of the tcpi/ip hostname, tcp port number, and whether that monitor is current enabled is provided via a central Preferences page. * background thread for all network io to keep user interface responsive. { the monitor information window } * notebook layout with four tabs: - History * Historical Line Graph tracking VAC, battery charge, batt voltage, ups load, and time remaining. Data collection for this chart is ten times the regular refresh time in seconds, and displays 40 collection cycles on screen. - Information * more detailed view of apcupsd current state and ups current state - Events * current apcupsd events as reported by apcaccess - Status * current apcupsd status as reported by apcaccess - refresh button, and quit button: * refresh button causes and immediate refresh of all data values * quit button closes the application, or hides the window for monitors { the monitor information window } * notebook layout with four tabs: - Active Monitors List * Status icon, state text, brief summary of active UPS monitor. - Preferences * configuration page allows user to specify the hostname, port, and refresh interval in seconds of the server/workstation running apcupsd with NIS configured. - Graph Properties * Alloww user to choose the color of each data series used in the History graph on monitor windows. - Glossary * Quick help text - About * Program version and information panel REQUIREMENTS: Gtk2/Glib-2.4 runtime support. APCUPSD installed and configured to NIS support. { get at http://apcupsd.sourceforge.net } * the following packages may need to be installed to build program and for runtime of binaries on some platforms. gapcmon {gtk version 2.4 is minimum package level required} glib-devel gtk-devel gconf2 DISTRIBUTION METHOD: Source RPM gapcmon-{version}-{release}.src.rpm Binary RPM gapcmon-{version}-{release}.i686.rpm Source tar gapcmon-{version}.tar.bz2 Debian Package gapcmon-{version}.deb (sometimes available) INSTALL INFO: Configure Source with for gapcmon : '# ./configure --prefix=/usr ' Then compile with 'make clean all', then 'sudo make install' Binary RPM install with this command 'rpm -ivh gapcmon-{version}-{release}.i686.rpm' Both methods result in '/usr/bin/gapcmon' being installed according to your system defaults for prefix. Note: the configure step requires the parm 'prefix=/usr'. INSTRUCTIONS: gapcmon -- Gtk Application 1. look in gnome menus for the "Applications" group, then select "APCUPSD monitor" - or enter '# gapcmon' on the command line. 2. To configure. - select preferences choice, - enter hostname and port, choose refresh interval in seconds. - be sure to click or unclick enable to activate the selection. KNOWN BUGS: NONE: ... MAILING LIST: http://sourceforge.net/projects/apcupsd, choose the 'users mailing list' apcupsd-users-request@lists.sourceforge.net http://sourceforge.net/projects/gapcmon, choose the 'Help Forum' WEB SITE: http://www.apcupsd.com/ or http://gapcmon.sourceforge.net/ CVS CHECKOUT: See sourceforge.net project page for cvs info and checkout module "gapcmon" REPORTING BUGS: Please report bugs and feature requests to "James Scott Jr" or use the HELP Forums on SourceForge for this project. I also respond to apcupsd-users-request@lists.sourceforge.net, list. ACKNOWLEDGMENTS & CONTRIBUTORS Thanks goes to project team creating and maintaining APCUPSD. Thanks is also due to Wesley Terrell for maintaining the Debian packages. Thanks to Jason Hale for maintaining the FreeBSD packages and two key patches; transparency support of KDE for systray icons, and sockaddr_in include guidance. apcupsd-3.14.14/src/gapcmon/apcupsd.png000066400000000000000000000011371274230402600177050ustar00rootroot00000000000000PNG  IHDR szzbKGDtIME; IDATXV0=TDF"$J>Ad$cK&̼y0ɽsnظok9$d99s3zZ{QUגZ0(v>@JRJ!P5B'clZB ca@4C^RMR[1>2b KZkc|J]RO4uB$c;Z2YP),ןl%o7j^iz%Zɐ+vb >>ڶ.. |!a2s$yzYGfԝ/)h;W@p+ XpAkN N$7Qn$X>w˛rWAddtҋo0{ZGlIX[vq~NBTIENDB`apcupsd-3.14.14/src/gapcmon/eggtrayicon.c000066400000000000000000000327111274230402600202210ustar00rootroot00000000000000 /* eggtrayicon.c serial-0085-0 *************************************** * Copyright (C) 2002 Anders Carlsson * * Modified by James Scott, Jr * - To enhance events and size management 4/2006 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1335, USA. */ #include #include #include #include #include #if defined (GDK_WINDOWING_WIN32) #include #endif #include "eggtrayicon.h" #define _(x) x #define N_(x) x #define SYSTEM_TRAY_REQUEST_DOCK 0 #define SYSTEM_TRAY_BEGIN_MESSAGE 1 #define SYSTEM_TRAY_CANCEL_MESSAGE 2 #define SYSTEM_TRAY_ORIENTATION_HORZ 0 #define SYSTEM_TRAY_ORIENTATION_VERT 1 enum { PROP_0, PROP_ORIENTATION }; static GtkPlugClass *parent_class = NULL; static void egg_tray_icon_init(EggTrayIcon * icon); static void egg_tray_icon_class_init(EggTrayIconClass * klass); static void egg_tray_icon_get_property(GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); static void egg_tray_icon_realize(GtkWidget * widget); static void egg_tray_icon_unrealize(GtkWidget * widget); static void egg_tray_icon_add (GtkContainer *container, GtkWidget *widget); static void egg_tray_icon_update_manager_window(EggTrayIcon * icon, gboolean dock_if_realized); static void egg_tray_icon_manager_window_destroyed(EggTrayIcon * icon); GType egg_tray_icon_get_type(void) { static GType our_type = 0; if (our_type == 0) { static const GTypeInfo our_info = { sizeof(EggTrayIconClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) egg_tray_icon_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof(EggTrayIcon), 0, /* n_preallocs */ (GInstanceInitFunc) egg_tray_icon_init }; our_type = g_type_register_static(GTK_TYPE_PLUG, "EggTrayIcon", &our_info, 0); } return our_type; } static void egg_tray_icon_init(EggTrayIcon * icon) { icon->stamp = 1; icon->orientation = GTK_ORIENTATION_HORIZONTAL; gtk_widget_add_events(GTK_WIDGET(icon), GDK_PROPERTY_CHANGE_MASK | GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK); } static void egg_tray_icon_class_init(EggTrayIconClass * klass) { GObjectClass *gobject_class = (GObjectClass *) klass; GtkWidgetClass *widget_class = (GtkWidgetClass *) klass; GtkContainerClass *container_class = (GtkContainerClass *)klass; parent_class = g_type_class_peek_parent(klass); gobject_class->get_property = egg_tray_icon_get_property; widget_class->realize = egg_tray_icon_realize; widget_class->unrealize = egg_tray_icon_unrealize; container_class->add = egg_tray_icon_add; g_object_class_install_property(gobject_class, PROP_ORIENTATION, g_param_spec_enum("orientation", "Orientation", "The orientation of the tray.", GTK_TYPE_ORIENTATION, GTK_ORIENTATION_HORIZONTAL, G_PARAM_READABLE)); #if defined (GDK_WINDOWING_WIN32) g_warning("Port eggtrayicon to Win32"); #endif } static void egg_tray_icon_get_property(GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { EggTrayIcon *icon = EGG_TRAY_ICON(object); switch (prop_id) { case PROP_ORIENTATION: g_value_set_enum(value, icon->orientation); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void egg_tray_icon_get_orientation_property(EggTrayIcon * icon) { Display *xdisplay; Atom type; int format; union { gulong *prop; guchar *prop_ch; } prop = { NULL}; gulong nitems; gulong bytes_after; int error, result; g_assert(icon->manager_window != None); xdisplay = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(GTK_WIDGET(icon))); gdk_error_trap_push(); type = None; result = XGetWindowProperty(xdisplay, icon->manager_window, icon->orientation_atom, 0, G_MAXLONG, FALSE, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &(prop.prop_ch)); error = gdk_error_trap_pop(); if (error || result != Success) return; if (type == XA_CARDINAL) { GtkOrientation orientation; orientation = (prop.prop[0] == SYSTEM_TRAY_ORIENTATION_HORZ) ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL; if (icon->orientation != orientation) { icon->orientation = orientation; g_object_notify(G_OBJECT(icon), "orientation"); } } if (prop.prop) XFree(prop.prop); } static GdkFilterReturn egg_tray_icon_manager_filter(GdkXEvent * xevent, GdkEvent * event, gpointer user_data) { EggTrayIcon *icon = user_data; XEvent *xev = (XEvent *) xevent; if (xev->xany.type == ClientMessage && xev->xclient.message_type == icon->manager_atom && xev->xclient.data.l[1] == icon->selection_atom) { egg_tray_icon_update_manager_window(icon, TRUE); } else if (xev->xany.window == icon->manager_window) { if (xev->xany.type == PropertyNotify && xev->xproperty.atom == icon->orientation_atom) { egg_tray_icon_get_orientation_property(icon); } if (xev->xany.type == DestroyNotify) { egg_tray_icon_manager_window_destroyed(icon); } } return GDK_FILTER_CONTINUE; } static void egg_tray_icon_unrealize(GtkWidget * widget) { EggTrayIcon *icon = EGG_TRAY_ICON(widget); GdkWindow *root_window; if (icon->manager_window != None) { GdkWindow *gdkwin; gdkwin = gdk_window_lookup_for_display(gtk_widget_get_display(widget), icon->manager_window); gdk_window_remove_filter(gdkwin, egg_tray_icon_manager_filter, icon); } root_window = gdk_screen_get_root_window(gtk_widget_get_screen(widget)); gdk_window_remove_filter(root_window, egg_tray_icon_manager_filter, icon); if (GTK_WIDGET_CLASS(parent_class)->unrealize) (*GTK_WIDGET_CLASS(parent_class)->unrealize) (widget); } static void egg_tray_icon_send_manager_message(EggTrayIcon * icon, long message, Window window, long data1, long data2, long data3) { XClientMessageEvent ev; Display *display; ev.type = ClientMessage; ev.window = window; ev.message_type = icon->system_tray_opcode_atom; ev.format = 32; ev.data.l[0] = gdk_x11_get_server_time(GTK_WIDGET(icon)->window); ev.data.l[1] = message; ev.data.l[2] = data1; ev.data.l[3] = data2; ev.data.l[4] = data3; display = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(GTK_WIDGET(icon))); gdk_error_trap_push(); XSendEvent(display, icon->manager_window, False, NoEventMask, (XEvent *) & ev); XSync(display, False); gdk_error_trap_pop(); } static void egg_tray_icon_send_dock_request(EggTrayIcon * icon) { egg_tray_icon_send_manager_message(icon, SYSTEM_TRAY_REQUEST_DOCK, icon->manager_window, gtk_plug_get_id(GTK_PLUG(icon)), 0, 0); } static void egg_tray_icon_update_manager_window(EggTrayIcon * icon, gboolean dock_if_realized) { Display *xdisplay; if (icon->manager_window != None) return; xdisplay = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(GTK_WIDGET(icon))); XGrabServer(xdisplay); icon->manager_window = XGetSelectionOwner(xdisplay, icon->selection_atom); if (icon->manager_window != None) XSelectInput(xdisplay, icon->manager_window, StructureNotifyMask | PropertyChangeMask); XUngrabServer(xdisplay); XFlush(xdisplay); if (icon->manager_window != None) { GdkWindow *gdkwin; gdkwin = gdk_window_lookup_for_display(gtk_widget_get_display(GTK_WIDGET(icon)), icon->manager_window); gdk_window_add_filter(gdkwin, egg_tray_icon_manager_filter, icon); if (dock_if_realized && GTK_WIDGET_REALIZED(icon)) egg_tray_icon_send_dock_request(icon); egg_tray_icon_get_orientation_property(icon); } } static gboolean transparent_expose_event (GtkWidget *widget, GdkEventExpose *event, gpointer user_data) { gdk_window_clear_area (widget->window, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } static void make_transparent_again (GtkWidget *widget, GtkStyle *previous_style, gpointer user_data) { gdk_window_set_back_pixmap (widget->window, NULL, TRUE); } static void make_transparent (GtkWidget *widget, gpointer user_data) { if (GTK_WIDGET_NO_WINDOW (widget) || GTK_WIDGET_APP_PAINTABLE (widget)) return; gtk_widget_set_app_paintable (widget, TRUE); gtk_widget_set_double_buffered (widget, FALSE); gdk_window_set_back_pixmap (widget->window, NULL, TRUE); g_signal_connect (widget, "expose_event", G_CALLBACK (transparent_expose_event), NULL); g_signal_connect_after (widget, "style_set", G_CALLBACK (make_transparent_again), NULL); } static void egg_tray_icon_manager_window_destroyed(EggTrayIcon * icon) { GdkWindow *gdkwin; g_return_if_fail(icon->manager_window != None); gdkwin = gdk_window_lookup_for_display(gtk_widget_get_display(GTK_WIDGET(icon)), icon->manager_window); gdk_window_remove_filter(gdkwin, egg_tray_icon_manager_filter, icon); icon->manager_window = None; egg_tray_icon_update_manager_window(icon, TRUE); } static void egg_tray_icon_realize(GtkWidget * widget) { EggTrayIcon *icon = EGG_TRAY_ICON(widget); GdkScreen *screen; GdkDisplay *display; Display *xdisplay; char buffer[256]; GdkWindow *root_window; if (GTK_WIDGET_CLASS(parent_class)->realize) GTK_WIDGET_CLASS(parent_class)->realize(widget); make_transparent (widget, NULL); screen = gtk_widget_get_screen(widget); display = gdk_screen_get_display(screen); xdisplay = gdk_x11_display_get_xdisplay(display); /* Now see if there's a manager window around */ g_snprintf(buffer, sizeof(buffer), "_NET_SYSTEM_TRAY_S%d", gdk_screen_get_number(screen)); icon->selection_atom = XInternAtom(xdisplay, buffer, False); icon->manager_atom = XInternAtom(xdisplay, "MANAGER", False); icon->system_tray_opcode_atom = XInternAtom(xdisplay, "_NET_SYSTEM_TRAY_OPCODE", False); icon->orientation_atom = XInternAtom(xdisplay, "_NET_SYSTEM_TRAY_ORIENTATION", False); egg_tray_icon_update_manager_window(icon, FALSE); egg_tray_icon_send_dock_request(icon); root_window = gdk_screen_get_root_window(screen); /* Add a root window filter so that we get changes on MANAGER */ gdk_window_add_filter(root_window, egg_tray_icon_manager_filter, icon); } static void egg_tray_icon_add (GtkContainer *container, GtkWidget *widget) { g_signal_connect (widget, "realize", G_CALLBACK (make_transparent), NULL); GTK_CONTAINER_CLASS (parent_class)->add (container, widget); } EggTrayIcon *egg_tray_icon_new_for_screen(GdkScreen * screen, const char *name) { g_return_val_if_fail(GDK_IS_SCREEN(screen), NULL); return g_object_new(EGG_TYPE_TRAY_ICON, "screen", screen, "title", name, NULL); } EggTrayIcon *egg_tray_icon_new(const gchar * name) { return g_object_new(EGG_TYPE_TRAY_ICON, "title", name, NULL); } guint egg_tray_icon_send_message(EggTrayIcon * icon, gint timeout, const gchar * message, gint len) { guint stamp; g_return_val_if_fail(EGG_IS_TRAY_ICON(icon), 0); g_return_val_if_fail(timeout >= 0, 0); g_return_val_if_fail(message != NULL, 0); if (icon->manager_window == None) return 0; if (len < 0) len = strlen(message); stamp = icon->stamp++; /* Get ready to send the message */ egg_tray_icon_send_manager_message(icon, SYSTEM_TRAY_BEGIN_MESSAGE, (Window) gtk_plug_get_id(GTK_PLUG(icon)), timeout, len, stamp); /* Now to send the actual message */ gdk_error_trap_push(); while (len > 0) { XClientMessageEvent ev; Display *xdisplay; xdisplay = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(GTK_WIDGET(icon))); ev.type = ClientMessage; ev.window = (Window) gtk_plug_get_id(GTK_PLUG(icon)); ev.format = 8; ev.message_type = XInternAtom(xdisplay, "_NET_SYSTEM_TRAY_MESSAGE_DATA", False); if (len > 20) { memcpy(&ev.data, message, 20); len -= 20; message += 20; } else { memcpy(&ev.data, message, len); len = 0; } XSendEvent(xdisplay, icon->manager_window, False, StructureNotifyMask, (XEvent *) & ev); XSync(xdisplay, False); } gdk_error_trap_pop(); return stamp; } void egg_tray_icon_cancel_message(EggTrayIcon * icon, guint id) { g_return_if_fail(EGG_IS_TRAY_ICON(icon)); g_return_if_fail(id > 0); egg_tray_icon_send_manager_message(icon, SYSTEM_TRAY_CANCEL_MESSAGE, (Window) gtk_plug_get_id(GTK_PLUG(icon)), id, 0, 0); } GtkOrientation egg_tray_icon_get_orientation(EggTrayIcon * icon) { g_return_val_if_fail(EGG_IS_TRAY_ICON(icon), GTK_ORIENTATION_HORIZONTAL); return icon->orientation; } apcupsd-3.14.14/src/gapcmon/eggtrayicon.h000066400000000000000000000051611274230402600202250ustar00rootroot00000000000000 /* eggtrayicon.h serial-0085-0 *************************************** * Copyright (C) 2002 Anders Carlsson * * Modified by James Scott, Jr * - To enhance events and size management 4/2006 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1335, USA. */ #ifndef __EGG_TRAY_ICON_H__ #define __EGG_TRAY_ICON_H__ #include #include #ifdef G_OS_WIN32 #include #endif /* WINDOWS */ G_BEGIN_DECLS #define EGG_TYPE_TRAY_ICON (egg_tray_icon_get_type ()) #define EGG_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_TRAY_ICON, EggTrayIcon)) #define EGG_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_TRAY_ICON, EggTrayIconClass)) #define EGG_IS_TRAY_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_TRAY_ICON)) #define EGG_IS_TRAY_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_TRAY_ICON)) #define EGG_TRAY_ICON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_TRAY_ICON, EggTrayIconClass)) typedef struct _EggTrayIcon EggTrayIcon; typedef struct _EggTrayIconClass EggTrayIconClass; struct _EggTrayIcon { GtkPlug parent_instance; guint stamp; #ifdef GDK_WINDOWING_X11 Atom selection_atom; Atom manager_atom; Atom system_tray_opcode_atom; Atom orientation_atom; Window manager_window; #endif GtkOrientation orientation; }; struct _EggTrayIconClass { GtkPlugClass parent_class; }; GType egg_tray_icon_get_type(void); EggTrayIcon *egg_tray_icon_new_for_screen(GdkScreen * screen, const gchar * name); EggTrayIcon *egg_tray_icon_new(const gchar * name); guint egg_tray_icon_send_message(EggTrayIcon * icon, gint timeout, const char *message, gint len); void egg_tray_icon_cancel_message(EggTrayIcon * icon, guint id); GtkOrientation egg_tray_icon_get_orientation(EggTrayIcon * icon); G_END_DECLS #endif /* __EGG_TRAY_ICON_H__ */ apcupsd-3.14.14/src/gapcmon/gapc_prefs.png000066400000000000000000000127671274230402600203720ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|dIDATx{XUe?{o@ފ( $Jp0Ǔ𐎗LMkzL5gp'M;tLQOMXj^.V^|Q@W}k s<{}]J̜NY间ɕ *Nby=aڂ(D^_|Qdc孤j*h4fxٳgfNgg'(tRƌFDEJJJ8p(hx<=TyI=NG^W`U#@Y5" btKՎ# G} wA @{{;W^j 3w>, NPPJj5juT*t*Rt]mCNƸV/E %q8/`X裏Xd jFF!00ʬ~&5CR)VٹsgGQ mm/+ү#9s&555lٲŋ(T*5yOT*ػwokDnc5ۉ&hH&_x*?)/K\.Ʉ 0L=zMZqz2 UUUT*RSS? p:# >.V^9x1=x-+Vߴr $/YA0X,L&Ejj'&x F#Ob޼y~M"55ϣR/b 8l V9(((`ȑ,Yɔ& ȩۿ=B~l6H{{;]]]l6BBB#<<@_Q1 ̛7*yL`p}}}ŋCgggm+&&0f3Ce֬Y|g>Я0Mwz={0an7,[,d\گ6V@H-bh4j5N7RUU݄c2uaof͚jrr#@JL&#`y1a< Î;xعsg-[BrG;b-[`6H ! >-55~l`0駟'zyCCC> >iކ8A@ _#;w?r>̅ hkkpB~~Brʢ -8{,'NJN:僷O'X_{CRQIh;SreY~! .TX, A`x<׺ B68 Y[uVƏOBB{/>B?Lhh(FQ_WW~Eqqq)v{Y@-R[9s [$~x(k <6 ͦXrr#F/Wrsz4i~Ν̙3G~/~TTTQ[[ǬG~ϿLˤy8tquHUv9~߰j*,  " pvލ^X>{Lvf֢͊jp_oLy'N,4iɓ'OII k "쫛 Q.d_Q[YYɓO>jUǾ}N[V|'ٓ99ƶmHHHpHBPP55 sw!!!x?fYd_/̩deN4]:RF?|񔔔 8Nx @̟$TD "eg\picΜ9466^CFQ|Nmm-|WlذAV)))O ?@ҥK),,r)瞓I|?)f)'G\oR$(h7(ۀٕѢ(2e%&O:z~h`o20L8k=d \$8 %%%E!!##$F#NSx0?sM>[id"1|$%%)pUf͚%Hs]ϱcb|nnˀ- lNNuuuJjy7 1Z-z>g?Ór;4@cǎe+ż+Zz_ "99AݻSRrJJJ.FOYt:v}]lˆ#(((v_`ge׮]}w)'i5Z'Oٗ.]6L4I IIIPUUEyy9;:u NGbbb_Oo"xw5mn׭['߿_ܳgk.>G)@īW/^z! @e=^P'|"n߾]?!> q_wzmM8/ߔFHHNFP;TL O¹:G/M,Z^OMM gΜaҤI #x #<=m h&[IO7w\l6uuu466r)LmPJ}{Ha qvX6"7 /Lw|[܈܎<~ڵ[Q| nQc*kans[<#qAU@C"A3tA?o x3>@T?7A߹}uu5mmmdNQq`mcN m <"45u/t`܈ۥ9v/20HK`!)Z#*Br }.iaO`KpXI@pM6++˧;~x233-lo{3GaL8 |SKwvAX5Ko]ڴ(VXΐ |p86 رR˴ _*+.iRF%BH0TUJ b,XF)wX FGd2)!ɄJ|rr2VAKK a_1|wgH5PD $_m`BoCʾJ`JJJ8qMC&;HQ åg͵{g~,׋q@ܥ /jZ|J'6gf!~ cgKZ c`bG;deBs %)?Qz,f/X3f\ӨVALL #F _=|zxȚW$o cUJTj)g!9:: ͇o+h p\.fiQ'\t/vDGG5W+Q^Y j[a$PHfq$ Ѐ*!)QznB}l~)kƏ\/ Ԥ_f]Nhh(dee1|%$V+iiiW|2AQW apsl3C;⌼"$ h1<dL]#uرcN{/- ⥗^կF 2Dnpo+QE@ !uv&#t 1jSD*Q#E˗`p4 [rB`Ry9rHMR ,<|7J!m PSC`^zv R†%ʰ7Mӧ9vXob~;6ѥEFrW%CA DFCn6l_QκYNL&z| ZE'`D]߶¶3NNhHw C6(CnEr Apx%R pF'K``RC|xI a+[f FC9>(Dtyl"n"+OP_ Kۚn†Jtu\ dnap=h"iJ~;NqIH,|ARHT1(b Zõxh4^/,wiN6CH~as<<xඊp`w  ulO 7 Jnzr7=7MMMbSS,677;wG̨z+-Ң νt!*~pjͥ!.YX>b#.t:6E21%%E|w;vjժE`75awtݡbZc8 FeA}\b@e~]cuTfNUmE nbn$O1W>]OS^wxL)IENDB`apcupsd-3.14.14/src/gapcmon/gapcmon.c000066400000000000000000006417101274230402600173370ustar00rootroot00000000000000/* gapcmon.c serial-0088-0 ***************************************** GKT+ GUI with Notification Area (System Tray) support. Program for monitoring the apcupsd.sourceforge.net package. Copyright (C) 2006 James Scott, Jr. Command Line Syntax: gapcmon [--help] 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* ************************************************************************** * * Program Structure * ------------------------ ------------------------------------------------- * GtkWindow Main Control Program Thread ---- * EggTrayIcon Notification system tray icon for main app. * * GtkNotebook Main Interface * * GtkTreeView Monitors pg: list of active monitors and state * - EggTrayIcon Notification system tray icon for monitors. * - GtkWindow Monitor Information Window - * TrayIcon and InfoWindow compose a monitor * * PG-n GtkNotebook Active monitor notebook with four pages; * summary chart, detailed, eventlog, statuslog pages. * - nbPage HISTORY A lg_Graph histogram line chart of * LINEV, LOADPCT, BCHARGE, CUMONBATT, TIMELEFT * g_timeout_add Monitor g_timeout per monitor for data updates * g_timeout_add Monitor g_timeout per graph 1:30 collection updates * - nbPage DETAILS Grouped results from the status output. * - nbPage EVENTS Current events log * - nbPage STATUS Current status log, same as APCACCESS * * GtkTreeView Preferences pg: For Main app, and Monitors * * GtkVBox About pg: Program copyright info * * GtkHBox Action info * - GtkLabel Program Title line * - GtkButton Program Close button * * GtkStatusbar Status message line * * ------------------------ --------------------------------------------------- * + GConfClient Tied to Preferences page * Produces direct change on application state and * operation by monitoring changes to config values * ------------------------ --------------------------------------------------- * + GThread Network Communication via socket io using GIOChannels * Communication to interface gtkthread through * a GAsyncQueue, with additional instance mutex * - protect hash table from multi-thread access * - protect GTK from multi-thread access * gdk_thread_[enter|leave] around gtk calls in timer * routines and threads - and gtk_main_loop. * ------------------------ --------------------------------------------------- * GCONF2 Info * CURRENT KEYS ARE: * key /schemas/apps/gapcmon/controller/keys * /apps/gapcmon/monitor/x/monitor-keys * Where x is the internal monitor number. * max monitors=unlimted or sizeof guint * Where key is the actual keyname like enabled, host_name, port_name, or * refresh_interval, etc. * ************************************************************************** * */ #include /* close() */ #include /* socket() */ #include /* socket() */ #include /* sockaddr_in */ #include /* ntohs() */ #include /* sockaddr_in */ #include /* gethostbyname() */ #include #include /* memset() */ #include #include /* malloc() */ #include #include #include "eggtrayicon.h" #include "gapcmon.h" static gboolean cb_monitor_dedicated_one_time_refresh(PGAPC_MONITOR pm); static gboolean cb_monitor_automatic_refresh(PGAPC_MONITOR pm); static gboolean cb_monitor_refresh_control(PGAPC_MONITOR pm); static gboolean gapc_monitor_update_tooltip_msg(PGAPC_MONITOR pm); static gint gapc_monitor_update(PGAPC_MONITOR pm); static gdouble gapc_util_point_filter_set(PGAPC_SUMS sq, gdouble this_point); static gdouble gapc_util_point_filter_reset(PGAPC_SUMS sq); static void lg_graph_set_chart_title (PLGRAPH plg, gchar * pch_text); static void lg_graph_set_y_label_text (PLGRAPH plg, gchar * pch_text); static void lg_graph_set_x_label_text (PLGRAPH plg, gchar * pch_text); static void lg_graph_set_chart_title_color (PLGRAPH plg, gchar * pch_color); static void lg_graph_set_chart_scales_color (PLGRAPH plg, gchar * pch_color); static void lg_graph_set_chart_window_fg_color (PLGRAPH plg, gchar * pch_color); static void lg_graph_set_chart_window_bg_color (PLGRAPH plg, gchar * pch_color); static PLGRAPH lg_graph_create (GtkWidget * box, gint width, gint height); static void lg_graph_set_ranges (PLGRAPH plg, gint xminor_by, gint xmajor_by, gint x_min, gint x_max, gint yminor_by, gint ymajor_by, gint y_min, gint y_max); static void lg_graph_redraw (PLGRAPH plg); static gint lg_graph_data_series_add (PLGRAPH plg, gchar * pch_legend_text, gchar * pch_color_text); static gboolean lg_graph_data_series_remove_all (PLGRAPH plg); static gboolean lg_graph_data_series_add_value (PLGRAPH plg, gint i_series_number, gdouble y_value); static gint lg_graph_data_series_draw (PLGRAPH plg, PLG_SERIES psd); /* * Private Interfaces */ static gint lg_graph_draw_tooltip (PLGRAPH plg); static gint lg_graph_data_series_draw_all (PLGRAPH plg, gboolean redraw_control); static void lg_graph_get_default_sizes (PLGRAPH plg, gint * width, gint * height); static void lg_graph_draw_x_grid_labels (PLGRAPH plg); static void lg_graph_draw_y_grid_labels (PLGRAPH plg); static gint lg_graph_draw_grid_lines (PLGRAPH plg); static gint lg_graph_draw_horizontal_text (PLGRAPH plg, gchar * pch_text, GdkRectangle * rect, gboolean redraw_control); static gint lg_graph_draw_vertical_text (PLGRAPH plg, gchar * pch_text, GdkRectangle * rect, gboolean redraw_control); static gint lg_graph_draw (PLGRAPH plg); static gint lg_graph_configure_event_cb (GtkWidget * widget, GdkEventConfigure * event, PLGRAPH plg); static gint lg_graph_expose_event_cb (GtkWidget * widget, GdkEventExpose * event, PLGRAPH plg); static gboolean lg_graph_motion_notify_event_cb (GtkWidget * widget, GdkEventMotion * ev, PLGRAPH plg); static gboolean lg_graph_button_press_event_cb (GtkWidget * widget, GdkEventButton * ev, PLGRAPH plg); static gboolean cb_util_barchart_handle_exposed(GtkWidget * widget, GdkEventExpose * event, gpointer data); static gboolean cb_util_line_chart_refresh(PGAPC_HISTORY pg); static gboolean cb_util_manage_iconify_event(GtkWidget *widget, GdkEventWindowState *event, gpointer gp); static void gapc_util_text_view_append(GtkWidget * view, gchar * pch); static void gapc_util_text_view_prepend(GtkWidget * view, gchar * pch); static gboolean gapc_util_text_view_clear_buffer(GtkWidget * view); static gboolean gapc_util_treeview_get_iter_from_monitor(GtkTreeModel * model, GtkTreeIter * iter, gint i_value); static gint gapc_util_update_hashtable(PGAPC_MONITOR pm, gchar * pch_unparsed); static void cb_panel_systray_icon_destroy(GtkObject * object, gpointer gp); static void cb_main_interface_button_quit(GtkWidget * button, PGAPC_CONFIG pcfg); static void gapc_monitor_interface_destroy(PGAPC_CONFIG pcfg, gint i_monitor); static GtkWidget *gapc_monitor_interface_create(PGAPC_CONFIG pcfg, gint i_monitor, GtkTreeIter * iter); static void cb_panel_monitor_list_activated(GtkTreeView * treeview, GtkTreePath * arg1, GtkTreeViewColumn * arg2, PGAPC_CONFIG pcfg); static gint gapc_panel_glossary_page(PGAPC_CONFIG pcfg, GtkWidget * notebook); static gint gapc_panel_graph_property_page(PGAPC_CONFIG pcfg, GtkWidget * notebook); /* * Common interface to the various versions of gethostbyname_r(). * Implemented in gethostname.c. */ struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen); /* * Some small number of globals are required */ static gboolean lg_graph_debug = FALSE; /* ************************************************************************* */ /* * Draws one data series points to chart * returns number of points processed */ static gint lg_graph_data_series_draw (PLGRAPH plg, PLG_SERIES psd) { gint v_index = 0; GdkPoint *point_pos = NULL; g_return_val_if_fail (plg != NULL, -1); g_return_val_if_fail (psd != NULL, -1); g_return_val_if_fail (psd->point_pos != NULL, -1); gdk_gc_set_rgb_fg_color (plg->series_gc, &psd->legend_color); gdk_gc_set_line_attributes (plg->series_gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_MITER); point_pos = psd->point_pos; /* trap first and only point */ if (psd->i_point_count == 0) { return 0; } if (psd->i_point_count == 1) { point_pos[0].x = plg->plot_box.x; point_pos[0].y = (plg->plot_box.y + plg->plot_box.height) - ((psd->lg_point_dvalue[0] * (gdouble) ((gdouble) plg->plot_box.height / (gdouble) plg->y_range.i_max_scale))); gdk_draw_arc (plg->pixmap, plg->series_gc, TRUE, point_pos[0].x - 1, point_pos[0].y - 2, 3, 3, 0, 360 * 64); return 1; } for (v_index = 0; v_index < psd->i_point_count; v_index++) { point_pos[v_index].x = plg->plot_box.x + (v_index * plg->x_range.i_minor_inc); point_pos[v_index].y = (plg->plot_box.y + plg->plot_box.height) - ((psd->lg_point_dvalue[v_index] * (gdouble) ((gdouble) plg->plot_box.height / (gdouble) plg->y_range.i_max_scale))); if ((v_index != 0) && (v_index < psd->i_point_count - 1)) { gdk_draw_arc (plg->pixmap, plg->series_gc, TRUE, point_pos[v_index].x - 1, point_pos[v_index].y - 2, 3, 3, 0, 360 * 64); gdk_draw_arc (plg->pixmap, plg->series_gc, FALSE, point_pos[v_index].x - 1, point_pos[v_index].y - 2, 3, 3, 0, 360 * 64); } } gdk_draw_lines (plg->pixmap, plg->series_gc, point_pos, psd->i_point_count); return v_index; } /* * Draws all data series points to chart * returns number of series processed, or -1 if not drawable */ static gint lg_graph_data_series_draw_all (PLGRAPH plg, gboolean redraw_control) { PLG_SERIES psd = NULL; GList *data_sets = NULL; gint v_index = 0; g_return_val_if_fail (plg != NULL, -1); if ( !(GTK_WIDGET_DRAWABLE (plg->drawing_area)) ) { return -1; } data_sets = g_list_first (plg->lg_series); while (data_sets) { psd = data_sets->data; if (psd != NULL) { /* found */ lg_graph_data_series_draw (plg, psd); v_index++; } data_sets = g_list_next (data_sets); } if (lg_graph_debug) { g_print ("DrawAllDataSeries: series=%d\n", v_index); } return v_index; } /* * Add a single value to the requested data series * auto indexes the value is max is reach (appends to the end) */ static gboolean lg_graph_data_series_add_value (PLGRAPH plg, gint i_series_number, gdouble y_value) { PLG_SERIES psd = NULL; GList *data_sets = NULL; gint v_index = 0, time_count = 0; gboolean b_found = FALSE; g_return_val_if_fail (plg != NULL, FALSE); data_sets = g_list_first (plg->lg_series); while (data_sets) { psd = data_sets->data; if (psd->i_series_id == i_series_number) { /* found */ b_found = TRUE; break; } data_sets = g_list_next (data_sets); } if (!b_found) { g_message ("lg_graph_data_series_add_value(%d): Invalid data series number", i_series_number); return FALSE; } if (y_value >= plg->y_range.i_max_scale) { y_value = (gdouble) plg->y_range.i_max_scale * 0.98; } if (psd->i_point_count == psd->i_max_points + 1) { for (v_index = 0; v_index < psd->i_max_points; v_index++) { psd->lg_point_dvalue[v_index] = psd->lg_point_dvalue[v_index + 1]; } psd->lg_point_dvalue[psd->i_max_points] = y_value; } else { psd->lg_point_dvalue[psd->i_point_count++] = y_value; } psd->d_max_value = MAX (y_value, psd->d_max_value); psd->d_min_value = MIN (y_value, psd->d_min_value); plg->i_points_available = MAX (plg->i_points_available, psd->i_point_count); /* record current time with data points */ if (psd->i_series_id == plg->i_num_series - 1) { GList *gl_remove = NULL; gl_remove = g_list_first (plg->lg_series_time); time_count = g_list_length (plg->lg_series_time); if (time_count == psd->i_max_points + 1) { plg->lg_series_time = g_list_remove_all (plg->lg_series_time, gl_remove->data); } plg->lg_series_time = g_list_append (plg->lg_series_time, GINT_TO_POINTER ((time_t) time (NULL))); } if (lg_graph_debug) { g_print ("DataSeriesAddValue: series=%d, value=%3.1f, index=%d, count=%d, time_count=%d, max_pts=%d\n", i_series_number, y_value, v_index, psd->i_point_count, time_count, psd->i_max_points); } return TRUE; } /* * A shutdown routine * destroys all the data series and any assocaited dynamic data */ static gboolean lg_graph_data_series_remove_all (PLGRAPH plg) { PLG_SERIES psd = NULL; GList *data_sets = NULL; gint i_count = 0; g_return_val_if_fail (plg != NULL, FALSE); data_sets = g_list_first (plg->lg_series); while (data_sets) { psd = data_sets->data; g_free (psd->lg_point_dvalue); g_free (psd->point_pos); g_free (psd); data_sets = g_list_next (data_sets); i_count++; } g_list_free (plg->lg_series); g_list_free (plg->lg_series_time); plg->lg_series = NULL; plg->lg_series_time = NULL; plg->i_num_series = 0; plg->i_points_available = 0; if (lg_graph_debug) { g_print ("DataSeriesRemoveAll: series total=%d\n", i_count); } return TRUE; } /* * allocates space for another data series * returns the series number of this dataset */ static gint lg_graph_data_series_add (PLGRAPH plg, gchar * pch_legend_text, gchar * pch_color_text) { PLG_SERIES psd = NULL; g_return_val_if_fail (plg != NULL, -1); g_return_val_if_fail (pch_legend_text != NULL, -1); g_return_val_if_fail (pch_color_text != NULL, -1); psd = (PLG_SERIES) g_new0 (LG_SERIES, 1); g_return_val_if_fail (psd != NULL, -1); psd->lg_point_dvalue = (gdouble *) g_new0 (gdouble, (plg->x_range.i_max_scale + 4)); g_return_val_if_fail (psd->lg_point_dvalue != NULL, -1); psd->point_pos = g_new0 (GdkPoint, (plg->x_range.i_max_scale + 4)); g_return_val_if_fail (psd->point_pos != NULL, -1); g_snprintf (psd->ch_legend_text, sizeof (psd->ch_legend_text), "%s", pch_legend_text); psd->i_max_points = plg->x_range.i_max_scale; gdk_color_parse (pch_color_text, &psd->legend_color); g_snprintf (psd->ch_legend_color, sizeof (psd->ch_legend_color), "%s", pch_color_text); psd->cb_id = CB_SERIES_ID; plg->lg_series = g_list_append (plg->lg_series, psd); psd->i_series_id = plg->i_num_series++; if (lg_graph_debug) { g_print ("DataSeriesAdd: series=%d, max_pts=%d\n", psd->i_series_id, psd->i_max_points); } return psd->i_series_id; } /* * Set the bottom x label text */ static void lg_graph_set_x_label_text (PLGRAPH plg, gchar * pch_text) { g_return_if_fail (plg != NULL); if (plg->x_label_text != NULL) { g_free (plg->x_label_text); } plg->x_label_text = g_strdup (pch_text); } static void lg_graph_set_y_label_text (PLGRAPH plg, gchar * pch_text) { g_return_if_fail (plg != NULL); if (plg->y_label_text != NULL) { g_free (plg->y_label_text); } plg->y_label_text = g_strdup (pch_text); } static void lg_graph_set_chart_title (PLGRAPH plg, gchar * pch_text) { g_return_if_fail (plg != NULL); if (plg->x_title_text != NULL) { g_free (plg->x_title_text); } plg->x_title_text = g_strdup (pch_text); } static void lg_graph_set_chart_window_bg_color (PLGRAPH plg, gchar * pch_color) { g_return_if_fail (plg != NULL); g_snprintf (plg->ch_color_window_bg, sizeof (plg->ch_color_window_bg), "%s", pch_color); } static void lg_graph_set_chart_window_fg_color (PLGRAPH plg, gchar * pch_color) { g_return_if_fail (plg != NULL); g_snprintf (plg->ch_color_chart_bg, sizeof (plg->ch_color_chart_bg), "%s", pch_color); } static void lg_graph_set_chart_scales_color (PLGRAPH plg, gchar * pch_color) { g_return_if_fail (plg != NULL); g_snprintf (plg->ch_color_scale_fg, sizeof (plg->ch_color_scale_fg), "%s", pch_color); } static void lg_graph_set_chart_title_color (PLGRAPH plg, gchar * pch_color) { g_return_if_fail (plg != NULL); g_snprintf (plg->ch_color_title_fg, sizeof (plg->ch_color_title_fg), "%s", pch_color); } static void lg_graph_redraw (PLGRAPH plg) { GdkRectangle update_rect; GdkRegion *region = NULL; g_return_if_fail (plg != NULL); update_rect.x = 0; update_rect.y = 0; update_rect.width = plg->drawing_area->allocation.width; update_rect.height = plg->drawing_area->allocation.height; /* --- And then draw it (calls expose event) --- */ region = gdk_region_rectangle (&update_rect); gdk_window_invalidate_region (plg->drawing_area->window, region, FALSE); gdk_region_destroy (region); } /* * Toggle the legend function on off * "button-press-event" */ static gboolean lg_graph_button_press_event_cb (GtkWidget * widget, GdkEventButton * ev, PLGRAPH plg) { g_return_val_if_fail (plg != NULL, FALSE); if ((ev->type & GDK_BUTTON_PRESS) && (ev->button == 1)) { plg->b_tooltip_active = plg->b_tooltip_active ? FALSE : TRUE; lg_graph_redraw (plg); return TRUE; } if ((ev->type & GDK_BUTTON_PRESS) && (ev->button == 2) && plg->b_mouse_onoff) { lg_graph_debug = lg_graph_debug ? FALSE : TRUE; return TRUE; } if ((ev->type & GDK_BUTTON_PRESS) && (ev->button == 3)) { plg->b_mouse_onoff = plg->b_mouse_onoff ? FALSE : TRUE; return TRUE; } return FALSE; } /* * Track the mouse pointer position * "motion-notify-event" */ static gboolean lg_graph_motion_notify_event_cb (GtkWidget * widget, GdkEventMotion * ev, PLGRAPH plg) { GdkModifierType state; gint x = 0, y = 0; g_return_val_if_fail (plg != NULL, FALSE); if (ev->is_hint) { gdk_window_get_pointer (ev->window, &x, &y, &state); } else { x = ev->x; y = ev->y; state = ev->state; } plg->mouse_pos.x = x; plg->mouse_pos.y = y; plg->mouse_state = state; if ( lg_graph_draw_tooltip (plg) ) { lg_graph_redraw (plg); } if (lg_graph_debug) { g_print ("mouse is at x=%d, y=%d, with a state of %d\n", x, y, state); } return FALSE; } /* * Draw the chart x scale legend */ static void lg_graph_draw_x_grid_labels (PLGRAPH plg) { gchar ch_grid_label[GAPC_MAX_BUFFER]; gchar ch_work[GAPC_MAX_BUFFER]; PangoLayout *layout = NULL; PangoTabArray *p_tabs = NULL; gint x_adj = 0, x1_adj = 0, width = 0, height = 0, h_index = 0, x_scale = 0; g_return_if_fail (plg != NULL); g_snprintf (ch_grid_label, GAPC_MAX_BUFFER, "%d", plg->x_range.i_max_scale); layout = gtk_widget_create_pango_layout (plg->drawing_area, ch_grid_label); pango_layout_set_markup (layout, ch_grid_label, -1); pango_layout_get_pixel_size (layout, &width, &height); x_adj = width / 2; x1_adj = width / 4; g_snprintf (ch_grid_label, GAPC_MAX_BUFFER, "%s", "0"); for (h_index = plg->x_range.i_inc_major_scale_by; h_index <= plg->x_range.i_max_scale; h_index += plg->x_range.i_inc_major_scale_by) { g_strlcpy (ch_work, ch_grid_label, GAPC_MAX_BUFFER); g_snprintf (ch_grid_label, GAPC_MAX_BUFFER, "%s\t%d", ch_work, h_index); if (h_index < 10) { x_scale++; } } g_strlcpy (ch_work, ch_grid_label, GAPC_MAX_BUFFER); g_snprintf (ch_grid_label, GAPC_MAX_BUFFER, "%s", ch_work); pango_layout_set_markup (layout, ch_grid_label, -1); if (lg_graph_debug) { g_print ("(%d:%d:%d)x_Labels=[%s]\n", x_adj, x1_adj, x_scale, ch_grid_label); } p_tabs = pango_tab_array_new (plg->x_range.i_num_major, TRUE); for (h_index = 0; h_index <= plg->x_range.i_num_major; h_index++) { gint xbase = 0; if (h_index > x_scale) { xbase = (h_index * plg->x_range.i_major_inc); } else { xbase = (h_index * plg->x_range.i_major_inc) + x1_adj; } if (h_index == 0) { xbase = plg->x_range.i_major_inc + x1_adj; } pango_tab_array_set_tab (p_tabs, h_index, PANGO_TAB_LEFT, xbase); } pango_layout_set_tabs (layout, p_tabs); pango_layout_context_changed (layout); gdk_draw_layout (plg->pixmap, plg->scale_gc, plg->plot_box.x - x_adj, plg->plot_box.y + plg->plot_box.height, layout); pango_tab_array_free (p_tabs); g_object_unref (layout); return; } /* * Draw the chart y scale legend */ static void lg_graph_draw_y_grid_labels (PLGRAPH plg) { gchar ch_grid_label[GAPC_MAX_BUFFER]; gchar ch_work[GAPC_MAX_BUFFER]; PangoLayout *layout = NULL; gint y_adj = 0, width = 0, height = 0, v_index = 0; g_return_if_fail (plg != NULL); g_snprintf (ch_grid_label, GAPC_MAX_BUFFER, "%d", plg->y_range.i_max_scale); layout = gtk_widget_create_pango_layout (plg->drawing_area, ch_grid_label); pango_layout_set_markup (layout, ch_grid_label, -1); pango_layout_get_pixel_size (layout, &width, &height); y_adj = height / 2; g_snprintf (ch_grid_label, GAPC_MAX_BUFFER, "%d", plg->y_range.i_max_scale); for (v_index = plg->y_range.i_max_scale - plg->y_range.i_inc_major_scale_by; v_index > 0; v_index -= plg->y_range.i_inc_major_scale_by) { g_strlcpy (ch_work, ch_grid_label, GAPC_MAX_BUFFER); g_snprintf (ch_grid_label, GAPC_MAX_BUFFER, "%s\n%d", ch_work, v_index); } g_strlcpy (ch_work, ch_grid_label, GAPC_MAX_BUFFER); g_snprintf (ch_grid_label, GAPC_MAX_BUFFER, "%s", ch_work); pango_layout_set_spacing (layout, ((plg->y_range.i_major_inc - height) * PANGO_SCALE)); pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT); pango_layout_set_markup (layout, ch_grid_label, -1); if (lg_graph_debug) { g_print ("(%d:%d)y_Labels=[%s]\n", y_adj, plg->y_range.i_major_inc, ch_grid_label); } pango_layout_context_changed (layout); gdk_draw_layout (plg->pixmap, plg->scale_gc, plg->plot_box.x - (width * 1.2), plg->plot_box.y - y_adj, layout); g_object_unref (layout); return; } /* * Draws the minor and major grid lines inside the current plot_area * returns -1 on error, or TRUE; */ static gint lg_graph_draw_grid_lines (PLGRAPH plg) { GtkWidget *drawing_area = NULL; gint y_minor_inc = 0, y_pos = 0, y_index = 0; gint y_major_inc = 0; gint x_minor_inc = 0, x_pos = 0, x_index = 0; gint x_major_inc = 0; gint count_major = 0, count_minor = 0; GdkSegment *seg_minor = NULL; GdkSegment *seg_major = NULL; g_return_val_if_fail (plg != NULL, -1); g_return_val_if_fail (GTK_WIDGET_DRAWABLE (plg->drawing_area), -1); drawing_area = plg->drawing_area; count_major = plg->y_range.i_num_major; count_minor = plg->y_range.i_num_minor; y_minor_inc = plg->y_range.i_minor_inc; y_major_inc = plg->y_range.i_major_inc; if (lg_graph_debug) { g_print ("count_major=%d, count_minor=%d, y_minor_inc=%d, y_major_inc=%d\n", count_major, count_minor, y_minor_inc, y_major_inc); } seg_minor = g_new0 (GdkSegment, count_minor + 8); seg_major = g_new0 (GdkSegment, count_major + 8); x_pos = plg->plot_box.width; y_pos = plg->plot_box.y; for (y_index = 0; y_index < count_minor; y_index++) { seg_minor[y_index].x1 = plg->plot_box.x; seg_minor[y_index].y1 = y_pos + (y_minor_inc * (y_index + 1)); seg_minor[y_index].x2 = plg->plot_box.x + x_pos - 2; seg_minor[y_index].y2 = seg_minor[y_index].y1; } x_pos = plg->plot_box.width; y_pos = plg->plot_box.y; for (y_index = 0; y_index < count_major; y_index++) { seg_major[y_index].x1 = plg->plot_box.x; seg_major[y_index].y1 = y_pos + (y_major_inc * (y_index + 1)); seg_major[y_index].x2 = plg->plot_box.x + x_pos - 2; seg_major[y_index].y2 = seg_major[y_index].y1; } gdk_gc_set_line_attributes (plg->window_gc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL); gdk_draw_segments (plg->pixmap, plg->window_gc, seg_minor, count_minor - 1); gdk_gc_set_line_attributes (plg->window_gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_BEVEL); gdk_draw_segments (plg->pixmap, plg->window_gc, seg_major, count_major - 1); g_free (seg_minor); g_free (seg_major); count_major = plg->x_range.i_num_major; count_minor = plg->x_range.i_num_minor; x_minor_inc = plg->x_range.i_minor_inc; x_major_inc = plg->x_range.i_major_inc; if (lg_graph_debug) { g_print ("count_major=%d, count_minor=%d, x_minor_inc=%d, x_major_inc=%d\n", count_major, count_minor, x_minor_inc, x_major_inc); } seg_minor = g_new0 (GdkSegment, count_minor + 8); seg_major = g_new0 (GdkSegment, count_major + 8); x_pos = plg->plot_box.x; y_pos = plg->plot_box.height; for (x_index = 0; x_index < count_minor; x_index++) { seg_minor[x_index].x1 = plg->plot_box.x + (x_minor_inc * (x_index + 1)); seg_minor[x_index].y1 = plg->plot_box.y + 2; seg_minor[x_index].x2 = seg_minor[x_index].x1; seg_minor[x_index].y2 = plg->plot_box.y + y_pos; } x_pos = plg->plot_box.x; y_pos = plg->plot_box.height; for (x_index = 0; x_index < count_major; x_index++) { seg_major[x_index].x1 = plg->plot_box.x + (x_major_inc * (x_index + 1)); seg_major[x_index].y1 = plg->plot_box.y + 2; seg_major[x_index].x2 = seg_major[x_index].x1; seg_major[x_index].y2 = plg->plot_box.y + y_pos; } gdk_gc_set_line_attributes (plg->window_gc, 1, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL); gdk_draw_segments (plg->pixmap, plg->window_gc, seg_minor, count_minor - 1); gdk_gc_set_line_attributes (plg->window_gc, 2, GDK_LINE_SOLID, GDK_CAP_ROUND, GDK_JOIN_BEVEL); gdk_draw_segments (plg->pixmap, plg->window_gc, seg_major, count_major - 1); g_free (seg_minor); g_free (seg_major); return TRUE; } /* * Draws the tooltip legend message at top or bottom of chart * returns the width of the text area, or -1 on error * requires plg->b_tooltip_active to be TRUE, (toggled by mouse) */ static gint lg_graph_draw_tooltip (PLGRAPH plg) { PangoLayout *layout = NULL; gint x_pos = 0, y_pos = 0, width = 0, height = 0; gint v_index = 0, x_adj = 0; PLG_SERIES psd = NULL; GList *data_sets = NULL; GdkRegion *region = NULL; gboolean b_found = FALSE; g_return_val_if_fail (plg != NULL, -1); g_return_val_if_fail (GTK_WIDGET_DRAWABLE (plg->drawing_area), -1); if (!plg->b_tooltip_active) { return -1; } if (plg->i_points_available < 1) { return -1; } /* * Create tooltip if needed */ region = gdk_region_rectangle (&plg->plot_box); x_adj = (plg->x_range.i_minor_inc / plg->x_range.i_inc_minor_scale_by); /* * see if ptr is at a x-range point */ if (!gdk_region_point_in (region, plg->mouse_pos.x, plg->mouse_pos.y)) { gdk_region_destroy (region); return -1; } gdk_region_destroy (region); for (v_index = 0; v_index <= plg->x_range.i_max_scale; v_index++) { x_pos = plg->plot_box.x + (v_index * x_adj); if ((plg->mouse_pos.x > (x_pos - (x_adj / 3))) && (plg->mouse_pos.x < (x_pos + (x_adj / 3)))) { if (v_index < plg->i_points_available) { b_found = TRUE; break; } } } /* * All we needed was x, so now post a tooltip */ if (b_found) { gchar ch_buffer[GAPC_MAX_BUFFER]; gchar ch_work[GAPC_MAX_BUFFER]; gchar ch_time_r[GAPC_MAX_TEXT]; gchar *pch_time = NULL; time_t point_time; point_time = (time_t) g_list_nth_data (plg->lg_series_time, v_index); pch_time = ctime_r (&point_time, ch_time_r); g_strdelimit (pch_time, "\n", ' '); g_snprintf (ch_buffer, sizeof (ch_buffer), "{ sample #%d @ %s}\n", v_index, pch_time); data_sets = g_list_first (plg->lg_series); while (data_sets) { psd = data_sets->data; if (psd != NULL) { /* found */ g_snprintf (ch_work, sizeof (ch_work), "%s", ch_buffer); g_snprintf (ch_buffer, sizeof (ch_buffer), "%s{%3.0f%% %s}", ch_work, psd->lg_point_dvalue[v_index], psd->ch_legend_color, psd->ch_legend_text); } data_sets = g_list_next (data_sets); } g_snprintf (ch_work, sizeof (ch_work), "%s", ch_buffer); g_snprintf (ch_buffer, sizeof (ch_buffer), "%s", ch_work); g_snprintf (plg->ch_tooltip_text, sizeof (plg->ch_tooltip_text), "%s", ch_buffer); } if (!b_found) { return -1; } layout = gtk_widget_create_pango_layout (plg->drawing_area, plg->ch_tooltip_text); pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); pango_layout_set_markup (layout, plg->ch_tooltip_text, -1); pango_layout_get_pixel_size (layout, &width, &height); x_pos = plg->x_tooltip.x + ((plg->x_tooltip.width - width) / 2); y_pos = plg->x_tooltip.y + ((plg->x_tooltip.height - height) / 2); gdk_draw_rectangle (plg->pixmap, plg->window_gc, /* box_gc, */ TRUE, plg->x_tooltip.x, plg->x_tooltip.y, plg->x_tooltip.width, plg->x_tooltip.height); gdk_draw_rectangle (plg->pixmap, plg->box_gc, FALSE, plg->x_tooltip.x, plg->x_tooltip.y, plg->x_tooltip.width, plg->x_tooltip.height); gdk_draw_layout (plg->pixmap, plg->scale_gc, x_pos, y_pos, layout); g_object_unref (layout); if (lg_graph_debug) { g_print ("DrawToolTip: x=%d, y=%d Width=%d, Height=%d, Text=%s\n", x_pos, y_pos, width, height, plg->ch_tooltip_text); } return width; } #if GTK_CHECK_VERSION(2,6,0) /* * Draws a label text on the Y axis * sets the width, height values of the input rectangle to the size of textbox * returns the height of the text area, or -1 on error */ static gint lg_graph_draw_vertical_text (PLGRAPH plg, gchar * pch_text, GdkRectangle * rect, gboolean redraw_control) { PangoRenderer *renderer = NULL; PangoMatrix matrix = PANGO_MATRIX_INIT; PangoContext *context = NULL; PangoLayout *layout = NULL; gint y_pos = 0; g_return_val_if_fail (plg != NULL, -1); g_return_val_if_fail (pch_text != NULL, -1); g_return_val_if_fail (rect != NULL, -1); g_return_val_if_fail (GTK_WIDGET_DRAWABLE (plg->drawing_area), -1); if (rect->width && redraw_control) { gdk_draw_rectangle (plg->pixmap, plg->window_gc, TRUE, rect->x, rect->y, rect->width, rect->height); } /* Get the default renderer for the screen, and set it up for drawing */ renderer = gdk_pango_renderer_get_default (gtk_widget_get_screen (plg->drawing_area)); gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer), plg->pixmap); gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), plg->title_gc); context = gtk_widget_get_pango_context (plg->drawing_area); layout = pango_layout_new (context); pango_layout_set_markup (layout, pch_text, -1); pango_matrix_rotate (&matrix, 90.0); pango_context_set_matrix (context, &matrix); pango_layout_context_changed (layout); /* xy switched due to rotate func */ pango_layout_get_pixel_size (layout, &rect->height, &rect->width); y_pos = rect->y + ((plg->plot_box.height - rect->height) / 2); gdk_draw_layout (plg->pixmap, plg->title_gc, rect->x, y_pos, layout); /* Clean up default renderer, since it is shared */ gdk_pango_renderer_set_drawable (GDK_PANGO_RENDERER (renderer), NULL); gdk_pango_renderer_set_gc (GDK_PANGO_RENDERER (renderer), NULL); pango_context_set_matrix (context, NULL); /* free the objects we created */ g_object_unref (layout); if (lg_graph_debug) { g_print ("Vertical Label: x=%d, y=%d Width=%d, Height=%d Text:%s\n", rect->x, rect->y, rect->width, rect->height, pch_text); } if (redraw_control) { GdkRegion *region = NULL; region = gdk_region_rectangle (rect); gdk_window_invalidate_region (plg->drawing_area->window, region, FALSE); gdk_region_destroy (region); } return rect->height; } #else static gint lg_graph_draw_vertical_text (PLGRAPH plg, gchar * pch_text, GdkRectangle * rect, gboolean redraw_control) { PangoContext *context = NULL; PangoLayout *layout = NULL; gint y_pos = 0; GdkPixmap *norm_pixmap = NULL; gint width, height; gint rot_width, rot_height; GdkPixbuf *norm_pixbuf = NULL, *rot_pixbuf = NULL; guint32 *norm_pix, *rot_pix; gint i, j, k, l; g_return_val_if_fail (plg != NULL, -1); g_return_val_if_fail (pch_text != NULL, -1); g_return_val_if_fail (rect != NULL, -1); g_return_val_if_fail (GTK_WIDGET_DRAWABLE (plg->drawing_area), -1); context = gtk_widget_get_pango_context (plg->drawing_area); layout = pango_layout_new (context); pango_layout_set_markup (layout, pch_text, -1); pango_layout_get_pixel_size (layout, &width, &height); if (width <= 0 || height <= 0) { return 0; } /* Figure out the rotated width and height */ rect->width = rot_width = height; rect->height = rot_height = width; norm_pixmap = gdk_pixmap_new (plg->drawing_area->window, width, height, -1); gdk_draw_rectangle (norm_pixmap, plg->window_gc, TRUE, 0, 0, width, height); gdk_draw_layout (norm_pixmap, plg->title_gc, 0, 0, layout); norm_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height); norm_pixbuf = gdk_pixbuf_get_from_drawable (norm_pixbuf, norm_pixmap, NULL, 0, 0, 0, 0, width, height); /* Get the raw pixel pointer of client buffer */ norm_pix = (guint32 *) gdk_pixbuf_get_pixels (norm_pixbuf); /* Allocate a new client buffer with rotated memory */ rot_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, rot_width, rot_height); rot_pix = (guint32 *) gdk_pixbuf_get_pixels (rot_pixbuf); /* Actually rotate */ k = 0; for (j = width - 1; j >= 0; j--) { l = j; for (i = 0; i < height; i++, k++, l += width) { rot_pix[k] = norm_pix[l]; } } /* compute a centered position on chart */ y_pos = rect->y + ((plg->plot_box.height - rect->height) / 2); /* Draw it to the chart */ gdk_pixbuf_render_to_drawable ( rot_pixbuf, plg->pixmap, plg->title_gc, 0, 0, rect->x -1, y_pos, rect->width, rect->height, GDK_RGB_DITHER_NONE, 0, 0); /* Free everything */ g_object_unref (layout); g_object_unref (G_OBJECT (norm_pixmap)); g_object_unref (G_OBJECT (norm_pixbuf)); g_object_unref (G_OBJECT (rot_pixbuf)); return rect->height; } #endif /* * Draws a label text on the X axis * sets the width, height values of the input rectangle to the size of textbox * returns the width of the text area, or -1 on error * redraw_control = 1 causes an expose_event, 0 or != 1 does not */ static gint lg_graph_draw_horizontal_text (PLGRAPH plg, gchar * pch_text, GdkRectangle * rect, gboolean redraw_control) { PangoLayout *layout = NULL; gint x_pos = 0; g_return_val_if_fail (plg != NULL, -1); g_return_val_if_fail (pch_text != NULL, -1); g_return_val_if_fail (rect != NULL, -1); g_return_val_if_fail (GTK_WIDGET_DRAWABLE (plg->drawing_area), -1); if (rect->width && redraw_control) { gdk_draw_rectangle (plg->pixmap, plg->window_gc, TRUE, rect->x, rect->y, rect->width, rect->height); } layout = gtk_widget_create_pango_layout (plg->drawing_area, pch_text); pango_layout_set_markup (layout, pch_text, -1); pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER); pango_layout_get_pixel_size (layout, &rect->width, &rect->height); x_pos = rect->x + ((plg->plot_box.width - rect->width) / 2); gdk_draw_layout (plg->pixmap, plg->title_gc, x_pos, rect->y, layout); g_object_unref (layout); if (lg_graph_debug) { g_print ("Horizontal Label: x=%d, y=%d Width=%d, Height=%d Text:%s\n", x_pos, rect->y, rect->width, rect->height, pch_text); } if (redraw_control) { GdkRegion *region = NULL; region = gdk_region_rectangle (rect); gdk_window_invalidate_region (plg->drawing_area->window, region, FALSE); gdk_region_destroy (region); } return rect->width; } /* * Computes the size of 3 proportional charactor using default font */ static void lg_graph_get_default_sizes (PLGRAPH plg, gint * width, gint * height) { PangoLayout *layout = NULL; g_return_if_fail (plg != NULL); layout = gtk_widget_create_pango_layout (plg->drawing_area, "1M5"); pango_layout_set_markup (layout, "M5", -1); pango_layout_get_pixel_size (layout, width, height); g_object_unref (layout); if (lg_graph_debug) { g_print ("Default Sizing(1M5): Width=%d, Height=%d\n", *width, *height); } return; } /* * Compute and set x-y ranges */ static void lg_graph_set_ranges (PLGRAPH plg, gint xminor_by, gint xmajor_by, gint x_min, gint x_max, gint yminor_by, gint ymajor_by, gint y_min, gint y_max) { g_return_if_fail (plg != NULL); plg->x_range.i_inc_minor_scale_by = xminor_by; /* minimum scale value - ex: 0 */ plg->x_range.i_inc_major_scale_by = xmajor_by; /* minimum scale value - ex: 0 */ plg->x_range.i_min_scale = x_min; /* minimum scale value - ex: 0 */ plg->x_range.i_max_scale = x_max; /* maximum scale value - ex: 100 */ plg->x_range.i_num_minor = x_max / xminor_by; /* number of minor points */ plg->x_range.i_num_major = x_max / xmajor_by; /* number of major points */ plg->y_range.i_inc_minor_scale_by = yminor_by; /* minimum scale value - ex: 0 */ plg->y_range.i_inc_major_scale_by = ymajor_by; /* minimum scale value - ex: 0 */ plg->y_range.i_min_scale = y_min; /* minimum scale value - ex: 0 */ plg->y_range.i_max_scale = y_max; /* maximum scale value - ex: 100 */ plg->y_range.i_num_minor = y_max / yminor_by; /* number of minor points */ plg->y_range.i_num_major = y_max / ymajor_by; /* number of major points */ return; } /* * Repaint * * data - widget to repaint */ static gint lg_graph_draw (PLGRAPH plg) { GtkWidget *drawing_area = NULL; g_return_val_if_fail (plg != NULL, TRUE); drawing_area = plg->drawing_area; if ( !(GTK_WIDGET_DRAWABLE (drawing_area)) ) { return TRUE; } /* * Clear the whole area */ gdk_draw_rectangle (plg->pixmap, plg->window_gc, TRUE, 0, 0, plg->drawing_area->allocation.width, plg->drawing_area->allocation.height); /* * draw plot area */ gdk_draw_rectangle (plg->pixmap, plg->box_gc, TRUE, plg->plot_box.x, plg->plot_box.y, plg->plot_box.width, plg->plot_box.height); gdk_gc_set_line_attributes (plg->drawing_area->style->black_gc, 2, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL); gdk_draw_rectangle (plg->pixmap, plg->drawing_area->style->black_gc, FALSE, plg->plot_box.x, plg->plot_box.y, plg->plot_box.width, plg->plot_box.height); if (lg_graph_debug) { g_print ("Window: Width=%d, Height=%d, Plot Area x=%d y=%d width=%d, height=%d\n", drawing_area->allocation.width, drawing_area->allocation.height, plg->plot_box.x, plg->plot_box.y, plg->plot_box.width, plg->plot_box.height); } /* * draw titles */ lg_graph_draw_horizontal_text (plg, plg->x_title_text, &plg->x_title, FALSE); lg_graph_draw_horizontal_text (plg, plg->x_label_text, &plg->x_label, FALSE); lg_graph_draw_vertical_text (plg, plg->y_label_text, &plg->y_label, FALSE); lg_graph_draw_grid_lines (plg); lg_graph_draw_x_grid_labels (plg); lg_graph_draw_y_grid_labels (plg); lg_graph_data_series_draw_all (plg, FALSE); lg_graph_draw_tooltip (plg); /* The entire pixmap is going to be copied * onto the window so the rect is configured * as the size of the window. */ lg_graph_redraw (plg); return (FALSE); } /* * configure_event * * Create a new backing pixmap of the appropriate size * Of course, this is called whenever the window is * resized. We have to free up things we allocated. */ static gint lg_graph_configure_event_cb (GtkWidget * widget, GdkEventConfigure * event, PLGRAPH plg) { GdkRectangle clip_area; gint xfactor = 0, yfactor = 0; /* --- Free background if we created it --- */ if (plg->pixmap) { gdk_pixmap_unref (plg->pixmap); } /* --- Create a new pixmap with new size --- */ plg->pixmap = gdk_pixmap_new (widget->window, widget->allocation.width, widget->allocation.height, -1); gdk_draw_rectangle (plg->pixmap, plg->window_gc, TRUE, 0, 0, widget->allocation.width, widget->allocation.height); plg->width = widget->allocation.width; plg->height = widget->allocation.height; clip_area.x = 0; clip_area.y = 0; clip_area.width = widget->allocation.width; clip_area.height = widget->allocation.height; xfactor = MAX (plg->x_range.i_num_minor, plg->x_range.i_num_major); yfactor = MAX (plg->y_range.i_num_minor, plg->y_range.i_num_major); lg_graph_get_default_sizes (plg, &plg->x_border, &plg->y_border); plg->x_border /= 4; plg->y_border /= 4; plg->x_label.x = plg->x_border * 6; /* define top-left corner of textbox */ plg->x_label.y = plg->height - (plg->y_border * 4) + 2; plg->y_label.x = plg->x_border; plg->y_label.y = plg->y_border * 6; plg->x_title.x = plg->x_border * 6; plg->x_title.y = 1; /* /plg->y_border ; */ plg->x_tooltip.x = plg->x_border; plg->x_tooltip.y = plg->y_border; plg->x_tooltip.width = plg->width - (plg->x_border * 2); plg->x_tooltip.height = plg->y_border * 7; plg->plot_box.x = plg->x_border * 6; plg->plot_box.y = plg->y_border * 6; plg->plot_box.width = ((gint) (plg->width - (plg->x_border * 10)) / xfactor) * xfactor; plg->plot_box.height = ((gint) (plg->height - (plg->y_border * 14)) / yfactor) * yfactor; /* reposition the box according to scale-able increments */ plg->plot_box.x = (((gfloat) (plg->width - plg->plot_box.width) / 10.0) * 7) + 4; plg->plot_box.y = (((gfloat) (plg->height - plg->plot_box.height) / 10.0) * 5) + 4; plg->x_label.x = plg->x_title.x = plg->plot_box.x; plg->y_label.y = plg->plot_box.y; plg->y_range.i_minor_inc = plg->plot_box.height / plg->y_range.i_num_minor; plg->y_range.i_major_inc = plg->plot_box.height / plg->y_range.i_num_major; plg->x_range.i_minor_inc = plg->plot_box.width / plg->x_range.i_num_minor; plg->x_range.i_major_inc = plg->plot_box.width / plg->x_range.i_num_major; g_timeout_add (250, (GSourceFunc) lg_graph_draw, plg); return TRUE; } /* * expose_event * * When the window is exposed to the viewer or * the gdk_widget_draw routine is called, this * routine is called. Copies the background pixmap * to the window. */ static gint lg_graph_expose_event_cb (GtkWidget * widget, GdkEventExpose * event, PLGRAPH plg) { g_return_val_if_fail (GDK_IS_DRAWABLE (widget->window), FALSE); /* --- Copy pixmap to the window --- */ gdk_draw_pixmap (widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], plg->pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); return FALSE; } static void cb_util_popup_menu_response_exit(GtkWidget * widget, gpointer gp) { PGAPC_CONFIG pcfg = NULL; PGAPC_MONITOR pm = NULL; gchar *penabled = NULL; g_return_if_fail(gp != NULL); if (((PGAPC_MONITOR) gp)->cb_id == CB_MONITOR_ID) { /* this is a monitor struct (2) */ pm = (PGAPC_MONITOR) gp; pm->b_run = FALSE; penabled = g_strdup_printf(GAPC_ENABLE_KEY, pm->cb_monitor_num); gconf_client_set_bool(pm->client, penabled, FALSE, NULL); g_free(penabled); } else { /* this is a config struct (1) */ pcfg = (PGAPC_CONFIG) gp; gtk_widget_destroy(GTK_WIDGET(pcfg->window)); } return; } static void cb_util_popup_menu_response_jumpto(GtkWidget * widget, gpointer gp) { PGAPC_CONFIG pcfg = NULL; PGAPC_MONITOR pm = NULL; GtkWindow *window = NULL; g_return_if_fail(gp != NULL); if (((PGAPC_MONITOR) gp)->cb_id == CB_MONITOR_ID) { /* this is a monitor struct (2) */ pm = (PGAPC_MONITOR) gp; window = GTK_WINDOW(pm->window); } else { /* this is a config struct (1) */ pcfg = (PGAPC_CONFIG) gp; window = GTK_WINDOW(pcfg->window); } if (window != NULL) { gtk_window_present(window); } return; } /* * Change the color values back to their original defaults */ static void cb_panel_property_color_reset (GtkButton *button, PGAPC_CONFIG pcfg) { gchar *pstring = NULL; g_return_if_fail (pcfg != NULL); gdk_color_parse ("green", &pcfg->color_linev); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_linev, 1); if (pstring != NULL) { gconf_client_set_string(pcfg->client, GAPC_COLOR_LINEV_KEY, pstring, NULL); g_free (pstring); } gdk_color_parse ("blue", &pcfg->color_loadpct); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_loadpct, 1); if (pstring != NULL) { gconf_client_set_string(pcfg->client, GAPC_COLOR_LOADPCT_KEY, pstring, NULL); g_free (pstring); } gdk_color_parse ("red", &pcfg->color_timeleft); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_timeleft, 1); if (pstring != NULL) { gconf_client_set_string(pcfg->client, GAPC_COLOR_TIMELEFT_KEY, pstring, NULL); g_free (pstring); } gdk_color_parse ("yellow", &pcfg->color_bcharge); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_bcharge, 1); if (pstring != NULL) { gconf_client_set_string(pcfg->client, GAPC_COLOR_BCHARGE_KEY, pstring, NULL); g_free (pstring); } gdk_color_parse ("black", &pcfg->color_battv); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_battv, 1); if (pstring != NULL) { gconf_client_set_string(pcfg->client, GAPC_COLOR_BATTV_KEY, pstring, NULL); g_free (pstring); } gdk_color_parse ("white", &pcfg->color_window); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_window, 1); if (pstring != NULL) { gconf_client_set_string(pcfg->client, GAPC_COLOR_WINDOW_KEY, pstring, NULL); g_free (pstring); } gdk_color_parse ("light blue", &pcfg->color_chart); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_chart, 1); if (pstring != NULL) { gconf_client_set_string(pcfg->client, GAPC_COLOR_CHART_KEY, pstring, NULL); g_free (pstring); } gdk_color_parse ("blue", &pcfg->color_title); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_title, 1); if (pstring != NULL) { gconf_client_set_string(pcfg->client, GAPC_COLOR_TITLE_KEY, pstring, NULL); g_free (pstring); } return; } /* * catch the color change signal and save its value into gconf */ static void cb_panel_property_color_change (GtkColorButton *widget, gchar *color_key) { GConfClient *client = NULL; GdkColor color; gchar *pstring = NULL; g_return_if_fail(GTK_IS_COLOR_BUTTON(widget)); g_return_if_fail(color_key != NULL); gtk_color_button_get_color (GTK_COLOR_BUTTON(widget), &color); pstring = gtk_color_selection_palette_to_string ( &color, 1); if (pstring == NULL) { return; } client = (GConfClient *)g_object_get_data (G_OBJECT(widget), "gconf-client"); if (client != NULL) { gconf_client_set_string (client, color_key, pstring, NULL); } g_free (pstring); return; } /* * Changes the Applets icon if needed * returns FALSE if OK * return TRUE is any error */ static gint gapc_util_change_icons(PGAPC_MONITOR pm) { GdkPixbuf *pixbuf = NULL; GdkPixbuf *scaled = NULL; GtkOrientation orientation; gint size = 0; g_return_val_if_fail(pm != NULL, TRUE); if (pm->i_icon_index >= GAPC_N_ICONS) { pm->i_icon_index = GAPC_ICON_ONLINE; } pixbuf = pm->my_icons[pm->i_icon_index]; if (pixbuf) { if (pm->tray_image != NULL) { orientation = egg_tray_icon_get_orientation(EGG_TRAY_ICON(pm->tray_icon)); if (orientation == GTK_ORIENTATION_HORIZONTAL) { size = pm->i_icon_height; } else { size = pm->i_icon_width; } if (size < 5) { size = 22; } scaled = gdk_pixbuf_scale_simple(pixbuf, size, size, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf(GTK_IMAGE(pm->tray_image), scaled); gtk_widget_show(pm->tray_image); gdk_pixbuf_unref(scaled); } if (pm->window != NULL) gtk_window_set_icon(GTK_WINDOW(pm->window), pixbuf); } return FALSE; } /* * used to switch timers when d_refresh changes * b_timer_control True trigger the target timer to stop and have this one * restart it; so it can pickup the new interval; */ static gboolean cb_util_line_chart_refresh_control(PGAPC_MONITOR pm) { GtkWidget *w = NULL; gchar *pch1 = NULL, *pch = NULL; g_return_val_if_fail(pm != NULL, FALSE); if ((!pm->b_run) || !(pm->cb_enabled)) return FALSE; /* stop timers */ pm->b_graph_control = FALSE; pm->phs.d_xinc = pm->d_graph * pm->d_refresh; pm->tid_graph_refresh = g_timeout_add((guint) (pm->phs.d_xinc * GAPC_REFRESH_FACTOR_1K ), (GSourceFunc) cb_util_line_chart_refresh, &pm->phs); pch = g_strdup_printf( "sampled every %3.1f seconds", pm->phs.d_xinc); lg_graph_set_x_label_text (pm->phs.plg, pch); g_free(pch); w = g_hash_table_lookup(pm->pht_Widgets, "StatusBar"); if ((pm->tid_graph_refresh != 0) && (w != NULL)) { gtk_statusbar_pop(GTK_STATUSBAR(w), pm->i_info_context); pch1 = g_strdup_printf ("Graphing refresh cycle changed for host %s completed!...", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(w), pm->i_info_context, pch1); g_free(pch1); } return FALSE; } /* * used to switch timers when d_refresh changes * b_timer_control True trigger the target timer to stop and have this one * restart it; so it can pickup the new interval; */ static gboolean cb_monitor_refresh_control(PGAPC_MONITOR pm) { GtkWidget *w = NULL; gchar *pch1 = NULL; g_return_val_if_fail(pm != NULL, FALSE); if ((!pm->b_run) || !(pm->cb_enabled)) return FALSE; /* stop timers */ pm->b_timer_control = FALSE; pm->tid_automatic_refresh = g_timeout_add((guint) (pm->d_refresh * GAPC_REFRESH_FACTOR_1K), (GSourceFunc) cb_monitor_automatic_refresh, pm); w = g_hash_table_lookup(pm->pht_Widgets, "StatusBar"); if ((pm->tid_automatic_refresh != 0) && (w != NULL)) { gtk_statusbar_pop(GTK_STATUSBAR(w), pm->i_info_context); pch1 = g_strdup_printf("Refresh Cycle Change for host %s Completed!...", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(w), pm->i_info_context, pch1); g_free(pch1); } return FALSE; } /* * timer service routine for IPL refresh and refresh_button. * used to overcome the multi-threaded startup delay. very short */ static gboolean cb_monitor_dedicated_one_time_refresh(PGAPC_MONITOR pm) { GtkWidget *w = NULL; gchar *pch1 = NULL; g_return_val_if_fail(pm != NULL, FALSE); if ((!pm->b_run) || !(pm->cb_enabled)) { return FALSE; } if (!g_mutex_trylock(pm->gm_update)) { w = g_hash_table_lookup(pm->pht_Widgets, "StatusBar"); if (w != NULL) { gtk_statusbar_pop(GTK_STATUSBAR(w), pm->i_info_context); pch1 = g_strdup_printf("Quick refresh for %s failed!" " Network thread is busy...", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(w), pm->i_info_context, pch1); g_free(pch1); } return TRUE; /* thread must be busy */ } gdk_threads_enter(); w = g_hash_table_lookup(pm->pht_Widgets, "StatusBar"); if (w != NULL) { gtk_statusbar_pop(GTK_STATUSBAR(w), pm->i_info_context); } gapc_monitor_update_tooltip_msg(pm); if (!gapc_monitor_update(pm)) { if (w != NULL) { pch1 = g_strdup_printf("Refresh for %s failed! " "(retry enabled)... network busy!", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(w), pm->i_info_context, pch1); g_free(pch1); } if (pm->i_netbusy_counter++ % 10) { /* Fall thru and quit after ten trys */ g_mutex_unlock(pm->gm_update); gdk_flush(); gdk_threads_leave(); return TRUE; /* try again */ } } if (w != NULL) { pch1 = g_strdup_printf("One-Time Refresh for %s Completed...", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(w), pm->i_info_context, pch1); g_free(pch1); } g_mutex_unlock(pm->gm_update); gdk_flush(); gdk_threads_leave(); return FALSE; /* this will terminate the timer */ } /* * used to make a work request to network queue */ static gboolean cb_monitor_automatic_refresh(PGAPC_MONITOR pm) { gchar *pch1 = NULL; GtkWidget *w = NULL; g_return_val_if_fail(pm != NULL, FALSE); if ((!pm->b_run) || !(pm->cb_enabled)) return FALSE; /* stop timers */ if (pm->b_timer_control) { g_timeout_add(100, (GSourceFunc) cb_monitor_refresh_control, pm); return FALSE; } if (!g_mutex_trylock(pm->gm_update)) { w = g_hash_table_lookup(pm->pht_Widgets, "StatusBar"); if (w != NULL) { gtk_statusbar_pop(GTK_STATUSBAR(w), pm->i_info_context); pch1 = g_strdup_printf("Automatic refresh for %s failed!" " Network thread is busy...", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(w), pm->i_info_context, pch1); g_free(pch1); } return TRUE; /* thread must be busy */ } gdk_threads_enter(); w = g_hash_table_lookup(pm->pht_Widgets, "StatusBar"); if (w != NULL) { gtk_statusbar_pop(GTK_STATUSBAR(w), pm->i_info_context); } gapc_monitor_update_tooltip_msg(pm); /* false = OK */ if (gapc_monitor_update(pm)) { if (w != NULL) { pch1 = g_strdup_printf("Automatic refresh for %s complete...", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(w), pm->i_info_context, pch1); g_free(pch1); } } else { if (w != NULL) { pch1 = g_strdup_printf("Automatic refresh for %s failed!" " Network thread is busy...", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(w), pm->i_info_context, pch1); g_free(pch1); } if (pm->i_netbusy_counter++ % 10) { /* fall thru every tenth time to queue a message */ g_mutex_unlock(pm->gm_update); gdk_flush(); gdk_threads_leave(); return TRUE; } } /* * This is the work request to network queue */ g_async_queue_push(pm->q_network, (gpointer) pm); g_mutex_unlock(pm->gm_update); gdk_flush(); gdk_threads_leave(); return TRUE; } /* * Manage the state icon in the panel and the associated tooltip * Composes the expanded tooltip message */ static gboolean gapc_monitor_update_tooltip_msg(PGAPC_MONITOR pm) { gchar *pchx = NULL, *pmsg = NULL, *ptitle = NULL, *pch5 = NULL, *pch5a = NULL, *pch5b = NULL; gchar *pch1 = NULL, *pch2 = NULL, *pch3 = NULL, *pch4 = NULL; gchar *pch6 = NULL, *pch7 = NULL, *pch8 = NULL, *pch9 = NULL; gchar *pchb = NULL, *pchc = NULL, *pchd = NULL, *pche = NULL; gchar *pcha = NULL, *pmview = NULL, *pch_watt = NULL; GtkWidget *w = NULL; gdouble d_value = 0.0, d_watt =0.0, d_loadpct = 0.0; gboolean b_flag = FALSE, b_valid = FALSE; gint i_series = 0; GtkTreeIter miter; GdkPixbuf *pixbuf; g_return_val_if_fail(pm != NULL, TRUE); if (pm->b_run != TRUE) return TRUE; w = g_hash_table_lookup(pm->pht_Widgets, "StatusBar"); pm->i_icon_index = GAPC_ICON_ONLINE; pch1 = g_hash_table_lookup(pm->pht_Status, "UPSNAME"); pch2 = g_hash_table_lookup(pm->pht_Status, "HOSTNAME"); if (pch2 == NULL) { pch2 = pm->pch_host; } if (pch2 == NULL) { pch2 = "unknown"; } pch3 = g_hash_table_lookup(pm->pht_Status, "STATUS"); if (pch3 == NULL) { pch3 = "NISERR"; } pch4 = g_hash_table_lookup(pm->pht_Status, "NUMXFERS"); pch5a = g_hash_table_lookup(pm->pht_Status, "TONBATT"); if (pch5a == NULL) { pch5a = " "; } pch5b = g_hash_table_lookup(pm->pht_Status, "CUMONBATT"); if (pch5b == NULL) { pch5b = " "; } pch5 = g_hash_table_lookup(pm->pht_Status, "XONBATT"); if (pch5 == NULL) { pch5 = " "; } pch6 = g_hash_table_lookup(pm->pht_Status, "LINEV"); pch7 = g_hash_table_lookup(pm->pht_Status, "BCHARGE"); if (pch7 == NULL) { pch7 = "n/a"; } pch8 = g_hash_table_lookup(pm->pht_Status, "LOADPCT"); if ( pch8 != NULL ) { d_loadpct = g_strtod (pch8, NULL); d_loadpct /= 100.0; } pch_watt = g_hash_table_lookup(pm->pht_Status, "NOMPOWER"); if ( pch_watt != NULL ) { pm->i_watt = g_strtod (pch_watt, NULL); d_watt = d_loadpct * pm->i_watt; } else { d_watt = d_loadpct * pm->i_watt; } pch9 = g_hash_table_lookup(pm->pht_Status, "TIMELEFT"); pcha = g_hash_table_lookup(pm->pht_Status, "VERSION"); pchb = g_hash_table_lookup(pm->pht_Status, "STARTTIME"); pchc = g_hash_table_lookup(pm->pht_Status, "MODEL"); pchd = g_hash_table_lookup(pm->pht_Status, "UPSMODE"); pche = g_hash_table_lookup(pm->pht_Status, "CABLE"); if (pm->b_data_available) { d_value = g_strtod(pch7, NULL); pchx = NULL; if (g_strrstr(pch3, "COMMLOST") != NULL) { pchx = " cable un-plugged..."; pm->i_icon_index = GAPC_ICON_UNPLUGGED; b_flag = TRUE; } else if ((d_value < 99.0) && (g_strrstr(pch3, "LINE") != NULL)) { pchx = " and charging..."; pch3 = "CHARGING"; pm->i_icon_index = GAPC_ICON_CHARGING; } else if (g_strrstr(pch3, "BATT") != NULL) { pchx = " on battery..."; pm->i_icon_index = GAPC_ICON_ONBATT; } } else { b_flag = TRUE; pchx = " NIS network error..."; pch3 = "NISERR"; g_hash_table_replace(pm->pht_Status, g_strdup("STATUS"), g_strdup(pch3)); pm->i_icon_index = GAPC_ICON_NETWORKERROR; for (i_series = 0; i_series < pm->phs.plg->i_num_series; i_series++) { gapc_util_point_filter_set(&(pm->phs.sq[i_series]), 0.0); } } if (b_flag) { ptitle = g_strdup_printf("" "%s@%s\nis %s%s" "", (pch1 != NULL) ? pch1 : "unknown", (pch2 != NULL) ? pch2 : "unknown", (pch3 != NULL) ? pch3 : "n/a", (pchx != NULL) ? pchx : " "); } else { ptitle = g_strdup_printf("" "%s@%s\nis %s%s" "", (pch1 != NULL) ? pch1 : "unknown", (pch2 != NULL) ? pch2 : "unknown", (pch3 != NULL) ? pch3 : "n/a", (pchx != NULL) ? pchx : " "); } pmsg = g_strdup_printf("%s@%s\nStatus: %s%s\n" "Refresh occurs every %3.1f seconds\n" "----------------------------------------------------------\n" "%s Outage[s]\n" "Last on %s\n" "%s Utility VAC\n" "%s Battery Charge\n" "%s UPS Load\n" "%3.0f of %d watts\n" "%s Remaining\n" "----------------------------------------------------------\n" "Build: %s\n" "Started: %s\n" "----------------------------------------------------------\n" "Model: %s\n" " Mode: %s\n" "Cable: %s", (pch1 != NULL) ? pch1 : "unknown", (pch2 != NULL) ? pch2 : "unknown", (pch3 != NULL) ? pch3 : "n/a", (pchx != NULL) ? pchx : " ", pm->d_refresh, (pch4 != NULL) ? pch4 : "n/a", (pch5 != NULL) ? pch5 : "n/a", (pch6 != NULL) ? pch6 : "n/a", (pch7 != NULL) ? pch7 : "n/a", (pch8 != NULL) ? pch8 : "n/a", d_watt, pm->i_watt, (pch9 != NULL) ? pch9 : "n/a", (pcha != NULL) ? pcha : "n/a", (pchb != NULL) ? pchb : "n/a", (pchc != NULL) ? pchc : "n/a", (pchd != NULL) ? pchd : "n/a", (pche != NULL) ? pche : "n/a"); switch (pm->i_icon_index) { case GAPC_ICON_NETWORKERROR: pmview = g_strdup_printf("" "%s@%s\n" "NIS network connection not Responding!", (pch1 != NULL) ? pch1 : "unknown", (pch2 != NULL) ? pch2 : "unknown"); break; case GAPC_ICON_UNPLUGGED: pmview = g_strdup_printf("" "%s@%s\n" "%s", (pch1 != NULL) ? pch1 : "unknown", (pch2 != NULL) ? pch2 : "unknown", (pchx != NULL) ? pchx : " un-plugged"); break; case GAPC_ICON_CHARGING: pmview = g_strdup_printf("" "%s@%s\n" "%s Outage, Last on %s\n" "%s VAC, %s Charge\n" "%s Remaining, %s total on battery, %3.0f of %d watts", (pch1 != NULL) ? pch1 : "unknown", (pch2 != NULL) ? pch2 : "unknown", (pch4 != NULL) ? pch4 : "n/a", (pch5 != NULL) ? pch5 : "n/a", (pch6 != NULL) ? pch6 : "n/a", (pch7 != NULL) ? pch7 : "n/a", (pch9 != NULL) ? pch9 : "n/a", (pch5b != NULL) ? pch5b : "n/a", d_watt, pm->i_watt); break; case GAPC_ICON_ONBATT: pmview = g_strdup_printf("" "%s@%s\n" "%s Outage, Last on %s\n" "%s Charge, %s total on battery\n" "%s Remaining, %s on battery, %3.0f of %d watts", (pch1 != NULL) ? pch1 : "unknown", (pch2 != NULL) ? pch2 : "unknown", (pch4 != NULL) ? pch4 : "n/a", (pch5 != NULL) ? pch5 : "n/a", (pch7 != NULL) ? pch7 : "n/a", (pch5b != NULL) ? pch5b : "n/a", (pch9 != NULL) ? pch9 : "n/a", (pch5a != NULL) ? pch5a : "n/a ", d_watt, pm->i_watt); break; case GAPC_ICON_ONLINE: case GAPC_ICON_DEFAULT: default: pmview = g_strdup_printf("%s@%s\n" "%s Outage, Last on %s\n" "%s VAC, %s Charge %s %3.0f of %d watts", (pch1 != NULL) ? pch1 : "unknown", (pch2 != NULL) ? pch2 : "unknown", (pch4 != NULL) ? pch4 : "n/a", (pch5 != NULL) ? pch5 : "n/a", (pch6 != NULL) ? pch6 : "n/a", (pch7 != NULL) ? pch7 : "n/a", (pchx != NULL) ? pchx : " ", d_watt, pm->i_watt); break; } pixbuf = pm->my_icons[pm->i_icon_index]; if (pm->i_old_icon_index != pm->i_icon_index) { b_flag = TRUE; } else { b_flag = FALSE; } if ((pm->tooltips != NULL) && (pm->tray_icon != NULL)) { gtk_tooltips_set_tip(pm->tooltips, GTK_WIDGET(pm->tray_icon), pmsg, NULL); if (b_flag) { gapc_util_change_icons(pm); } } b_valid = gapc_util_treeview_get_iter_from_monitor(pm->monitor_model, &miter, pm->cb_monitor_num); if (b_valid) { if (b_flag) { gtk_list_store_set(GTK_LIST_STORE(pm->monitor_model), &miter, GAPC_MON_STATUS, pmview, GAPC_MON_UPSSTATE, pch3, GAPC_MON_ICON, pixbuf, -1); } else { gtk_list_store_set(GTK_LIST_STORE(pm->monitor_model), &miter, GAPC_MON_STATUS, pmview, GAPC_MON_UPSSTATE, pch3, -1); } } if ((w = g_hash_table_lookup(pm->pht_Widgets, "TitleStatus"))) { gtk_label_set_markup(GTK_LABEL(w), ptitle); lg_graph_set_chart_title (pm->phs.plg, ptitle); g_snprintf(pm->ch_title_info, GAPC_MAX_TEXT, "%s", ptitle); lg_graph_draw ( pm->phs.plg ); } g_free(pmsg); g_free(ptitle); /* g_free (pmview); */ return b_flag; } /* * main data updating routine. * -- collects and pushes data to all ui */ static gint gapc_monitor_update(PGAPC_MONITOR pm) { gint i_x = 0; GtkWidget *win = NULL, *w = NULL; gchar *pch = NULL, *pch1 = NULL, *pch2 = NULL, *pch3 = NULL, *pch4 = NULL; gchar *pch_watt = NULL, *pch5 = NULL, *pch6 = NULL; gdouble dValue = 0.00, dScale = 0.0, dtmp = 0.0, dCharge = 0.0, d_loadpct = 0.0, d_watt = 0.0; gchar ch_buffer[GAPC_MAX_TEXT]; PGAPC_BAR_H pbar = NULL; g_return_val_if_fail(pm != NULL, FALSE); if (pm->window == NULL) /* not created yet */ return TRUE; if (pm->b_run == FALSE) return FALSE; if (pm->b_data_available == FALSE) return FALSE; w = g_hash_table_lookup(pm->pht_Widgets, "StatusPage"); if (gapc_util_text_view_clear_buffer(GTK_WIDGET(w))) { return FALSE; } for (i_x = 1; pm->pach_status[i_x] != NULL; i_x++) { gapc_util_text_view_append(GTK_WIDGET(w), pm->pach_status[i_x]); } w = g_hash_table_lookup(pm->pht_Widgets, "EventsPage"); gapc_util_text_view_clear_buffer(GTK_WIDGET(w)); for (i_x = 0; pm->pach_events[i_x] != NULL; i_x++) { gapc_util_text_view_prepend(GTK_WIDGET(w), pm->pach_events[i_x]); } /* * compute graphic points */ pch = g_hash_table_lookup(pm->pht_Status, "LINEV"); if (pch == NULL) { pch = "n/a"; } dValue = g_strtod(pch, NULL); dScale = (( dValue - 200 ) > 1) ? 230.0 : 120.0; dValue /= dScale; gapc_util_point_filter_set(&(pm->phs.sq[0]), dValue); pbar = g_hash_table_lookup(pm->pht_Status, "HBar1"); pbar->d_value = dValue; g_snprintf(pbar->c_text, sizeof(pbar->c_text), "%s from Utility", pch); w = g_hash_table_lookup(pm->pht_Widgets, "HBar1-Widget"); if (GTK_WIDGET_DRAWABLE(w)) gdk_window_invalidate_rect(w->window, &pbar->rect, FALSE); pch = g_hash_table_lookup(pm->pht_Status, "BATTV"); if (pch == NULL) { pch = "n/a"; } pch1 = g_hash_table_lookup(pm->pht_Status, "NOMBATTV"); if (pch1 == NULL) { pch1 = "n/a"; } dValue = g_strtod(pch, NULL); dScale = g_strtod(pch1, NULL); if (dScale == 0.0) dScale = ((gint) (dValue - 20)) ? 24 : 12; dValue /= dScale; gapc_util_point_filter_set(&(pm->phs.sq[4]), dValue); pbar = g_hash_table_lookup(pm->pht_Status, "HBar2"); pbar->d_value = (dValue > 1.0) ? 1.0 : dValue; g_snprintf(pbar->c_text, sizeof(pbar->c_text), "%s DC on Battery", pch); w = g_hash_table_lookup(pm->pht_Widgets, "HBar2-Widget"); if (GTK_WIDGET_DRAWABLE(w)) gdk_window_invalidate_rect(w->window, &pbar->rect, FALSE); pch = g_hash_table_lookup(pm->pht_Status, "BCHARGE"); if (pch == NULL) { pch = "n/a"; } dCharge = dValue = g_strtod(pch, NULL); dValue /= 100.0; gapc_util_point_filter_set(&(pm->phs.sq[3]), dValue); pbar = g_hash_table_lookup(pm->pht_Status, "HBar3"); pbar->d_value = dValue; g_snprintf(pbar->c_text, sizeof(pbar->c_text), "%s Battery Charge", pch); w = g_hash_table_lookup(pm->pht_Widgets, "HBar3-Widget"); if (GTK_WIDGET_DRAWABLE(w)) gdk_window_invalidate_rect(w->window, &pbar->rect, FALSE); pch = g_hash_table_lookup(pm->pht_Status, "LOADPCT"); if (pch == NULL) { pch = "n/a"; } dValue = g_strtod(pch, NULL); d_loadpct = dtmp = dValue /= 100.0; gapc_util_point_filter_set(&(pm->phs.sq[1]), dValue); pbar = g_hash_table_lookup(pm->pht_Status, "HBar4"); pbar->d_value = (dValue > 1.0) ? 1.0 : dValue; g_snprintf(pbar->c_text, sizeof(pbar->c_text), "%s", pch); w = g_hash_table_lookup(pm->pht_Widgets, "HBar4-Widget"); if (GTK_WIDGET_DRAWABLE(w)) gdk_window_invalidate_rect(w->window, &pbar->rect, FALSE); pch = g_hash_table_lookup(pm->pht_Status, "TIMELEFT"); if (pch == NULL) { pch = "n/a"; } dValue = g_strtod(pch, NULL); dScale = dValue / (1 - dtmp); dValue /= dScale; gapc_util_point_filter_set(&(pm->phs.sq[2]), dValue); pbar = g_hash_table_lookup(pm->pht_Status, "HBar5"); pbar->d_value = dValue; g_snprintf(pbar->c_text, sizeof(pbar->c_text), "%s Remaining", pch); w = g_hash_table_lookup(pm->pht_Widgets, "HBar5-Widget"); if (GTK_WIDGET_DRAWABLE(w)) gdk_window_invalidate_rect(w->window, &pbar->rect, FALSE); /* * information window update */ win = g_hash_table_lookup(pm->pht_Widgets, "SoftwareInformation"); pch = g_hash_table_lookup(pm->pht_Status, "VERSION"); pch1 = g_hash_table_lookup(pm->pht_Status, "UPSNAME"); pch2 = g_hash_table_lookup(pm->pht_Status, "CABLE"); pch3 = g_hash_table_lookup(pm->pht_Status, "UPSMODE"); pch4 = g_hash_table_lookup(pm->pht_Status, "STARTTIME"); pch5 = g_hash_table_lookup(pm->pht_Status, "STATUS"); g_snprintf(ch_buffer, sizeof(ch_buffer), "" "%s\n%s\n%s\n%s\n%s\n%s" "", (pch != NULL) ? pch : "N/A", (pch1 != NULL) ? pch1 : "N/A", (pch2 != NULL) ? pch2 : "N/A", (pch3 != NULL) ? pch3 : "N/A", (pch4 != NULL) ? pch4 : "N/A", (pch5 != NULL) ? pch5 : "N/A"); gtk_label_set_markup(GTK_LABEL(win), ch_buffer); win = g_hash_table_lookup(pm->pht_Widgets, "PerformanceSummary"); pch = g_hash_table_lookup(pm->pht_Status, "SELFTEST"); pch1 = g_hash_table_lookup(pm->pht_Status, "NUMXFERS"); pch2 = g_hash_table_lookup(pm->pht_Status, "LASTXFER"); pch3 = g_hash_table_lookup(pm->pht_Status, "XONBATT"); pch4 = g_hash_table_lookup(pm->pht_Status, "XOFFBATT"); pch5 = g_hash_table_lookup(pm->pht_Status, "TONBATT"); pch6 = g_hash_table_lookup(pm->pht_Status, "CUMONBATT"); g_snprintf(ch_buffer, sizeof(ch_buffer), "" "%s\n%s\n%s\n%s\n%s\n%s\n%s" "", (pch != NULL) ? pch : "N/A", (pch1 != NULL) ? pch1 : "N/A", (pch2 != NULL) ? pch2 : "N/A", (pch3 != NULL) ? pch3 : "N/A", (pch4 != NULL) ? pch4 : "N/A", (pch5 != NULL) ? pch5 : "N/A", (pch6 != NULL) ? pch6 : "N/A"); gtk_label_set_markup(GTK_LABEL(win), ch_buffer); win = g_hash_table_lookup(pm->pht_Widgets, "ProductInformation"); pch = g_hash_table_lookup(pm->pht_Status, "MODEL"); pch1 = g_hash_table_lookup(pm->pht_Status, "SERIALNO"); pch2 = g_hash_table_lookup(pm->pht_Status, "MANDATE"); pch3 = g_hash_table_lookup(pm->pht_Status, "FIRMWARE"); pch4 = g_hash_table_lookup(pm->pht_Status, "BATTDATE"); pch_watt = g_hash_table_lookup(pm->pht_Status, "NOMPOWER"); if (pch_watt != NULL) { pm->i_watt = g_strtod (pch_watt, NULL); d_watt = d_loadpct * pm->i_watt; } else { d_watt = d_loadpct * pm->i_watt; } g_snprintf(ch_buffer, sizeof(ch_buffer), "" "%s\n%s\n%s\n%s\n%s\n%3.0f of %d" "", (pch != NULL) ? pch : "N/A", (pch1 != NULL) ? pch1 : "N/A", (pch2 != NULL) ? pch2 : "N/A", (pch3 != NULL) ? pch3 : "N/A", (pch4 != NULL) ? pch4 : "N/A", d_watt, pm->i_watt); gtk_label_set_markup(GTK_LABEL(win), ch_buffer); return TRUE; } /* sknet_util_log_msg() * capture the current application related error values * output the composed str only if debug_flag is on */ static void sknet_util_log_msg (gchar * pch_func, gchar * pch_topic, gchar * pch_emsg) { if (lg_graph_debug) { g_print ("%s(%s) msg=%s\n", pch_func, pch_topic, pch_emsg); } return; } /* * Write nbytes to the network. * It may require several writes. */ static gint sknet_net_write_nbytes (GIOChannel * ioc, gchar * ptr, gsize nbytes) { gssize nleft = 0; gsize nwritten = 0; GError *gerror = NULL; GIOStatus ios = 0; gboolean b_eof = TRUE; nleft = nbytes; do { b_eof = FALSE; ios = g_io_channel_write_chars (ioc, ptr, nleft, &nwritten, &gerror); switch (ios) { case G_IO_STATUS_ERROR: sknet_util_log_msg ("sknet_net_write_nbytes", "G_IO_STATUS_ERROR", gerror->message); g_error_free (gerror); return -1; break; case G_IO_STATUS_AGAIN: sknet_util_log_msg ("sknet_net_write_nbytes", "G_IO_STATUS_AGAIN", "retry enabled"); g_usleep (500000); break; case G_IO_STATUS_EOF: sknet_util_log_msg ("sknet_net_write_nbytes", "G_IO_STATUS_EOF", "ok"); return 0; break; case G_IO_STATUS_NORMAL: break; default: sknet_util_log_msg ("sknet_net_write_nbytes", "unknown state", "aborted"); b_eof = TRUE; return 0; break; } nleft -= nwritten; ptr += nwritten; } while ((nleft > 0) && (b_eof != TRUE)); return (nbytes - nleft); } /* * Send a message over the network. The send consists of * two network packets. The first is sends a short containing * the length of the data packet which follows. * Returns number of bytes sent * Returns -1 on error */ static gint sknet_net_send (GIOChannel * ioc, gchar * buff, gsize len) { gint rc = 0; gshort pktsiz = 0; /* send short containing size of data packet */ pktsiz = g_htons ((gshort) len); rc = sknet_net_write_nbytes (ioc, (gchar *) &pktsiz, sizeof (gshort)); if (rc != sizeof (gshort)) { sknet_util_log_msg ("sknet_net_send", "send message size", "failed"); return -1; } /* send data packet */ rc = sknet_net_write_nbytes (ioc, buff, len); if (rc != len) { sknet_util_log_msg ("sknet_net_send", "send message buffer", "failed"); return -1; } return rc; } /* * Read nbytes from the network. * It is possible that the total bytes requires several * read requests, which will happen automatically. * Returns: count of bytes read, or -1 for error */ static gint sknet_net_read_nbytes (GIOChannel * ioc, gchar * ptr, gsize nbytes) { gsize nleft = 0; gsize nread = 0; GError *gerror = NULL; GIOStatus ios = 0; gboolean b_eof = FALSE; nleft = nbytes; do { b_eof = FALSE; ios = g_io_channel_read_chars (ioc, ptr, nleft, &nread, &gerror); switch (ios) { case G_IO_STATUS_ERROR: sknet_util_log_msg ("sknet_net_read_nbytes", "G_IO_STATUS_ERROR", gerror->message); g_error_free (gerror); return -1; break; case G_IO_STATUS_AGAIN: sknet_util_log_msg ("sknet_net_read_nbytes", "G_IO_STATUS_AGAIN", "aborted"); g_usleep (500000); break; case G_IO_STATUS_EOF: sknet_util_log_msg ("sknet_net_read_nbytes", "G_IO_STATUS_EOF", "ok"); return 0; break; case G_IO_STATUS_NORMAL: break; default: sknet_util_log_msg ("sknet_net_read_nbytes", "unknown state", "aborted"); b_eof = TRUE; return 0; break; } nleft -= nread; ptr += nread; } while ((nleft > 0) && (b_eof != TRUE)); return (nbytes - nleft); /* return >= 0 */ } /* * Receive a message from the other end. Each message consists of * two packets. The first is a header that contains the size * of the data that follows in the second packet. * Returns number of bytes read * Returns 0 on end of file * Returns -1 on hard end of file (i.e. network connection close) * Returns -2 on error */ static gint sknet_net_recv (GIOChannel * ioc, gchar * buff, gsize maxlen) { gint nbytes = 0; gshort pktsiz = 0; /* get data size -- in short */ nbytes = sknet_net_read_nbytes (ioc, (gchar *) &pktsiz, sizeof (gshort)); if (nbytes <= 0) { sknet_util_log_msg ("sknet_net_recv", "read msg_len", "failed"); return -1; /* assume hard EOF received */ } if (nbytes != sizeof (gshort)) { sknet_util_log_msg ("sknet_net_recv", "read short_len", "failed"); return -2; } pktsiz = g_ntohs (pktsiz); /* decode no. of bytes that follow */ if (pktsiz > maxlen) { sknet_util_log_msg ("sknet_net_recv", "msg_len gt buffer", "overflow"); return -2; } if (pktsiz == 0) { sknet_util_log_msg ("sknet_net_recv", "Soft error", "End-of-File"); return 0; /* soft EOF */ } /* now read the actual data */ nbytes = sknet_net_read_nbytes (ioc, buff, pktsiz); if (nbytes <= 0) { sknet_util_log_msg ("sknet_net_recv", "read message", "failed"); return -2; } if (nbytes != pktsiz) { sknet_util_log_msg ("sknet_net_recv", "read incomplete", "length error"); return -2; } return (nbytes); /* return actual length of message */ } /* sknet_net_close() * Close the active or error'ed socket */ static void sknet_net_close (GIOChannel *ioc, gboolean b_flush) { int sockfd =0; GError *gerror = NULL; GIOStatus ios = G_IO_STATUS_NORMAL; sockfd = g_io_channel_unix_get_fd (ioc); ios = g_io_channel_shutdown (ioc, b_flush, &gerror); if (gerror != NULL) { sknet_util_log_msg ("sknet_channel_close", "error", gerror->message); g_error_free (gerror); } if (ios != G_IO_STATUS_NORMAL) { g_message ("net_close: g_io_channel_shutdown(%d) failed with %d", sockfd, ios); } g_io_channel_unref (ioc); return; } /* * Open a TCP connection using GIOChannels to a host * Returns NULL on error, with err text in ch_error_message * Returns GIOChannel ptr otherwise * Affects: -psk->gip, which is a sockaddr_in address of partner host * this value is allocated and retained for the life of this program * -psk->b_network_control, if true causes the addr to be resolved again * or if false, it uses the current value - saving a dns hit/query */ static GIOChannel *sknet_net_open (PSKCOMM psk) { GIOChannel *ioc = NULL; int sockfd; struct sockaddr_in *tcp_serv_addr = NULL; gint nrc = 0; g_return_val_if_fail (psk != NULL, NULL); /* * Allocate a new address struct if it does not exist */ if (psk->gip == NULL) { psk->b_network_control=TRUE; psk->gip = g_new0( struct sockaddr_in , 1); g_return_val_if_fail (psk->gip != NULL, NULL); tcp_serv_addr = (struct sockaddr_in *)psk->gip; } else { tcp_serv_addr = (struct sockaddr_in *)psk->gip; } /* * Fill in the structure serv_addr with the address of * the server that we want to connect with. */ if ( psk->b_network_control ) { memset ((char *)tcp_serv_addr, 0, sizeof (struct sockaddr_in)); tcp_serv_addr->sin_family = AF_INET; tcp_serv_addr->sin_port = g_htons (psk->i_port); nrc = inet_aton (psk->ch_ip_string, (struct in_addr *)&tcp_serv_addr->sin_addr.s_addr); if ( nrc == 0) /* inet_aton failed */ { struct hostent he, *phe; char *buff; size_t bufflen = 0; phe = gethostname_re(psk->ch_ip_string, &he, &buff, &bufflen); if (phe == NULL) { free(buff); sknet_util_log_msg ("sknet_net_open", "gethostbyname() failed", ""); g_snprintf(psk->ch_error_msg, sizeof(psk->ch_error_msg), "gethostbyname() failed"); psk->ioc = NULL; return NULL; } if (he.h_length != sizeof (struct in_addr) || he.h_addrtype != AF_INET) { free(buff); sknet_util_log_msg ("sknet_net_open", "struct hostent", "argument error"); g_snprintf(psk->ch_error_msg, sizeof(psk->ch_error_msg),"%s","argument error"); psk->ioc = NULL; return NULL; } tcp_serv_addr->sin_addr.s_addr = *(unsigned int *) he.h_addr; free(buff); } /* end if inet_addr */ } /* end if b_network */ /* Open a TCP socket */ if ((sockfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { sknet_util_log_msg ("sknet_net_open", "socket() api failed", (gchar *) g_strerror (errno)); g_snprintf(psk->ch_error_msg, sizeof(psk->ch_error_msg),"%s", (gchar *) g_strerror (errno)); psk->ioc = NULL; return NULL; } { struct timeval tv; int rcx = 0; tv.tv_sec = 0; tv.tv_usec = 200000; rcx = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO | SO_SNDTIMEO, &tv, (socklen_t) sizeof(struct timeval)); if (rcx == -1) { sknet_util_log_msg ("sknet_net_open", "setsockopt(200ms) failed!", (gchar *) g_strerror (errno)); } } /* connect to server */ if ((connect (sockfd, (struct sockaddr *) tcp_serv_addr, sizeof (struct sockaddr_in))) == -1) { sknet_util_log_msg ("sknet_net_open", "connect() api failed", (gchar *) g_strerror (errno)); g_snprintf(psk->ch_error_msg, sizeof(psk->ch_error_msg),"%s", (gchar *) g_strerror (errno)); close (sockfd); psk->b_network_control = TRUE; psk->ioc = NULL; return NULL; } psk->b_network_control = FALSE; ioc = g_io_channel_unix_new (sockfd); g_io_channel_set_encoding (ioc, NULL, NULL); g_io_channel_set_buffered (ioc, FALSE); psk->ioc = ioc; return ioc; } /* sknet_net_client_init() * Create a control structure and set ip values * for an open call. * return NULL on error. */ static PSKCOMM sknet_net_client_init (gchar *pch_remote_ip, gint i_remote_port) { PSKCOMM psk = NULL; psk = g_new0(SKNET_COMMS, 1); g_return_val_if_fail(psk != NULL, NULL); psk->gp_reserved = NULL; psk->cb_id = 0; /* initialize count of instances created */ g_snprintf( psk->ch_ip_string, sizeof(psk->ch_ip_string), "%s", pch_remote_ip); psk->i_port = i_remote_port; psk->b_network_control = TRUE; g_snprintf (psk->ch_error_msg, sizeof (psk->ch_error_msg), "client init(client ready to connect to %s:%6d", psk->ch_ip_string, psk->i_port); sknet_util_log_msg ("sknet_net_client_init", psk->ch_error_msg, "Ready"); return psk; } /* * Close server socket if open and release internal storage */ static void sknet_net_shutdown (PSKCOMM psk) { g_return_if_fail (psk != NULL); if (psk->gp_reserved != NULL) { ((PSKCOMM)psk->gp_reserved)->cb_id--; /* decrement count of instances created */ } else { /* or close main socket */ if (psk->fd_server) { close (psk->fd_server); } } if (psk->gip != NULL) { g_free(psk->gip); } g_free(psk); return; } /* * performs a complete NIS transaction by sending cmd and * loading each result line into the pch array. * also, refreshes status key/value pairs in hastable. * return error = 0, or number of lines read from network */ static gint gapc_net_transaction_service(PGAPC_MONITOR pm, gchar * cp_cmd, gchar ** pch) { gint n = 0, iflag = 0; GIOChannel *ioc = NULL; g_return_val_if_fail(pm, -1); g_return_val_if_fail(pm->psk, -1); g_return_val_if_fail(pm->pch_host, -1); ioc = sknet_net_open(pm->psk); if (ioc == NULL) { return 0; } n = sknet_net_send( ioc, cp_cmd, g_utf8_strlen(cp_cmd, -1)); if (n <= 0) { sknet_net_close( ioc, TRUE); return 0; } /* clear current data */ for (iflag = 0; iflag < GAPC_MAX_ARRAY; iflag++) { if (pch[iflag] != NULL) { g_free(pch[iflag]); } pch[iflag] = NULL; } iflag = 0; while (iflag < GAPC_MAX_ARRAY) { n = sknet_net_recv(ioc, pm->psk->ch_session_message, sizeof(pm->psk->ch_session_message)); if (n < 1) break; pm->psk->ch_session_message[n] = 0; pch[iflag++] = g_strdup(pm->psk->ch_session_message); if (g_str_equal(cp_cmd, "status") && iflag > 1) gapc_util_update_hashtable(pm, pm->psk->ch_session_message); } sknet_net_close(ioc, TRUE); return iflag; /* count of records received */ } /* * Worker thread for network communications. */ static gpointer *gapc_net_thread_qwork(PGAPC_MONITOR pm) { gint rc = 0; GAsyncQueue *thread_queue = NULL; g_return_val_if_fail(pm != NULL, NULL); g_return_val_if_fail(pm->q_network != NULL, NULL); g_async_queue_ref(pm->q_network); thread_queue = pm->q_network; if (pm->psk == NULL) { pm->psk = sknet_net_client_init (pm->pch_host, pm->i_port); if (pm->psk == NULL) { g_async_queue_unref(thread_queue); g_thread_exit(GINT_TO_POINTER(0)); } } while ((pm = (PGAPC_MONITOR) g_async_queue_pop(thread_queue))) { if (pm->b_thread_stop) { break; } if (pm->b_run) { g_mutex_lock(pm->gm_update); if (!pm->b_run) { /* may have waited a while for lock */ g_mutex_unlock(pm->gm_update); continue; } if ((rc = gapc_net_transaction_service(pm, "status", pm->pach_status))) { gapc_net_transaction_service(pm, "events", pm->pach_events); } g_mutex_unlock(pm->gm_update); if (rc > 0) { pm->b_data_available = TRUE; } else { pm->b_data_available = FALSE; } } else { pm->b_data_available = FALSE; } } /* end-while */ if (pm->psk != NULL) { sknet_net_shutdown (pm->psk); pm->psk = NULL; } g_async_queue_unref(thread_queue); g_thread_exit(GINT_TO_POINTER(1)); return NULL; } /* * return the answer and reset the internal controls to zero */ static gdouble gapc_util_point_filter_reset(PGAPC_SUMS sq) { gdouble d_the_final_answer = 0.0; g_mutex_lock(sq->gm_graph); d_the_final_answer = sq->last_answer; sq->point_count = 0; sq->this_point = 0.0; sq->last_point = 0.0; sq->this_answer = 0.0; sq->last_answer = 0.0; sq->answer_summ = 0.0; sq->point_min = 0.0; sq->point_max = 0.0; g_mutex_unlock(sq->gm_graph); return (d_the_final_answer); } /* * Compute the average of the given data point */ static gdouble gapc_util_point_filter_set(PGAPC_SUMS sq, gdouble this_point) { g_mutex_lock(sq->gm_graph); sq->this_point = this_point; sq->this_point *= 100; sq->point_count++; /* some calc here */ sq->answer_summ += sq->this_point ; sq->this_answer = sq->answer_summ / sq->point_count; sq->last_point = sq->this_point; sq->last_answer = sq->this_answer; if (sq->point_min > sq->this_point) sq->point_min = sq->this_point; if (sq->point_max < sq->this_point) sq->point_max = sq->this_point; g_mutex_unlock(sq->gm_graph); return (sq->this_answer); } /* * Get a iter to the list_store record containing this monitor key. * Will search either list_store * - monitor col is the same in both models * Returns: TRUE and iter is found, FALSE and invalid iter if not found */ static gboolean gapc_util_treeview_get_iter_from_monitor(GtkTreeModel * model, GtkTreeIter * iter, gint i_value) { gboolean valid = FALSE, b_result = FALSE; gint i_monitor; g_return_val_if_fail(model != NULL, FALSE); g_return_val_if_fail(iter != NULL, FALSE); valid = gtk_tree_model_get_iter_first(model, iter); while (valid) { gtk_tree_model_get(model, iter, GAPC_PREFS_MONITOR, &i_monitor, -1); if (i_monitor == i_value) { /* set sucess flag */ b_result = TRUE; break; } valid = gtk_tree_model_iter_next(model, iter); } return b_result; } /* * Add a preferences record to the gconf instance and prefs_model * returns FALSE on error * returns TRUE on sucess */ static gboolean gapc_panel_preferences_gconf_add_rec(PGAPC_CONFIG pcfg, gint i_monitor) { GAPC_PKEYS pk; gchar *pkey = NULL; g_return_val_if_fail(pcfg != NULL, FALSE); g_return_val_if_fail(pcfg->client != NULL, FALSE); g_return_val_if_fail(pcfg->prefs_model != NULL, FALSE); pkey = GAPC_MID_GROUP_KEY; g_snprintf(pk.k_enabled, GAPC_MAX_TEXT, "%s/%d/%s", pkey, i_monitor, "enabled"); g_snprintf(pk.k_use_systray, GAPC_MAX_TEXT, "%s/%d/%s", pkey, i_monitor, "use_systray"); g_snprintf(pk.k_port_number, GAPC_MAX_TEXT, "%s/%d/%s", pkey, i_monitor, "port_number"); g_snprintf(pk.k_network_interval, GAPC_MAX_TEXT, "%s/%d/%s", pkey, i_monitor, "network_interval"); g_snprintf(pk.k_graph_interval, GAPC_MAX_TEXT, "%s/%d/%s", pkey, i_monitor, "graph_interval"); g_snprintf(pk.k_host_name, GAPC_MAX_TEXT, "%s/%d/%s", pkey, i_monitor, "host_name"); g_snprintf(pk.v_host_name, GAPC_MAX_TEXT, "%s", GAPC_HOST_DEFAULT); gconf_client_set_bool(pcfg->client, pk.k_enabled, FALSE, NULL); gconf_client_set_bool(pcfg->client, pk.k_use_systray, FALSE, NULL); gconf_client_set_int(pcfg->client, pk.k_port_number, GAPC_PORT_DEFAULT, NULL); gconf_client_set_float(pcfg->client, pk.k_network_interval, GAPC_REFRESH_DEFAULT, NULL); gconf_client_set_float(pcfg->client, pk.k_graph_interval, GAPC_LINEGRAPH_REFRESH_FACTOR, NULL); gconf_client_set_string(pcfg->client, pk.k_host_name, pk.v_host_name, NULL); return TRUE; } /* * capture the current application related error values centrally */ static void gapc_util_log_app_msg(gchar * pch_func, gchar * pch_topic, gchar * pch_emsg) { gchar *pch = NULL; g_return_if_fail(pch_func != NULL); pch = g_strdup_printf("%s(%s) emsg=%s", pch_func, pch_topic, pch_emsg); g_message(pch); g_free(pch); return; } /* * parses received line of text into key/value pairs to be inserted * into the status hashtable. */ static gint gapc_util_update_hashtable(PGAPC_MONITOR pm, gchar * pch_unparsed) { gchar *pch_in = NULL; gchar *pch = NULL; gchar *pch_end = NULL; gint ilen = 0; g_return_val_if_fail(pm != NULL, FALSE); g_return_val_if_fail(pch_unparsed != NULL, -1); /* unparsed contains - keystring : keyvalue nl */ pch_in = g_strdup(pch_unparsed); pch_end = g_strrstr(pch_in, "\n"); if (pch_end != NULL) *pch_end = 0; ilen = g_utf8_strlen(pch_in, -1); pch = g_strstr_len(pch_in, ilen, ":"); *pch = 0; pch_in = g_strchomp(pch_in); pch++; pch = g_strstrip(pch); g_hash_table_replace(pm->pht_Status, g_strdup(pch_in), g_strdup(pch)); g_free(pch_in); return ilen; } /* * Implements a Horizontal Bar Chart... * - data value has a range of 0.0 to 1.0 for 0-100% display * - in chart text is limited to about 30 chars */ static gboolean cb_util_barchart_handle_exposed(GtkWidget * widget, GdkEventExpose * event, gpointer data) { PGAPC_BAR_H pbar = data; gint i_percent = 0; PangoLayout *playout = NULL; g_return_val_if_fail(data, FALSE); /* error exit */ pbar->rect.x = 0; pbar->rect.y = 0; pbar->rect.width = widget->allocation.width; pbar->rect.height = widget->allocation.height; /* scale up the less than zero data value */ i_percent = (gint) ((gdouble) (widget->allocation.width / 100.0) * (gdouble) (pbar->d_value * 100.0)); /* the frame of the chart */ gtk_paint_box(widget->style, widget->window, GTK_WIDGET_STATE(widget), GTK_SHADOW_ETCHED_IN, &pbar->rect, widget, "gapc_hbar_frame", 0, 0, widget->allocation.width - 1, widget->allocation.height - 1); /* the scaled value */ gtk_paint_box(widget->style, widget->window, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, &pbar->rect, widget, "gapc_hbar_value", 1, 1, i_percent, widget->allocation.height - 4); if (pbar->c_text[0]) { gint x = 0, y = 0; playout = gtk_widget_create_pango_layout(widget, pbar->c_text); pango_layout_set_markup(playout, pbar->c_text, -1); pango_layout_get_pixel_size(playout, &x, &y); x = (widget->allocation.width - x) / 2; y = (widget->allocation.height - y) / 2; gtk_paint_layout(widget->style, widget->window, GTK_STATE_NORMAL, TRUE, &pbar->rect, widget, "gapc_hbar_text", (pbar->b_center_text) ? x : 6, y, playout); g_object_unref(playout); } return TRUE; } /* * creates horizontal bar chart and allocates control data * requires cb_h_bar_chart_exposed() routine * return drawing area widget */ static GtkWidget *gapc_util_barchart_create(PGAPC_MONITOR pm, GtkWidget * vbox, gchar * pch_hbar_name, gdouble d_percent, gchar * pch_text) { PGAPC_BAR_H pbar = NULL; GtkWidget *drawing_area = NULL; gchar *pch = NULL; g_return_val_if_fail(pm != NULL, NULL); pbar = g_new0(GAPC_BAR_H, 1); pbar->d_value = d_percent; pbar->b_center_text = FALSE; g_strlcpy(pbar->c_text, pch_text, sizeof(pbar->c_text)); drawing_area = gtk_drawing_area_new(); /* manual bargraph */ gtk_widget_set_size_request(drawing_area, 100, 20); g_signal_connect(G_OBJECT(drawing_area), "expose_event", G_CALLBACK(cb_util_barchart_handle_exposed), (gpointer) pbar); gtk_box_pack_start(GTK_BOX(vbox), drawing_area, TRUE, TRUE, 0); gtk_widget_show(drawing_area); g_hash_table_insert(pm->pht_Status, g_strdup(pch_hbar_name), pbar); pch = g_strdup_printf("%s-Widget", pch_hbar_name); g_hash_table_insert(pm->pht_Widgets, pch, drawing_area); return drawing_area; } /* * Utility Routines for text views */ static gboolean gapc_util_text_view_clear_buffer(GtkWidget * view) { GtkTextIter start, end; GtkTextBuffer *buffer = NULL; g_return_val_if_fail(view != NULL, TRUE); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); gtk_text_buffer_get_bounds(buffer, &start, &end); gtk_text_buffer_delete(buffer, &start, &end); return FALSE; } /* * Utility Routines for text views */ static void gapc_util_text_view_prepend(GtkWidget * view, gchar * pch) { GtkTextIter iter; GtkTextBuffer *buffer; g_return_if_fail(view != NULL); g_return_if_fail(pch != NULL); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); gtk_text_buffer_get_start_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, pch, -1); } /* * Utility Routines for text views */ static void gapc_util_text_view_append(GtkWidget * view, gchar * pch) { GtkTextIter iter; GtkTextBuffer *buffer; g_return_if_fail(view != NULL); g_return_if_fail(pch != NULL); buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view)); gtk_text_buffer_get_end_iter(buffer, &iter); gtk_text_buffer_insert(buffer, &iter, pch, -1); } static gint gapc_panel_monitor_model_rec_add(PGAPC_CONFIG pcfg, PGAPC_MONITOR pm) { GtkTreeIter iter; gchar *pch = NULL; g_return_val_if_fail(pcfg != NULL, -1); g_return_val_if_fail(pm != NULL, -1); g_return_val_if_fail(pcfg->monitor_model != NULL, -1); g_return_val_if_fail(pcfg->monitor_select != NULL, -1); gtk_list_store_append(GTK_LIST_STORE(pcfg->monitor_model), &iter); pch = g_hash_table_lookup(pm->pht_Status, "STATUS"); if (pch == NULL) { pch = "Starting"; } gtk_list_store_set(GTK_LIST_STORE(pcfg->monitor_model), &iter, GAPC_MON_ICON, pm->my_icons[pm->i_icon_index], GAPC_MON_STATUS, pm->ch_title_info, GAPC_MON_MONITOR, pm->cb_monitor_num, GAPC_MON_POINTER, (gpointer) pm, GAPC_MON_UPSSTATE, g_strdup(pch), -1); gtk_tree_selection_select_iter(pcfg->monitor_select, &iter); return TRUE; } static gint gapc_panel_preferences_model_rec_remove(PGAPC_CONFIG pcfg) { GtkTreeIter iter, *piter = NULL; gboolean result = FALSE; gint i_monitor = 0; gchar ch[GAPC_MAX_TEXT]; gchar chk[GAPC_MAX_TEXT]; GError *gerror = NULL; g_return_val_if_fail(pcfg != NULL, -1); g_return_val_if_fail(pcfg->prefs_model != NULL, -1); if (gtk_tree_selection_get_selected(pcfg->prefs_select, NULL, &iter)) { piter = gtk_tree_iter_copy(&iter); if (gtk_tree_model_iter_next(GTK_TREE_MODEL(pcfg->prefs_model), piter)) { gtk_tree_selection_select_iter(pcfg->prefs_select, piter); } gtk_tree_iter_free(piter); gtk_tree_model_get(GTK_TREE_MODEL(pcfg->prefs_model), &iter, GAPC_PREFS_MONITOR, &i_monitor, -1); /* now remove the record from gconf */ g_snprintf(ch, GAPC_MAX_TEXT, "%s/%d", GAPC_MID_GROUP_KEY, i_monitor); gconf_client_unset(pcfg->client, ch, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_preferences_model_rec_remove()", "gconf_client_unset(DIR) Failed", gerror->message); g_error_free(gerror); gerror = NULL; } gconf_client_suggest_sync(pcfg->client, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_preferences_model_rec_remove()", "gconf_client_suggest_sync() Failed", gerror->message); g_error_free(gerror); gerror = NULL; } g_snprintf(chk, GAPC_MAX_TEXT, "%s/%s", ch, "enabled"); gconf_client_unset(pcfg->client, chk, NULL); g_snprintf(chk, GAPC_MAX_TEXT, "%s/%s", ch, "use_systray"); gconf_client_unset(pcfg->client, chk, NULL); g_snprintf(chk, GAPC_MAX_TEXT, "%s/%s", ch, "skip_pagers"); gconf_client_unset(pcfg->client, chk, NULL); g_snprintf(chk, GAPC_MAX_TEXT, "%s/%s", ch, "port_number"); gconf_client_unset(pcfg->client, chk, NULL); g_snprintf(chk, GAPC_MAX_TEXT, "%s/%s", ch, "network_interval"); gconf_client_unset(pcfg->client, chk, NULL); g_snprintf(chk, GAPC_MAX_TEXT, "%s/%s", ch, "graph_interval"); gconf_client_unset(pcfg->client, chk, NULL); g_snprintf(chk, GAPC_MAX_TEXT, "%s/%s", ch, "host_name"); gconf_client_unset(pcfg->client, chk, NULL); gconf_client_unset(pcfg->client, ch, &gerror); /* again to drop it in gconf */ if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_preferences_model_rec_remove()", "gconf_client_unset(DIR) Failed", gerror->message); g_error_free(gerror); gerror = NULL; } gconf_client_suggest_sync(pcfg->client, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_preferences_model_rec_remove()", "gconf_client_suggest_sync() Failed", gerror->message); g_error_free(gerror); gerror = NULL; } } return result; } static gint gapc_panel_preferences_model_rec_add(PGAPC_CONFIG pcfg) { g_return_val_if_fail(pcfg != NULL, -1); g_return_val_if_fail(pcfg->prefs_model != NULL, -1); g_return_val_if_fail(pcfg->prefs_select != NULL, -1); gapc_panel_preferences_gconf_add_rec(pcfg, ++pcfg->prefs_last_monitor); return TRUE; } /* * EggTrayIcon Callbacks */ static void cb_panel_systray_icon_activated(GtkPlug * plug, gpointer gp) { PGAPC_CONFIG pcfg = NULL; PGAPC_MONITOR pm = NULL; g_return_if_fail(plug != NULL); g_return_if_fail(gp != NULL); if (((PGAPC_MONITOR) gp)->cb_id == CB_MONITOR_ID) { /* this is a monitor struct (2) */ pm = (PGAPC_MONITOR) gp; if (pm->window != NULL) { g_object_set(pm->window, "skip-pager-hint", TRUE, "skip-taskbar-hint", TRUE, NULL); } } else { /* this is a config struct (1) */ pcfg = (PGAPC_CONFIG) gp; if (pcfg->window != NULL) { g_object_set(pcfg->window, "skip-pager-hint", TRUE, "skip-taskbar-hint", TRUE, NULL); } } return; } static gboolean cb_panel_systray_icon_configure(GtkWidget * widget, GdkEventConfigure * event, gpointer gp) { PGAPC_CONFIG pcfg = NULL; PGAPC_MONITOR pm = NULL; gint *pi_icon_size = NULL; g_return_val_if_fail(gp != NULL, FALSE); g_return_val_if_fail(event != NULL, FALSE); if (((PGAPC_MONITOR) gp)->cb_id == CB_MONITOR_ID) { /* this is a monitor struct (2) */ pm = (PGAPC_MONITOR) gp; pi_icon_size = &pm->i_icon_size; pm->i_icon_height = event->height; pm->i_icon_width = event->width; } else { /* this is a config struct (1) */ pcfg = (PGAPC_CONFIG) gp; pi_icon_size = &pcfg->i_icon_size; pcfg->i_icon_height = event->height; pcfg->i_icon_width = event->width; } *pi_icon_size = MIN(event->width, event->height); return FALSE; } static gboolean cb_panel_systray_icon_handle_clicked(GtkWidget * widget, GdkEventButton * event, gpointer gp) { PGAPC_CONFIG pcfg = NULL; PGAPC_MONITOR pm = NULL; GtkWidget *window = NULL; gboolean b_visible = FALSE; GtkWidget *menu = NULL; g_return_val_if_fail(gp != NULL, FALSE); g_return_val_if_fail(widget != NULL, FALSE); if (((PGAPC_MONITOR) gp)->cb_id == CB_MONITOR_ID) { /* this is a monitor struct (2) */ pm = (PGAPC_MONITOR) gp; window = pm->window; b_visible = pm->b_visible; menu = pm->menu; } else { /* this is a config struct (1) */ pcfg = (PGAPC_CONFIG) gp; window = pcfg->window; b_visible = pcfg->b_visible; menu = pcfg->menu; } if (window == NULL) { return FALSE; } if (event->type == GDK_BUTTON_PRESS) { switch (event->button) { case 1: if (b_visible) { gtk_widget_hide(GTK_WIDGET(window)); } else { gtk_window_present(GTK_WINDOW(window)); } break; case 2: case 3: if (menu != NULL) { gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, event->button, event->time); } break; default: return FALSE; } return TRUE; } return FALSE; } static void cb_panel_systray_icon_destroy(GtkObject * object, gpointer gp) { PGAPC_CONFIG pcfg = NULL; PGAPC_MONITOR pm = NULL; g_return_if_fail(gp != NULL); if (((PGAPC_MONITOR) gp)->cb_id == CB_MONITOR_ID) { /* this is a monitor struct (2) */ pm = (PGAPC_MONITOR) gp; pm->tray_icon = NULL; pm->tray_image = NULL; if (pm->b_run && (pm->window != NULL)) { g_object_set(pm->window, "skip-pager-hint", FALSE, "skip-taskbar-hint", FALSE, NULL); gtk_window_present(GTK_WINDOW(pm->window)); } } else { /* this is a config struct (1) */ pcfg = (PGAPC_CONFIG) gp; pcfg->tray_icon = NULL; pcfg->tray_image = NULL; if (pcfg->b_run && (pcfg->window != NULL)) { g_object_set(pcfg->window, "skip-pager-hint", FALSE, "skip-taskbar-hint", FALSE, NULL); gtk_window_present(GTK_WINDOW(pcfg->window)); } } return; } static gboolean gapc_panel_systray_icon_create(gpointer gp) { PGAPC_CONFIG pcfg = NULL; PGAPC_MONITOR pm = NULL; EggTrayIcon **tray_icon = NULL; GtkWidget **tray_image = NULL; GdkPixbuf *pixbuf = NULL; GtkTooltips *tooltips = NULL; gchar *pch_title = NULL; g_return_val_if_fail(gp != NULL, FALSE); if (((PGAPC_MONITOR) gp)->cb_id == CB_MONITOR_ID) { /* this is a monitor struct (2) */ pm = (PGAPC_MONITOR) gp; tray_icon = &pm->tray_icon; tray_image = &pm->tray_image; tooltips = pm->tooltips; pixbuf = pm->my_icons[GAPC_ICON_DEFAULT]; if (!pm->cb_use_systray) { return FALSE; } pch_title = pm->ch_title_info; } else { /* this is a config struct (1) */ pcfg = (PGAPC_CONFIG) gp; tray_icon = &pcfg->tray_icon; tray_image = &pcfg->tray_image; tooltips = pcfg->tooltips; pixbuf = pcfg->my_icons[GAPC_ICON_DEFAULT]; pch_title = GAPC_WINDOW_TITLE; if (!pcfg->b_use_systray) { return FALSE; } } g_return_val_if_fail(*tray_icon == NULL, FALSE); g_return_val_if_fail(*tray_image == NULL, FALSE); *tray_icon = egg_tray_icon_new(pch_title); g_return_val_if_fail(*tray_icon != NULL, FALSE); g_signal_connect(*tray_icon, "embedded", G_CALLBACK(cb_panel_systray_icon_activated), gp); g_signal_connect(*tray_icon, "destroy", G_CALLBACK(cb_panel_systray_icon_destroy), gp); g_signal_connect(*tray_icon, "configure-event", G_CALLBACK(cb_panel_systray_icon_configure), gp); g_signal_connect(*tray_icon, "button-press-event", G_CALLBACK(cb_panel_systray_icon_handle_clicked), gp); *tray_image = gtk_image_new_from_pixbuf(pixbuf); gtk_container_add(GTK_CONTAINER(*tray_icon), *tray_image); gtk_widget_show(*tray_image); gtk_widget_show_all(GTK_WIDGET(*tray_icon)); if (tooltips != NULL) { gtk_tooltips_set_tip(tooltips, GTK_WIDGET(*tray_icon), pch_title, NULL); } return TRUE; } static gboolean gapc_panel_systray_icon_remove(gpointer gp) { PGAPC_CONFIG pcfg = NULL; PGAPC_MONITOR pm = NULL; EggTrayIcon **tray_icon = NULL; GtkWidget **tray_image = NULL; g_return_val_if_fail(gp != NULL, FALSE); if (((PGAPC_MONITOR) gp)->cb_id == CB_MONITOR_ID) { /* this is a monitor struct (2) */ pm = (PGAPC_MONITOR) gp; tray_icon = &pm->tray_icon; tray_image = &pm->tray_image; } else { /* this is a config struct (1) */ pcfg = (PGAPC_CONFIG) gp; tray_icon = &pcfg->tray_icon; tray_image = &pcfg->tray_image; } g_return_val_if_fail(*tray_icon != NULL, FALSE); g_return_val_if_fail(*tray_image != NULL, FALSE); gtk_widget_destroy(*tray_image); gtk_widget_destroy(GTK_WIDGET(*tray_icon)); return TRUE; } /* * Handle the prefs add record button action */ static void cb_panel_prefs_button_add_rec(GtkWidget * button, PGAPC_CONFIG pcfg) { g_return_if_fail(pcfg != NULL); gapc_panel_preferences_model_rec_add(pcfg); return; } /* * Handle the prefs remove record button action */ static void cb_panel_prefs_button_remove_rec(GtkWidget * button, PGAPC_CONFIG pcfg) { g_return_if_fail(pcfg != NULL); gapc_panel_preferences_model_rec_remove(pcfg); return; } /* * Handle the prefs use-systray checkbutton action */ static void cb_panel_prefs_button_use_systray(GtkWidget * button, PGAPC_CONFIG pcfg) { gboolean b_value = FALSE; gchar *pch = NULL; g_return_if_fail(pcfg != NULL); if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))) { b_value = TRUE; } else { b_value = FALSE; } pch = pcfg->pch_gkeys[GAPC_PREFS_SYSTRAY]; gconf_client_set_bool(pcfg->client, pch, b_value, NULL); return; } /* * Handled the toggle of a checkbox in the preferences dialog * Could be: * enabled - enabled this monitor to run * systray - include the notification tray icon * pagers - remove from task_list and pager_list */ static void cb_panel_prefs_handle_cell_toggled(GtkCellRendererToggle * cell, gchar * path_str, PGAPC_PREFS_COLUMN pcolumn) { GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path = NULL; gboolean b_value; gint col_number = 0, i_monitor = 0; gchar *penabled = NULL; g_return_if_fail(pcolumn != NULL); g_return_if_fail(path_str != NULL); model = pcolumn->prefs_model; col_number = pcolumn->i_col_num; /* get toggled iter */ path = gtk_tree_path_new_from_string(path_str); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_path_free(path); /* get the column id they asked for -- hope its boolean */ gtk_tree_model_get(model, &iter, col_number, &b_value, GAPC_PREFS_MONITOR, &i_monitor, -1); /* do something with the value */ b_value ^= 1; switch (col_number) { case GAPC_PREFS_ENABLED: penabled = g_strdup_printf(GAPC_ENABLE_KEY, i_monitor); gconf_client_set_bool(pcolumn->client, penabled, b_value, NULL); g_free(penabled); break; case GAPC_PREFS_SYSTRAY: penabled = g_strdup_printf(GAPC_SYSTRAY_KEY, i_monitor); gconf_client_set_bool(pcolumn->client, penabled, b_value, NULL); g_free(penabled); break; default: g_message("Cell_Toggled:Unknown key for Value(%s)\n", b_value ? "True" : "False"); break; } return; } /* * A callback routine that collect changes to the path row and save it directly * to the desired location, also passes it back to the treeview for display. * These data point use this routine. * - Host * - Port * - Graph refresh * - Network refresh * - Monitor - not a visible field * We update gconf here and gconf updates the * list_store in cb_panel_preference_gconf_changed() */ static void cb_panel_prefs_handle_cell_edited(GtkCellRendererText * cell, gchar * path_string, gchar * pch_new, PGAPC_PREFS_COLUMN pcolumn) { GtkTreeModel *model; GtkTreeIter iter; GtkTreePath *path; gint col_number = 0, i_port = 0, i_monitor = 0, i_len = 0; gfloat f_refresh = 0.0, f_graph = 0.0; gchar ch[GAPC_MAX_TEXT], *pch = NULL; gboolean b_dupped = FALSE; g_return_if_fail(pcolumn != NULL); g_return_if_fail(pch_new != NULL); g_return_if_fail(path_string != NULL); model = pcolumn->prefs_model; col_number = pcolumn->i_col_num; i_len = g_snprintf(ch, GAPC_MAX_TEXT, "%s", pch_new); /* * get iter to record */ path = gtk_tree_path_new_from_string(path_string); gtk_tree_model_get_iter(model, &iter, path); gtk_tree_path_free(path); /* * get data from that row */ gtk_tree_model_get(model, &iter, GAPC_PREFS_MONITOR, &i_monitor, -1); switch (col_number) { case GAPC_PREFS_HOST: { gchar *phost = g_strdup_printf(GAPC_HOST_KEY, i_monitor); if ((pch_new == NULL) || (i_len < 2)) { pch = g_strdup(GAPC_HOST_DEFAULT); } else { pch = pch_new; b_dupped = TRUE; } gconf_client_set_string(pcolumn->client, phost, pch, NULL); g_free(phost); } break; case GAPC_PREFS_PORT: { gchar *pport = g_strdup_printf(GAPC_PORT_KEY, i_monitor); i_port = (gint) g_strtod(pch_new, NULL); if (i_port == 0) { i_port = GAPC_PORT_DEFAULT; pch = g_strdup_printf("%d", i_port); } else { pch = pch_new; b_dupped = TRUE; } gconf_client_set_int(pcolumn->client, pport, i_port, NULL); g_free(pport); } break; case GAPC_PREFS_WATT: { gchar *pport = g_strdup_printf(GAPC_WATT_KEY, i_monitor); i_port = (gint) g_strtod(pch_new, NULL); if (i_port == 0) { i_port = GAPC_WATT_DEFAULT; pch = g_strdup_printf("%d", i_port); } else { pch = pch_new; b_dupped = TRUE; } gconf_client_set_int(pcolumn->client, pport, i_port, NULL); g_free(pport); } break; case GAPC_PREFS_REFRESH: { gchar *prefresh = g_strdup_printf(GAPC_REFRESH_KEY, i_monitor); f_refresh = (gfloat) g_strtod(pch_new, NULL); if (f_refresh < GAPC_REFRESH_MIN_INCREMENT) { f_refresh = GAPC_REFRESH_DEFAULT; pch = g_strdup_printf("%3.1f", f_refresh); } else { pch = pch_new; b_dupped = TRUE; } gconf_client_set_float(pcolumn->client, prefresh, f_refresh, NULL); g_free(prefresh); } break; case GAPC_PREFS_GRAPH: { gchar *prefresh = g_strdup_printf(GAPC_GRAPH_KEY, i_monitor); f_graph = (gfloat) g_strtod(pch_new, NULL); if (f_graph < GAPC_REFRESH_MIN_INCREMENT) { f_graph = GAPC_LINEGRAPH_REFRESH_FACTOR; pch = g_strdup_printf("%3.1f", f_graph); } else { pch = pch_new; b_dupped = TRUE; } gconf_client_set_float(pcolumn->client, prefresh, f_graph, NULL); g_free(prefresh); } break; default: g_message("Cell_Edited:Unknown key for Value(%s)\n", pch_new); g_object_set(cell, "text", pch_new, NULL); break; } if ((pch != NULL) && !b_dupped) { g_free(pch); } return; } /* * Cell data function used to format floating point numbers * This gets called a thousand times... */ static void cb_panel_prefs_handle_float_format(GtkTreeViewColumn * col, GtkCellRenderer * renderer, GtkTreeModel * model, GtkTreeIter * iter, gpointer gp) { gfloat d_value; gchar buf[32]; guint colnum = 0; gchar *pch_format = NULL; g_return_if_fail(gp != NULL); colnum = GPOINTER_TO_UINT(gp); pch_format = (gchar *) g_object_get_data(G_OBJECT(col), "float_format"); gtk_tree_model_get(model, iter, colnum, &d_value, -1); if (pch_format) { g_snprintf(buf, sizeof(buf), pch_format, d_value); } else { g_snprintf(buf, sizeof(buf), "%3.0f", d_value); } g_object_set(renderer, "text", buf, NULL); return; } /* This routine initializes a user-data structure for use by the renderers of * the preference treeview */ static PGAPC_PREFS_COLUMN gapc_panel_prefs_col_data_init(PGAPC_CONFIG pcfg, GAPC_PrefsType col_num) { PGAPC_PREFS_COLUMN pcol = NULL; pcol = g_new0(GAPC_PREFS_COLUMN, 1); g_return_val_if_fail(pcol != NULL, NULL); pcol->cb_id = CB_COLUMN_ID; pcol->prefs_model = pcfg->prefs_model; pcol->i_col_num = col_num; pcol->client = pcfg->client; return pcol; } /* * Gets the gconf instance preferences for all monitors * and loads the prefs_model. * returns FALSE on error * returns TRUE on sucess */ static gboolean gapc_panel_preferences_data_model_load(PGAPC_CONFIG pcfg) { GError *gerror = NULL; GSList *monitors = NULL; GtkTreeIter iter; gboolean b_valid = FALSE; gboolean v_enabled; gboolean v_use_systray; gint v_port_number; gint v_watt_number; gfloat v_network_interval; gfloat v_graph_interval; gchar *v_host_name; gchar k_enabled[GAPC_MAX_TEXT]; gchar k_use_systray[GAPC_MAX_TEXT]; gchar k_port_number[GAPC_MAX_TEXT]; gchar k_network_interval[GAPC_MAX_TEXT]; gchar k_graph_interval[GAPC_MAX_TEXT]; gchar k_host_name[GAPC_MAX_TEXT]; gchar k_watt_number[GAPC_MAX_TEXT]; g_return_val_if_fail(pcfg != NULL, FALSE); g_return_val_if_fail(pcfg->client != NULL, FALSE); g_return_val_if_fail(pcfg->prefs_model != NULL, FALSE); b_valid = gconf_client_dir_exists(pcfg->client, GAPC_MID_GROUP_KEY, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_preferences_data_model_load", "gconf_dir_exists() Failed", gerror->message); g_error_free(gerror); gerror = NULL; return FALSE; } if (b_valid == FALSE) { gapc_util_log_app_msg("gapc_panel_preferences_data_model_load", "No monitors predefined.", "very first startup"); return FALSE; } monitors = gconf_client_all_dirs(pcfg->client, GAPC_MID_GROUP_KEY, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_preferences_data_model_load", "gconf_client_all_dirs() Failed", gerror->message); g_error_free(gerror); gerror = NULL; return FALSE; } while (monitors) { /* should be the regular text key */ gchar *pmon = NULL; gint i_monitor = 0; GtkWidget *widget = NULL; pmon = g_strrstr((gchar *) monitors->data, "/"); if (pmon) { i_monitor = (gint) g_strtod(pmon + 1, NULL); pcfg->prefs_last_monitor = MAX(pcfg->prefs_last_monitor, i_monitor); } else { g_free(monitors->data); monitors = g_slist_next(monitors); continue; } g_snprintf(k_enabled, GAPC_MAX_TEXT, "%s/%s", (gchar *) monitors->data, "enabled"); g_snprintf(k_use_systray, GAPC_MAX_TEXT, "%s/%s", (gchar *) monitors->data, "use_systray"); g_snprintf(k_port_number, GAPC_MAX_TEXT, "%s/%s", (gchar *) monitors->data, "port_number"); g_snprintf(k_watt_number, GAPC_MAX_TEXT, "%s/%s", (gchar *) monitors->data, "ups_wattage"); g_snprintf(k_network_interval, GAPC_MAX_TEXT, "%s/%s", (gchar *) monitors->data, "network_interval"); g_snprintf(k_graph_interval, GAPC_MAX_TEXT, "%s/%s", (gchar *) monitors->data, "graph_interval"); g_snprintf(k_host_name, GAPC_MAX_TEXT, "%s/%s", (gchar *) monitors->data, "host_name"); v_enabled = gconf_client_get_bool(pcfg->client, k_enabled, NULL); v_use_systray = gconf_client_get_bool(pcfg->client, k_use_systray, NULL); v_port_number = gconf_client_get_int(pcfg->client, k_port_number, NULL); if (v_port_number == 0) { v_port_number = GAPC_PORT_DEFAULT; } v_watt_number = gconf_client_get_int(pcfg->client, k_watt_number, NULL); if (v_watt_number == 0) { v_watt_number = GAPC_WATT_DEFAULT; } v_network_interval = gconf_client_get_float(pcfg->client, k_network_interval, NULL); if (v_network_interval == 0.0) { v_network_interval = GAPC_REFRESH_DEFAULT; } v_graph_interval = gconf_client_get_float(pcfg->client, k_graph_interval, NULL); if (v_graph_interval == 0.0) { v_graph_interval = GAPC_LINEGRAPH_REFRESH_FACTOR; } v_host_name = gconf_client_get_string(pcfg->client, k_host_name, NULL); if (v_host_name == NULL) { v_host_name = g_strdup(GAPC_HOST_DEFAULT); } gtk_list_store_append(GTK_LIST_STORE(pcfg->prefs_model), &iter); gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_MONITOR, i_monitor, GAPC_PREFS_SYSTRAY, v_use_systray, GAPC_PREFS_ENABLED, v_enabled, GAPC_PREFS_PORT, v_port_number, GAPC_PREFS_REFRESH, v_network_interval, GAPC_PREFS_GRAPH, v_graph_interval, GAPC_PREFS_HOST, v_host_name, GAPC_PREFS_WATT, v_watt_number, -1); /* Startup Processing */ if (v_enabled) { widget = gapc_monitor_interface_create(pcfg, i_monitor, &iter); if ((widget != NULL) && !v_use_systray ) { gtk_window_present( GTK_WINDOW(widget)); } } g_free(monitors->data); monitors = g_slist_next(monitors); } g_slist_free(monitors); return TRUE; } /* * Create a data model to hold the preferences for this program. We are * using the list store model to hold the all data. Then we create the * complete GtkTreeView and initialize the columns. * returns GtkTreeView or NULL */ static GtkWidget *gapc_panel_preferences_model_init(PGAPC_CONFIG pcfg) { GtkWidget *treeview = NULL; GtkTreeModel *model = NULL; GtkTreeViewColumn *column = NULL; GtkCellRenderer *renderer_enabled = NULL, *renderer_systray = NULL, *renderer_port = NULL, *renderer_watt = NULL, *renderer_refresh = NULL, *renderer_graph = NULL, *renderer_host = NULL, *anyrndr = NULL; PGAPC_PREFS_COLUMN col_enabled = NULL, col_systray = NULL, col_port = NULL, col_refresh = NULL, col_graph = NULL, col_host = NULL, col_watt = NULL; g_return_val_if_fail(pcfg != NULL, NULL); /* Don't create it twice */ if (pcfg->prefs_treeview != NULL) return GTK_WIDGET(pcfg->prefs_treeview); /* Create the model -- this column order and that of the enum must match */ model = GTK_TREE_MODEL(gtk_list_store_new(GAPC_N_PREFS_COLUMNS, G_TYPE_INT, /* Monitor base-1 */ G_TYPE_BOOLEAN, /* enabled */ G_TYPE_BOOLEAN, /* systray icon */ G_TYPE_INT, /* Port */ G_TYPE_FLOAT, /* network Refresh */ G_TYPE_FLOAT, /* graph Refresh */ G_TYPE_STRING, /* Host */ G_TYPE_INT /* Wattage */ )); /* store it for later */ pcfg->prefs_model = model; /* load the data model */ gapc_panel_preferences_data_model_load(pcfg); /* create the display columns and treeview */ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); gtk_tree_view_columns_autosize(GTK_TREE_VIEW(treeview)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_set_enable_search(GTK_TREE_VIEW(treeview), FALSE); /* allocate control struct for viewable columns */ col_enabled = gapc_panel_prefs_col_data_init(pcfg, GAPC_PREFS_ENABLED); col_systray = gapc_panel_prefs_col_data_init(pcfg, GAPC_PREFS_SYSTRAY); col_port = gapc_panel_prefs_col_data_init(pcfg, GAPC_PREFS_PORT); col_watt = gapc_panel_prefs_col_data_init(pcfg, GAPC_PREFS_WATT); col_refresh = gapc_panel_prefs_col_data_init(pcfg, GAPC_PREFS_REFRESH); col_graph = gapc_panel_prefs_col_data_init(pcfg, GAPC_PREFS_GRAPH); col_host = gapc_panel_prefs_col_data_init(pcfg, GAPC_PREFS_HOST); /* create display formatters where needed */ renderer_enabled = gtk_cell_renderer_toggle_new(); renderer_systray = gtk_cell_renderer_toggle_new(); renderer_port = gtk_cell_renderer_text_new(); renderer_watt = gtk_cell_renderer_text_new(); renderer_refresh = gtk_cell_renderer_text_new(); renderer_graph = gtk_cell_renderer_text_new(); renderer_host = gtk_cell_renderer_text_new(); anyrndr = gtk_cell_renderer_text_new(); /* set renderers attributes */ g_object_set(G_OBJECT(renderer_port), "xalign", 0.5, "editable", TRUE, NULL); g_object_set(G_OBJECT(renderer_watt), "xalign", 0.5, "editable", TRUE, NULL); g_object_set(G_OBJECT(renderer_graph), "xalign", 0.5, "editable", TRUE, NULL); g_object_set(G_OBJECT(renderer_refresh), "xalign", 0.5, "editable", TRUE, NULL); g_object_set(G_OBJECT(renderer_host), "editable", TRUE, NULL); /* prepare callbacks to correctly handle the columns * careful to use these only once per column -- * using an auto g_free to release allocated storage */ gtk_signal_connect_full(GTK_OBJECT(renderer_enabled), "toggled", G_CALLBACK(cb_panel_prefs_handle_cell_toggled), NULL, col_enabled, g_free, FALSE, TRUE); gtk_signal_connect_full(GTK_OBJECT(renderer_systray), "toggled", G_CALLBACK(cb_panel_prefs_handle_cell_toggled), NULL, col_systray, g_free, FALSE, TRUE); gtk_signal_connect_full(GTK_OBJECT(renderer_port), "edited", G_CALLBACK(cb_panel_prefs_handle_cell_edited), NULL, col_port, g_free, FALSE, TRUE); gtk_signal_connect_full(GTK_OBJECT(renderer_watt), "edited", G_CALLBACK(cb_panel_prefs_handle_cell_edited), NULL, col_watt, g_free, FALSE, TRUE); gtk_signal_connect_full(GTK_OBJECT(renderer_refresh), "edited", G_CALLBACK(cb_panel_prefs_handle_cell_edited), NULL, col_refresh, g_free, FALSE, TRUE); gtk_signal_connect_full(GTK_OBJECT(renderer_graph), "edited", G_CALLBACK(cb_panel_prefs_handle_cell_edited), NULL, col_graph, g_free, FALSE, TRUE); gtk_signal_connect_full(GTK_OBJECT(renderer_host), "edited", G_CALLBACK(cb_panel_prefs_handle_cell_edited), NULL, col_host, g_free, FALSE, TRUE); /* Define the column order and attributes */ column = gtk_tree_view_column_new_with_attributes("Enabled", renderer_enabled, "active", GAPC_PREFS_ENABLED, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("use\nTrayIcon", renderer_systray, "active", GAPC_PREFS_SYSTRAY, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("network\nRefresh", renderer_refresh, "text", GAPC_PREFS_REFRESH, NULL); g_object_set_data(G_OBJECT(column), "float_format", "%3.1f"); gtk_tree_view_column_set_cell_data_func(column, renderer_refresh, cb_panel_prefs_handle_float_format, GUINT_TO_POINTER(GAPC_PREFS_REFRESH), NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("Port", renderer_port, "text", GAPC_PREFS_PORT, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("graph\nRefresh", renderer_graph, "text", GAPC_PREFS_GRAPH, NULL); g_object_set_data(G_OBJECT(column), "float_format", "%3.0f"); gtk_tree_view_column_set_cell_data_func(column, renderer_graph, cb_panel_prefs_handle_float_format, GUINT_TO_POINTER(GAPC_PREFS_GRAPH), NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("Rated\nWattage", renderer_watt, "text", GAPC_PREFS_WATT, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("Host Name or IP Address", renderer_host, "text", GAPC_PREFS_HOST, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("Monitor", anyrndr, "text", GAPC_PREFS_MONITOR, NULL); gtk_tree_view_column_set_sort_column_id(column, GAPC_PREFS_MONITOR); gtk_tree_view_column_clicked(column); g_object_set(G_OBJECT(column), "visible", FALSE, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); return treeview; } /* * Create a data model to hold the current list of active monitors. We are * using the list store model to hold the active data. Then we create the * complete GtkTreeView and initialize the columns. * returns GtkTreeView or NULL */ static GtkWidget *gapc_panel_monitors_model_init(PGAPC_CONFIG pcfg) { GtkWidget *treeview = NULL; GtkTreeModel *model = NULL; GtkCellRenderer *renderer_icon = NULL, *renderer_text = NULL, *renderer_state = NULL, *renderer_any = NULL; GtkTreeViewColumn *column = NULL; g_return_val_if_fail(pcfg != NULL, NULL); /* Don't create it twice */ if (pcfg->monitor_treeview != NULL) return GTK_WIDGET(pcfg->monitor_treeview); /* Create the model -- this column order and that of the enum must match */ model = GTK_TREE_MODEL(gtk_list_store_new(GAPC_N_MON_COLUMNS, G_TYPE_INT, /* Monitor Num */ GDK_TYPE_PIXBUF, /* ICON */ G_TYPE_STRING, /* Status Text */ G_TYPE_POINTER, /* monitor ptr */ G_TYPE_STRING /* State Text */ )); /* store it for later */ pcfg->monitor_model = model; /* create the display columns and treeview */ treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model)); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(treeview), TRUE); gtk_tree_view_columns_autosize(GTK_TREE_VIEW(treeview)); gtk_tree_view_set_enable_search(GTK_TREE_VIEW(treeview), FALSE); g_signal_connect(treeview, "row-activated", G_CALLBACK(cb_panel_monitor_list_activated), pcfg); renderer_icon = gtk_cell_renderer_pixbuf_new(); renderer_text = gtk_cell_renderer_text_new(); renderer_state = gtk_cell_renderer_text_new(); renderer_any = gtk_cell_renderer_text_new(); g_object_set(G_OBJECT(renderer_state), "xalign", 0.5, NULL); g_object_set(G_OBJECT(renderer_text), "xalign", 0.0, NULL); g_object_set(G_OBJECT(renderer_text), "yalign", 0.5, NULL); column = gtk_tree_view_column_new(); gtk_tree_view_column_set_title(column, "Status"); gtk_tree_view_column_pack_start(column, renderer_icon, TRUE); gtk_tree_view_column_add_attribute(column, renderer_icon, "pixbuf", GAPC_MON_ICON); gtk_tree_view_column_pack_end(column, renderer_state, FALSE); gtk_tree_view_column_add_attribute(column, renderer_state, "markup", GAPC_MON_UPSSTATE); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("Current summary ups info", renderer_text, "markup", GAPC_MON_STATUS, NULL); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); column = gtk_tree_view_column_new_with_attributes("Monitor", renderer_any, "text", GAPC_MON_MONITOR, NULL); gtk_tree_view_column_set_sort_column_id(column, GAPC_MON_MONITOR); g_object_set(G_OBJECT(column), "visible", FALSE, NULL); gtk_tree_view_column_clicked(column); gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), column); return treeview; } /* * Load ICONs and set default icon * return TRUE if ok, FALSE otherwise */ static gboolean gapc_util_load_icons(PGAPC_CONFIG pcfg) { guint i_x = 0, x = 0; GError *gerror = NULL; GdkPixbuf *pixbuf = NULL; gboolean b_rc = TRUE; gchar pch_file[GAPC_MAX_ARRAY]; gchar *pch_2 = "./"; gchar *pch_3 = "../pixmaps/"; gchar *pch_4 = NULL; gchar *pch_image_names[] = { "online.png", "onbatt.png", "charging.png", "apcupsd.png", "unplugged.png", "gapc_prefs.png", NULL }; g_return_val_if_fail(pcfg != NULL, FALSE); /* build system path for icons */ pch_4 = g_strconcat (ICON_DIR, "/pixmaps/", NULL); i_x = 0; while (i_x == 0) { if (g_file_test(pch_image_names[0], G_FILE_TEST_EXISTS)) { i_x = 1; break; } g_snprintf(pch_file, GAPC_MAX_ARRAY, "%s%s", pch_2, pch_image_names[0]); if (g_file_test(pch_file, G_FILE_TEST_EXISTS)) { i_x = 2; break; } g_snprintf(pch_file, GAPC_MAX_ARRAY, "%s%s", pch_3, pch_image_names[0]); if (g_file_test(pch_file, G_FILE_TEST_EXISTS)) { i_x = 3; break; } g_snprintf(pch_file, GAPC_MAX_ARRAY, "%s%s", pch_4, pch_image_names[0]); if (g_file_test(pch_file, G_FILE_TEST_EXISTS)) { i_x = 4; break; } break; } if (i_x == 0) { gapc_util_log_app_msg("gapc_util_load_icons", "Unable to find icons", "--load failed!"); g_free (pch_4); return FALSE; } for (x = 0; (pch_image_names[x] != NULL) && (x < GAPC_N_ICONS); x++) { switch (i_x) { case 1: g_snprintf(pch_file, GAPC_MAX_ARRAY, "%s", pch_image_names[x]); break; case 2: g_snprintf(pch_file, GAPC_MAX_ARRAY, "%s%s", pch_2, pch_image_names[x]); break; case 3: g_snprintf(pch_file, GAPC_MAX_ARRAY, "%s%s", pch_3, pch_image_names[x]); break; case 4: g_snprintf(pch_file, GAPC_MAX_ARRAY, "%s%s", pch_4, pch_image_names[x]); break; default: g_return_val_if_reached(FALSE); break; } pixbuf = gdk_pixbuf_new_from_file(pch_file, &gerror); if (gerror != NULL) { gchar *pch = NULL; pch = g_strdup_printf("Get Icon=%s Failed", pch_file); gapc_util_log_app_msg("gapc_util_load_icons", pch, gerror->message); g_error_free(gerror); g_free(pch); gerror = NULL; b_rc = FALSE; pcfg->my_icons[x] = NULL; } else { pcfg->my_icons[x] = gdk_pixbuf_scale_simple(pixbuf, GAPC_ICON_SIZE, GAPC_ICON_SIZE, GDK_INTERP_BILINEAR); g_object_unref(pixbuf); } } g_free (pch_4); return b_rc; } /* * Monitor List "row-activated" */ static void cb_panel_monitor_list_activated(GtkTreeView * treeview, GtkTreePath * arg1, GtkTreeViewColumn * arg2, PGAPC_CONFIG pcfg) { PGAPC_MONITOR pm = NULL; GtkTreeIter iter; g_return_if_fail(pcfg != NULL); if (gtk_tree_model_get_iter(pcfg->monitor_model, &iter, arg1)) { gtk_tree_model_get(pcfg->monitor_model, &iter, GAPC_MON_POINTER, &pm, -1); if ((pm != NULL) && (pm->window != NULL)) { if (pm->b_visible) { gtk_widget_hide(GTK_WIDGET(pm->window)); } else { gtk_window_present(GTK_WINDOW(pm->window)); } } } return; } /* * Active monitor selection */ static void cb_panel_monitor_list_selection(GtkTreeSelection * selection, PGAPC_CONFIG pcfg) { GtkTreeIter iter; GtkTreeModel *model; gint i_monitor = 0; g_return_if_fail(pcfg != NULL); if (gtk_tree_selection_get_selected(selection, &model, &iter)) { gtk_tree_model_get(model, &iter, GAPC_MON_MONITOR, &i_monitor, -1); pcfg->cb_last_monitor = i_monitor; } return; } /* * The Active Monitor Icon List for the information window * returns created notebook page number. */ static gint gapc_panel_monitor_list_page(PGAPC_CONFIG pcfg, GtkNotebook * notebook) { GtkWidget *label = NULL, *frame = NULL, *vbox = NULL, *sw = NULL; GtkWidget *treeview = NULL; GtkTreeSelection *select = NULL; GtkTreeIter iter; gint i_page = 0; g_return_val_if_fail(pcfg != NULL, -1); g_return_val_if_fail(notebook != NULL, -1); /* Create notebook page */ frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT); label = gtk_label_new("Active Monitors"); i_page = gtk_notebook_append_page(notebook, frame, label); gtk_widget_show(frame); label = gtk_label_new("" "double-click a row to popup information window." ""); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); vbox = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); frame = gtk_frame_new(""); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_frame_set_label_widget(GTK_FRAME(frame), label); gtk_frame_set_label_align(GTK_FRAME(frame), 0.5, 0.8); gtk_container_add(GTK_CONTAINER(vbox), frame); gtk_widget_show(frame); /* Create the container for the icon view */ sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(frame), sw); gtk_widget_show(sw); /* create the active monitor list in a treeview */ treeview = gapc_panel_monitors_model_init(pcfg); pcfg->monitor_treeview = GTK_TREE_VIEW(treeview); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(GTK_WIDGET(treeview)); /* Setup the selection handler */ select = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); pcfg->monitor_select = select; gtk_tree_selection_set_mode(select, GTK_SELECTION_SINGLE); g_signal_connect(G_OBJECT(select), "changed", G_CALLBACK(cb_panel_monitor_list_selection), pcfg); /* Selection the first record */ if (gtk_tree_model_get_iter_first(pcfg->monitor_model, &iter)) { gtk_tree_selection_select_iter(select, &iter); } return i_page; } /* * The Preferences List for the information window * returns created notebook page number. */ static gint gapc_panel_preferences_page(PGAPC_CONFIG pcfg, GtkNotebook * notebook) { GtkWidget *label = NULL, *frame = NULL, *vbox = NULL, *sw = NULL; GtkWidget *pbox = NULL, *box = NULL, *cbox = NULL; GtkWidget *treeview = NULL; GtkTreeSelection *select = NULL; GtkTreeIter iter; gint i_page = 0; g_return_val_if_fail(pcfg != NULL, -1); g_return_val_if_fail(notebook != NULL, -1); /* Create notebook page */ frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT); label = gtk_label_new("Preferences"); i_page = gtk_notebook_append_page(notebook, frame, label); gtk_widget_show(frame); label = gtk_label_new("" "double-click a columns value to change it." ""); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); box = gtk_event_box_new(); gtk_container_add(GTK_CONTAINER(frame), box); gtk_widget_show(box); vbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(box), vbox); gtk_widget_show(vbox); frame = gtk_frame_new(""); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_frame_set_label_widget(GTK_FRAME(frame), label); gtk_frame_set_label_align(GTK_FRAME(frame), 0.5, 0.8); gtk_container_add(GTK_CONTAINER(vbox), frame); gtk_widget_show(frame); pbox = gtk_vbox_new(FALSE, 0); gtk_container_add(GTK_CONTAINER(frame), pbox); gtk_widget_show(pbox); /* Create the container for the icon view */ sw = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(pbox), sw); gtk_widget_show(sw); /* create the preferences in a treeview */ treeview = gapc_panel_preferences_model_init(pcfg); pcfg->prefs_treeview = GTK_TREE_VIEW(treeview); gtk_container_add(GTK_CONTAINER(sw), treeview); gtk_widget_show(GTK_WIDGET(treeview)); /* Setup the selection handler */ select = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); pcfg->prefs_select = select; gtk_tree_selection_set_mode(select, GTK_SELECTION_BROWSE); /* Select the first record */ if (gtk_tree_model_get_iter_first(pcfg->prefs_model, &iter)) { gtk_tree_selection_select_iter(select, &iter); } /* add options for adding monitors */ box = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(pbox), box, FALSE, FALSE, 0); gtk_widget_show(box); cbox = gtk_button_new_from_stock(GTK_STOCK_ADD); g_signal_connect(cbox, "clicked", G_CALLBACK(cb_panel_prefs_button_add_rec), pcfg); gtk_tooltips_set_tip(pcfg->tooltips, GTK_WIDGET(cbox), "Adds a new monitor\ndefinition to the system.", NULL); gtk_box_pack_start(GTK_BOX(box), cbox, FALSE, FALSE, 2); gtk_widget_show(cbox); cbox = gtk_button_new_from_stock(GTK_STOCK_REMOVE); g_signal_connect(cbox, "clicked", G_CALLBACK(cb_panel_prefs_button_remove_rec), pcfg); gtk_tooltips_set_tip(pcfg->tooltips, GTK_WIDGET(cbox), "Removes selected monitor\ndefinition from the system.", NULL); gtk_box_pack_start(GTK_BOX(box), cbox, FALSE, FALSE, 2); gtk_widget_show(cbox); /* add options for control panel */ frame = gtk_frame_new("Control panel options"); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN); gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 0); gtk_widget_show(frame); box = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(frame), box); gtk_widget_show(box); cbox = gtk_check_button_new_with_mnemonic("Use _tray Icon"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbox), pcfg->b_use_systray); g_signal_connect(cbox, "toggled", G_CALLBACK(cb_panel_prefs_button_use_systray), pcfg); gtk_tooltips_set_tip(pcfg->tooltips, GTK_WIDGET(cbox), "Creates a notification area icon\nfor this control panel.", NULL); gtk_box_pack_start(GTK_BOX(box), cbox, FALSE, FALSE, 2); gtk_widget_show(cbox); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("UseTrayIcon"), cbox); return i_page; } /* * The about page in the information window * returns created notebook page number. */ static gint gapc_panel_about_page(GtkNotebook * notebook, gchar * pch_pname, gchar * pch_pversion, GdkPixbuf * icon) { GtkWidget *label = NULL, *frame = NULL, *vbox = NULL; GtkWidget *hbox = NULL, *image = NULL; gchar *about_text = NULL; gchar *about_msg = NULL; GdkPixbuf *scaled = NULL; gint i_page = 0; g_return_val_if_fail(notebook != NULL, -1); about_text = g_strdup_printf("%s\nVersion %s\n", pch_pname, pch_pversion); about_msg = g_strdup_printf("gui monitor for UPSs under the management" " of the APCUPSD.sourceforge.net package\n" "http://gapcmon.sourceforge.net/\n\n" "Copyright \xC2\xA9 2006 James Scott, Jr.\n" "skoona@users.sourceforge.net\n\n" "Released under the GNU Public License\n" "%s comes with\nABSOLUTELY NO WARRANTY", pch_pname); /* Create About page */ frame = gtk_frame_new(NULL); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT); label = gtk_label_new("About"); i_page = gtk_notebook_append_page(notebook, frame, label); gtk_widget_show(frame); vbox = gtk_vbox_new(FALSE, 8); gtk_container_add(GTK_CONTAINER(frame), vbox); gtk_widget_show(vbox); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); gtk_widget_show(hbox); image = gtk_image_new(); gtk_misc_set_alignment((GtkMisc *) image, 1.0, 0.5); scaled = gdk_pixbuf_scale_simple(icon, 48, 48, GDK_INTERP_BILINEAR); gtk_image_set_from_pixbuf(GTK_IMAGE(image), scaled); gtk_box_pack_start(GTK_BOX(hbox), image, TRUE, TRUE, 0); gtk_widget_show(image); gdk_pixbuf_unref(scaled); label = gtk_label_new(about_text); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment((GtkMisc *) label, 0.0, 0.7); gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE, 0); gtk_widget_show(label); label = gtk_label_new(about_msg); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment((GtkMisc *) label, 0.5, 0.5); gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); gtk_widget_show(label); g_free(about_text); g_free(about_msg); return i_page; } static void cb_monitor_interface_show(GtkWidget * widget, PGAPC_MONITOR pm) { g_return_if_fail(pm != NULL); pm->b_visible = TRUE; lg_graph_draw ( pm->phs.plg ); } static void cb_monitor_interface_hide(GtkWidget * widget, PGAPC_MONITOR pm) { g_return_if_fail(pm != NULL); pm->b_visible = FALSE; } static gboolean cb_monitor_interface_delete_event(GtkWidget * widget, GdkEvent * event, PGAPC_MONITOR pm) { g_return_val_if_fail(pm != NULL, FALSE); return gtk_widget_hide_on_delete(widget); } /* * Handle the close button action from the information window */ /* static void cb_monitor_interface_button_close(GtkWidget * button, PGAPC_MONITOR pm) { g_return_if_fail(pm != NULL); gtk_widget_hide(GTK_WIDGET(pm->window)); return; } */ /* * Handle the refresh button action from the information window */ static void cb_monitor_interface_button_refresh(GtkWidget * button, PGAPC_MONITOR pm) { g_return_if_fail(pm != NULL); if ((!pm->b_run) || !(pm->cb_enabled) || (pm->window == NULL)) { return; } g_async_queue_push(pm->q_network, pm); g_timeout_add(GAPC_REFRESH_FACTOR_ONE_TIME, (GSourceFunc) cb_monitor_dedicated_one_time_refresh, pm); return; } static void cb_main_interface_show(GtkWidget * widget, PGAPC_CONFIG pcfg) { g_return_if_fail(pcfg != NULL); pcfg->b_visible = TRUE; } static void cb_main_interface_hide(GtkWidget * widget, PGAPC_CONFIG pcfg) { g_return_if_fail(pcfg != NULL); pcfg->b_visible = FALSE; } /* "window-state-event" * iconify/minimize verus hide needs this routine to manage visibility */ static gboolean cb_util_manage_iconify_event(GtkWidget *widget, GdkEventWindowState *event, gpointer gp) { g_return_val_if_fail(gp != NULL, FALSE); /* iconified */ if ((event->type == GDK_WINDOW_STATE) && ( ((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && (event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) || ((event->changed_mask & GDK_WINDOW_STATE_WITHDRAWN) && (event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN)) )){ if ( ((PGAPC_MONITOR)gp)->cb_id == CB_MONITOR_ID) { if ( event->window == GTK_WIDGET(((PGAPC_MONITOR)gp)->window)->window ) { ((PGAPC_MONITOR)gp)->b_visible = FALSE; } } else { if ( event->window == GTK_WIDGET(((PGAPC_CONFIG)gp)->window)->window ) { ((PGAPC_CONFIG)gp)->b_visible = FALSE; } } return TRUE; } /* un - iconified */ if ((event->type == GDK_WINDOW_STATE) && ( ((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) && !(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED)) || ((event->changed_mask & GDK_WINDOW_STATE_WITHDRAWN) && !(event->new_window_state & GDK_WINDOW_STATE_WITHDRAWN))) ) { if ( ((PGAPC_MONITOR)gp)->cb_id == CB_MONITOR_ID) { if ( event->window == GTK_WIDGET(((PGAPC_MONITOR)gp)->window)->window ) { ((PGAPC_MONITOR)gp)->b_visible = TRUE; } } else { if ( event->window == GTK_WIDGET(((PGAPC_CONFIG)gp)->window)->window ) { ((PGAPC_CONFIG)gp)->b_visible = TRUE; } } return TRUE; } return FALSE; } static gboolean cb_main_interface_delete_event(GtkWidget * widget, GdkEvent * event, PGAPC_CONFIG pcfg) { g_return_val_if_fail(pcfg != NULL, FALSE); cb_main_interface_button_quit(widget, pcfg); return FALSE; } /* * Handle the quit button action from the information window */ static void cb_main_interface_button_quit(GtkWidget * button, PGAPC_CONFIG pcfg) { GtkTreeIter iter; PGAPC_MONITOR pm = NULL; gboolean valid = FALSE; g_return_if_fail(pcfg != NULL); valid = gtk_tree_model_get_iter_first(pcfg->monitor_model, &iter); while (valid) { gtk_tree_model_get(pcfg->monitor_model, &iter, GAPC_MON_POINTER, &pm, -1); if ((pm != NULL) && (pm->window != NULL)) { pm->b_run = FALSE; gtk_widget_destroy(GTK_WIDGET(pm->window)); pm->window = NULL; pm = NULL; } valid = gtk_tree_model_iter_next(pcfg->monitor_model, &iter); } gtk_widget_destroy(GTK_WIDGET(pcfg->window)); return; } /* * GConf2 routine * Handles changes to use_systray and skip_pager for the control panel. * Triggers for this routine should not be installed until after the * control panel has been created. */ static void cb_panel_controller_gconf_changed(GConfClient * client, guint cnxn_id, GConfEntry * entry, PGAPC_CONFIG pcfg) { gboolean b_new_value = FALSE; GtkWidget *cbox = NULL; gchar const *pstring = NULL; GdkColor *pcolor = NULL; g_return_if_fail(pcfg != NULL); g_return_if_fail(entry != NULL); g_return_if_fail(entry->value != NULL); g_return_if_fail(pcfg->window != NULL); switch (entry->value->type) { case GCONF_VALUE_STRING: /* take action to propagate the value to all monitors */ pstring = gconf_value_get_string(entry->value); if (pstring == NULL) { break; } pcolor = NULL; if (g_str_equal(entry->key, GAPC_COLOR_LINEV_KEY)) { pcolor = &pcfg->color_linev; cbox = g_hash_table_lookup(pcfg->pht_Widgets, "color-linev"); } if (g_str_equal(entry->key, GAPC_COLOR_LOADPCT_KEY)) { pcolor = &pcfg->color_loadpct; cbox = g_hash_table_lookup(pcfg->pht_Widgets, "color-loadpct"); } if (g_str_equal(entry->key, GAPC_COLOR_TIMELEFT_KEY)) { pcolor = &pcfg->color_timeleft; cbox = g_hash_table_lookup(pcfg->pht_Widgets, "color-timeleft"); } if (g_str_equal(entry->key, GAPC_COLOR_BCHARGE_KEY)) { pcolor = &pcfg->color_bcharge; cbox = g_hash_table_lookup(pcfg->pht_Widgets, "color-bcharge"); } if (g_str_equal(entry->key, GAPC_COLOR_BATTV_KEY)) { pcolor = &pcfg->color_battv; cbox = g_hash_table_lookup(pcfg->pht_Widgets, "color-battv"); } if (g_str_equal(entry->key, GAPC_COLOR_WINDOW_KEY)) { pcolor = &pcfg->color_window; cbox = g_hash_table_lookup(pcfg->pht_Widgets, "color-window"); } if (g_str_equal(entry->key, GAPC_COLOR_CHART_KEY)) { pcolor = &pcfg->color_chart; cbox = g_hash_table_lookup(pcfg->pht_Widgets, "color-chart"); } if (g_str_equal(entry->key, GAPC_COLOR_TITLE_KEY)) { pcolor = &pcfg->color_title; cbox = g_hash_table_lookup(pcfg->pht_Widgets, "color-title"); } if ( pcolor ) { gdk_color_parse (pstring, pcolor); } if ( cbox ) { gtk_color_button_set_color (GTK_COLOR_BUTTON(cbox), pcolor); } break; case GCONF_VALUE_BOOL: b_new_value = gconf_value_get_bool(entry->value); if (g_str_equal(entry->key, pcfg->pch_gkeys[GAPC_PREFS_SYSTRAY])) { if (pcfg->b_use_systray == b_new_value) { break; } pcfg->b_use_systray = b_new_value; if (b_new_value) { if (pcfg->tray_icon == NULL) { gapc_panel_systray_icon_create(pcfg); } } else { if (pcfg->tray_icon != NULL) { gapc_panel_systray_icon_remove(pcfg); } } cbox = g_hash_table_lookup(pcfg->pht_Widgets, "UseTrayIcon"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbox), pcfg->b_use_systray); break; } break; default: gapc_util_log_app_msg("cb_panel_controller_gconf_changed", "(UnKnown Data Type for key)", entry->key); } return; } /* * GConf2 routine * Handles changes to prefs_model, or the master list of monitors in the preferences page. * Triggers for this routine should not be installed until after the * control panel has been created. */ static void cb_panel_preferences_gconf_changed(GConfClient * client, guint cnxn_id, GConfEntry * entry, PGAPC_CONFIG pcfg) { gchar *pch_value = NULL; gchar *pkey = NULL, **pkey_l = NULL; gboolean ov_b_tray = FALSE; gint ov_i_port = 0; gint ov_i_watt = 0; gfloat ov_f_graph = 0.0; gfloat ov_f_refresh = 0.0; gchar *ov_s_host = NULL; gint i_monitor = 0; gint i_value = 0, i_len = 0; gfloat f_value = 0.0; gchar *s_value = NULL, ch[GAPC_MAX_TEXT]; gboolean b_value = FALSE, b_flag_dupped = FALSE; gboolean b_ls_valid = FALSE; gboolean b_v_valid = FALSE; gboolean b_k_valid = FALSE; gboolean b_k_is_dir = FALSE; gboolean b_m_valid = FALSE; gboolean b_m_enabled = FALSE, b_add = TRUE, b_active_valid = FALSE; GtkTreeIter iter; GtkTreeIter miter; PGAPC_MONITOR pm = NULL; g_return_if_fail(pcfg != NULL); g_return_if_fail(entry != NULL); g_return_if_fail(pcfg->window != NULL); /* Parse out monitor number and item.key */ pkey_l = g_strsplit(entry->key, "/", -1); if (pkey_l[5] != NULL) { pkey = g_strdup(pkey_l[5]); b_k_valid = TRUE; } else { b_k_is_dir = TRUE; } if (pkey_l[4] != NULL) { i_monitor = (gint) g_strtod(pkey_l[4], NULL); b_m_valid = TRUE; } g_strfreev(pkey_l); gdk_threads_enter(); /* Determine control bools */ b_ls_valid = gapc_util_treeview_get_iter_from_monitor(pcfg->prefs_model, &iter, i_monitor); if (b_ls_valid) { gtk_tree_model_get(pcfg->prefs_model, &iter, GAPC_PREFS_ENABLED, &b_m_enabled, GAPC_PREFS_SYSTRAY, &ov_b_tray, GAPC_PREFS_PORT, &ov_i_port, GAPC_PREFS_WATT, &ov_i_watt, GAPC_PREFS_GRAPH, &ov_f_graph, GAPC_PREFS_REFRESH, &ov_f_refresh, GAPC_PREFS_HOST, &ov_s_host, -1); } if (entry->value != NULL) { pch_value = (gchar *) gconf_value_to_string(entry->value); if (pch_value != NULL) { b_v_valid = TRUE; } } /* perform record.level operations */ if (b_ls_valid && !b_k_valid && !b_v_valid) { /* delete null dir - no key val */ if (b_m_enabled) { gapc_monitor_interface_destroy(pcfg, i_monitor); b_m_enabled = FALSE; } gtk_list_store_remove(GTK_LIST_STORE(pcfg->prefs_model), &iter); b_ls_valid = FALSE; pcfg->cb_last_monitor_deleted = i_monitor; } if (i_monitor == pcfg->cb_last_monitor_deleted) { /* override gconf_unset-kde issue */ b_k_valid = FALSE; b_v_valid = FALSE; b_m_enabled = FALSE; } if (!b_ls_valid && b_v_valid && b_k_valid) { /* add new rec if keys valid -nfound */ gtk_list_store_append(GTK_LIST_STORE(pcfg->prefs_model), &iter); gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_MONITOR, i_monitor, GAPC_PREFS_SYSTRAY, FALSE, GAPC_PREFS_ENABLED, FALSE, GAPC_PREFS_PORT, GAPC_PORT_DEFAULT, GAPC_PREFS_GRAPH, GAPC_LINEGRAPH_REFRESH_FACTOR, GAPC_PREFS_HOST, GAPC_HOST_DEFAULT, GAPC_PREFS_REFRESH, GAPC_REFRESH_DEFAULT, GAPC_PREFS_WATT, GAPC_WATT_DEFAULT, -1); b_ls_valid = TRUE; b_add = TRUE; b_m_enabled = FALSE; } /* perform cell.level operations */ if (b_ls_valid && b_v_valid && b_k_valid) { b_active_valid = gapc_util_treeview_get_iter_from_monitor(pcfg->monitor_model, &miter, i_monitor); if (b_active_valid) { gtk_tree_model_get(pcfg->monitor_model, &miter, GAPC_MON_POINTER, &pm, -1); } else { b_active_valid = FALSE; } if ((pm == NULL) || (pm->window == NULL)) { b_active_valid = FALSE; } if (g_str_equal(pkey, "enabled")) { b_value = gconf_value_get_bool(entry->value); if (b_value != b_m_enabled) { gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_ENABLED, b_value, -1); } if (b_value && !b_m_enabled && !b_active_valid) { gtk_widget_show_all(gapc_monitor_interface_create(pcfg, i_monitor, &iter)); } if (!b_value && b_m_enabled && b_active_valid) { gapc_monitor_interface_destroy(pcfg, i_monitor); } } if (g_str_equal(pkey, "use_systray")) { b_value = gconf_value_get_bool(entry->value); if (b_value != ov_b_tray) { gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_SYSTRAY, b_value, -1); } if ((b_m_enabled) && (b_active_valid)) { pm->cb_use_systray = b_value; if (b_value) { gapc_panel_systray_icon_create(pm); } else { gapc_panel_systray_icon_remove(pm); } } } if (g_str_equal(pkey, "port_number")) { i_value = gconf_value_get_int(entry->value); if (i_value != ov_i_port) { gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_PORT, i_value, -1); } if ((b_m_enabled) && (b_active_valid)) { pm->i_port = i_value; pm->b_network_control = TRUE; if (pm->psk != NULL) { pm->psk->i_port = i_value; pm->psk->b_network_control = TRUE; } } } if (g_str_equal(pkey, "ups_wattage")) { i_value = gconf_value_get_int(entry->value); if (i_value != ov_i_watt) { gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_WATT, i_value, -1); } if ( pm != NULL ) { pm->i_watt = i_value; } } if (g_str_equal(pkey, "network_interval")) { f_value = gconf_value_get_float(entry->value); if (f_value != ov_f_refresh) { gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_REFRESH, f_value, -1); } if ((b_m_enabled) && (b_active_valid)) { pm->d_refresh = f_value; pm->b_timer_control = TRUE; } } if (g_str_equal(pkey, "graph_interval")) { f_value = gconf_value_get_float(entry->value); if (f_value != ov_f_graph) { gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_GRAPH, f_value, -1); } if ((b_m_enabled) && (b_active_valid)) { pm->d_graph = f_value; pm->b_graph_control = TRUE; } } if (g_str_equal(pkey, "host_name")) { s_value = (gchar *) gconf_value_get_string(entry->value); i_len = g_snprintf(ch, GAPC_MAX_TEXT, "%s", s_value); if (i_len < 2) { s_value = g_strdup(GAPC_HOST_DEFAULT); b_flag_dupped = TRUE; } if (!g_str_equal(s_value, ov_s_host)) { gtk_list_store_set(GTK_LIST_STORE(pcfg->prefs_model), &iter, GAPC_PREFS_HOST, s_value, -1); } if ((b_m_enabled) && (b_active_valid)) { if (pm->pch_host != NULL) { g_free(pm->pch_host); } pm->pch_host = g_strdup(s_value); pm->b_network_control = TRUE; if (pm->psk != NULL) { g_snprintf(pm->psk->ch_ip_string, sizeof(pm->psk->ch_ip_string), "%s", s_value); pm->psk->b_network_control = TRUE; } } if (b_flag_dupped) { g_free(s_value); b_flag_dupped = FALSE; } if (ov_s_host) { g_free(ov_s_host); } } } if (pkey != NULL) { g_free(pkey); } if (pch_value != NULL) { g_free(pch_value); } gdk_flush(); gdk_threads_leave(); return; } /* * Clears the gconf directory watchers for the control panel * returns FALSE on error * returns TRUE on sucess */ static gboolean gapc_panel_gconf_destroy(PGAPC_CONFIG pcfg) { g_return_val_if_fail(pcfg != NULL, FALSE); if (pcfg->i_group_id > 0) { gconf_client_remove_dir(pcfg->client, GAPC_MID_GROUP_KEY, NULL); gconf_client_remove_dir(pcfg->client, GAPC_CP_GROUP_KEY, NULL); gconf_client_notify_remove(pcfg->client, pcfg->i_group_id); gconf_client_notify_remove(pcfg->client, pcfg->i_prefs_id); } g_object_unref(pcfg->client); g_free(pcfg->pch_gkeys[GAPC_PREFS_SYSTRAY]); pcfg->i_group_id = 0; pcfg->i_prefs_id = 0; pcfg->client = NULL; pcfg->pch_gkeys[GAPC_PREFS_SYSTRAY] = NULL; return TRUE; } /* * Set the gconf directory watchers for the control panel * returns FALSE on error * returns TRUE on sucess */ static gboolean gapc_panel_gconf_watch(PGAPC_CONFIG pcfg) { GError *gerror = NULL; g_return_val_if_fail(pcfg != NULL, FALSE); /* Have gconf call us if something does change */ pcfg->i_group_id = gconf_client_notify_add(pcfg->client, GAPC_CP_GROUP_KEY, (GConfClientNotifyFunc) cb_panel_controller_gconf_changed, pcfg, NULL, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_gconf_watch", "gconf_client_notify_add(controller.group) Failed", gerror->message); g_error_free(gerror); pcfg->i_group_id = 0; gerror = NULL; return FALSE; } pcfg->i_prefs_id = gconf_client_notify_add(pcfg->client, GAPC_MID_GROUP_KEY, (GConfClientNotifyFunc) cb_panel_preferences_gconf_changed, pcfg, NULL, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_gconf_watch", "gconf_client_notify_add(prefs.group) Failed", gerror->message); g_error_free(gerror); pcfg->i_group_id = 0; gerror = NULL; return FALSE; } return TRUE; } /* * Gets the gconf instance preferences for this program * and init the control panel values. * returns FALSE on error * returns TRUE on sucess */ static gboolean gapc_panel_gconf_init(PGAPC_CONFIG pcfg) { GError *gerror = NULL; gchar *pstring = NULL; g_return_val_if_fail(pcfg != NULL, FALSE); /* prepare control panel keys */ pcfg->pch_gkeys[GAPC_PREFS_SYSTRAY] = g_strdup(GAPC_CP_SYSTRAY_KEY); /* contact gconf2 */ pcfg->client = gconf_client_get_default(); g_return_val_if_fail(pcfg->client != NULL, FALSE); /* Have gconf watch for changes in this controller directory */ gconf_client_add_dir(pcfg->client, GAPC_CP_GROUP_KEY, GCONF_CLIENT_PRELOAD_ONELEVEL, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_gconf_init", "gconf_client_add_dir() Failed", gerror->message); g_error_free(gerror); gerror = NULL; return FALSE; } /* Have gconf watch for changes in this monitor directory */ gconf_client_add_dir(pcfg->client, GAPC_MID_GROUP_KEY, GCONF_CLIENT_PRELOAD_ONELEVEL, &gerror); if (gerror != NULL) { gapc_util_log_app_msg("gapc_panel_gconf_init", "gconf_client_add_dir() Failed", gerror->message); g_error_free(gerror); gerror = NULL; return FALSE; } /* Defaults are FALSE */ pcfg->b_use_systray = gconf_client_get_bool(pcfg->client, pcfg->pch_gkeys[GAPC_PREFS_SYSTRAY], NULL); /* Load graph colors or set defaults */ pstring = gconf_client_get_string(pcfg->client, GAPC_COLOR_LINEV_KEY, NULL); if (pstring) { gdk_color_parse (pstring, &pcfg->color_linev); } else { gdk_color_parse ("green", &pcfg->color_linev); } pstring = gconf_client_get_string(pcfg->client, GAPC_COLOR_LOADPCT_KEY, NULL); if (pstring) { gdk_color_parse (pstring, &pcfg->color_loadpct); } else { gdk_color_parse ("blue", &pcfg->color_loadpct); } pstring = gconf_client_get_string(pcfg->client, GAPC_COLOR_TIMELEFT_KEY, NULL); if (pstring) { gdk_color_parse (pstring, &pcfg->color_timeleft); } else { gdk_color_parse ("red", &pcfg->color_timeleft); } pstring = gconf_client_get_string(pcfg->client, GAPC_COLOR_BCHARGE_KEY, NULL); if (pstring) { gdk_color_parse (pstring, &pcfg->color_bcharge); } else { gdk_color_parse ("yellow", &pcfg->color_bcharge); } pstring = gconf_client_get_string(pcfg->client, GAPC_COLOR_BATTV_KEY, NULL); if (pstring) { gdk_color_parse (pstring, &pcfg->color_battv); } else { gdk_color_parse ("black", &pcfg->color_battv); } pstring = gconf_client_get_string(pcfg->client, GAPC_COLOR_WINDOW_KEY, NULL); if (pstring) { gdk_color_parse (pstring, &pcfg->color_window); } else { gdk_color_parse ("white", &pcfg->color_window); } pstring = gconf_client_get_string(pcfg->client, GAPC_COLOR_CHART_KEY, NULL); if (pstring) { gdk_color_parse (pstring, &pcfg->color_chart); } else { gdk_color_parse ("light blue", &pcfg->color_chart); } pstring = gconf_client_get_string(pcfg->client, GAPC_COLOR_TITLE_KEY, NULL); if (pstring) { gdk_color_parse (pstring, &pcfg->color_title); } else { gdk_color_parse ("blue", &pcfg->color_title); } return TRUE; } /* * Handle Object.Destroy Signal * have no choice be go away when destroyed */ static void cb_monitor_interface_destroy(GtkWidget * widget, PGAPC_MONITOR pm) { PGAPC_CONFIG pcfg = (PGAPC_CONFIG)pm->gp; GtkWidget *sbar = NULL; gint h_index = 0; g_return_if_fail(pm != NULL); g_return_if_fail(pcfg != NULL); pm->b_run = FALSE; if (pm->tid_graph_refresh) { g_source_remove(pm->tid_graph_refresh); } if (pm->tid_automatic_refresh) { g_source_remove(pm->tid_automatic_refresh); } if (pm->tid_thread_qwork != NULL) { pm->b_thread_stop = TRUE; g_async_queue_push(pm->q_network, pm); g_thread_join(pm->tid_thread_qwork); } g_mutex_free(pm->gm_update); g_async_queue_unref(pm->q_network); for (h_index = 0; h_index < GAPC_LINEGRAPH_MAX_SERIES; h_index++) { if (pm->phs.sq[h_index].gm_graph != NULL) { g_mutex_free(pm->phs.sq[h_index].gm_graph); } } if (pm->pht_Widgets != NULL) { g_hash_table_destroy(pm->pht_Widgets); g_hash_table_destroy(pm->pht_Status); pm->pht_Widgets = NULL; pm->pht_Status = NULL; } for (h_index = 0; h_index < GAPC_MAX_ARRAY; h_index++) { if (pm->pach_events[h_index] != NULL) { g_free(pm->pach_events[h_index]); } pm->pach_events[h_index] = NULL; if (pm->pach_status[h_index] != NULL) { g_free(pm->pach_status[h_index]); } pm->pach_status[h_index] = NULL; } if (pm->tray_icon != NULL) { gtk_widget_destroy(GTK_WIDGET(pm->tray_icon)); pm->tray_icon = NULL; pm->tray_image = NULL; } if (pm->menu != NULL) { gtk_widget_destroy(GTK_WIDGET(pm->menu)); pm->menu = NULL; } g_object_unref (pm->tooltips); lg_graph_data_series_remove_all ( pm->phs.plg ); sbar = g_hash_table_lookup (pcfg->pht_Widgets, "StatusBar"); if (sbar) { gchar *pch = NULL; gtk_statusbar_pop(GTK_STATUSBAR(sbar), pcfg->i_info_context); pch = g_strdup_printf ("Monitor for %s Destroyed!...", pm->pch_host ); gtk_statusbar_push(GTK_STATUSBAR(sbar), pcfg->i_info_context, pch); g_free(pch); } g_free(pm); return; } static void cb_main_interface_destroy(GtkWidget * widget, PGAPC_CONFIG pcfg) { gint x = 0; g_return_if_fail(pcfg != NULL); pcfg->b_run = FALSE; gapc_panel_gconf_destroy(pcfg); if (GTK_IS_TREE_VIEW(pcfg->prefs_treeview)) { gtk_widget_destroy(GTK_WIDGET(pcfg->prefs_treeview)); pcfg->prefs_treeview = NULL; } if (GTK_IS_TREE_VIEW(pcfg->monitor_treeview)) { gtk_widget_destroy(GTK_WIDGET(pcfg->monitor_treeview)); pcfg->monitor_treeview = NULL; } if (pcfg->prefs_model != NULL) { gtk_list_store_clear(GTK_LIST_STORE(pcfg->prefs_model)); g_object_unref(G_OBJECT(pcfg->prefs_model)); pcfg->prefs_model = NULL; } if (pcfg->monitor_model != NULL) { gtk_list_store_clear(GTK_LIST_STORE(pcfg->monitor_model)); g_object_unref(G_OBJECT(pcfg->monitor_model)); pcfg->monitor_model = NULL; } if (pcfg->pht_Widgets != NULL) { g_hash_table_destroy(pcfg->pht_Widgets); g_hash_table_destroy(pcfg->pht_Status); } for (x = 0; x < GAPC_N_ICONS; x++) { g_object_unref(pcfg->my_icons[x]); } g_object_unref (pcfg->tooltips); gtk_main_quit(); return; } /* * returns TRUE if helps was offered, else FALSE if input was all ok. */ static gint gapc_main_interface_parse_args(gint argc, gchar ** argv, PGAPC_CONFIG pcfg) { gchar *pch = NULL; GString *gs_parm1 = NULL, *gs_parm2 = NULL; gs_parm1 = g_string_new(GAPC_CP_GROUP_KEY); gs_parm2 = g_string_new(GAPC_CP_GROUP_KEY); /* *********************************************************** * * Get user input * - default to known values * - check config file for saved values -- careful not to override cmdline */ while (--argc > 0) { /* ADJUST COUNTER HERE */ g_string_assign(gs_parm1, argv[argc]); if (argv[argc + 1] != NULL) { g_string_assign(gs_parm2, argv[argc + 1]); } pch = g_strstr_len(gs_parm1->str, 6, "-help"); if (pch != NULL) { g_print("\nsyntax: gapcmon [--help]\n" "where: --help, this message, no command line options are available\n" "Skoona@Users.SourceForge.Net (GPL) 2006 \n\n"); g_string_free(gs_parm1, TRUE); g_string_free(gs_parm2, TRUE); return TRUE; /* trigger exit */ } } g_string_free(gs_parm1, TRUE); g_string_free(gs_parm2, TRUE); /* ********************************************************* * Apply instance value */ return FALSE; } /* * Create main interface with the following panels * - icon list * - preferences panel * - about panel */ static GtkWidget *gapc_main_interface_create(PGAPC_CONFIG pcfg) { GtkWindow *window = NULL; GdkPixbuf *pixbuf = NULL; GtkWidget *sbar = NULL, *notebook = NULL, *menu = NULL, *menu_item = NULL; GtkWidget *label = NULL, *button = NULL; GtkWidget *bbox = NULL, *lbox = NULL, *nbox = NULL, *box = NULL; gint i_page = 0; g_return_val_if_fail(pcfg != NULL, NULL); /* Create hash table for easy access to system widgets */ pcfg->pht_Status = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); pcfg->pht_Widgets = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); pixbuf = pcfg->my_icons[GAPC_ICON_DEFAULT]; pcfg->b_visible = FALSE; pcfg->tooltips = gtk_tooltips_new(); g_object_ref (pcfg->tooltips); gtk_object_sink (GTK_OBJECT(pcfg->tooltips)); pcfg->b_run = TRUE; pcfg->cb_last_monitor_deleted = -1; /* * Create the top level window for the notebook to be packed into.*/ window = g_object_new(GTK_TYPE_WINDOW, "border-width", 0, "destroy-with-parent", TRUE, "icon", pixbuf, "resizable", TRUE, "title", GAPC_WINDOW_TITLE, "type", GTK_WINDOW_TOPLEVEL, "type-hint", GDK_WINDOW_TYPE_HINT_NORMAL, "window-position", GTK_WIN_POS_NONE, NULL); pcfg->window = GTK_WIDGET(window); g_signal_connect(window, "destroy", G_CALLBACK(cb_main_interface_destroy), pcfg); g_signal_connect(window, "delete-event", G_CALLBACK(cb_main_interface_delete_event), pcfg); g_signal_connect(window, "show", G_CALLBACK(cb_main_interface_show), pcfg); g_signal_connect(window, "hide", G_CALLBACK(cb_main_interface_hide), pcfg); g_signal_connect(window, "window-state-event", G_CALLBACK(cb_util_manage_iconify_event), pcfg); gapc_panel_systray_icon_create(pcfg); lbox = gtk_vbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(window), lbox); gtk_widget_show(lbox); /* */ /* Notebook Box */ bbox = gtk_vbox_new(FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(bbox), 6); gtk_box_pack_start(GTK_BOX(lbox), bbox, TRUE, TRUE, 2); gtk_widget_show(bbox); nbox = gtk_hbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(bbox), nbox, TRUE, TRUE, 0); gtk_widget_show(nbox); /* create the status bar */ sbar = gtk_statusbar_new(); gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(sbar), FALSE); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("StatusBar"), sbar); gtk_box_pack_end(GTK_BOX(lbox), sbar, FALSE, TRUE, 0); gtk_widget_show(sbar); pcfg->i_info_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(sbar), "Informational"); /* buttons Box */ bbox = gtk_hbox_new(FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(bbox), 0); gtk_box_pack_end(GTK_BOX(lbox), bbox, FALSE, FALSE, 0); gtk_widget_show(bbox); box = gtk_hbutton_box_new(); gtk_container_set_border_width(GTK_CONTAINER(box), 6); gtk_box_pack_end(GTK_BOX(bbox), box, FALSE, FALSE, 2); gtk_widget_show(box); /* Create the top-level notebook */ notebook = gtk_notebook_new(); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP); gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE); gtk_notebook_set_homogeneous_tabs(GTK_NOTEBOOK(notebook), TRUE); gtk_box_pack_start(GTK_BOX(nbox), notebook, TRUE, TRUE, 0); gtk_widget_show(notebook); /* Create the main pages */ gapc_panel_monitor_list_page(pcfg, GTK_NOTEBOOK(notebook)); i_page = gapc_panel_preferences_page(pcfg, GTK_NOTEBOOK(notebook)); gapc_panel_graph_property_page(pcfg, notebook); gapc_panel_glossary_page(pcfg, notebook); gapc_panel_about_page(GTK_NOTEBOOK(notebook), GAPC_WINDOW_TITLE, GAPC_VERSION, pixbuf); label = gtk_label_new("" GAPC_GROUP_TITLE ""); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_line_wrap(GTK_LABEL(label), FALSE); gtk_box_pack_start(GTK_BOX(bbox), label, TRUE, TRUE, 0); gtk_widget_show(label); /* quit Control button */ /* button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_hide), GTK_WIDGET(window)); gtk_box_pack_end(GTK_BOX(box), button, TRUE, TRUE, 0); gtk_widget_show(button); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); gtk_widget_grab_default(button); */ button = gtk_button_new_from_stock(GTK_STOCK_QUIT); g_signal_connect(button, "clicked", G_CALLBACK(cb_main_interface_button_quit), pcfg); gtk_box_pack_end(GTK_BOX(box), button, TRUE, TRUE, 0); gtk_widget_show(button); gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), i_page); pcfg->menu = menu = gtk_menu_new(); menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_JUMP_TO, NULL); g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(cb_util_popup_menu_response_jumpto), pcfg); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); gtk_widget_show(menu_item); menu_item = gtk_separator_menu_item_new(); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); gtk_widget_show(menu_item); menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(cb_util_popup_menu_response_exit), pcfg); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); gtk_widget_show(menu_item); gtk_widget_show(menu); gtk_widget_show_all(lbox); return GTK_WIDGET(window); } /* * Creates a GtkGLGraph histogram linechart page */ static gint gapc_monitor_history_page(PGAPC_MONITOR pm, GtkWidget * notebook) { PGAPC_HISTORY pphs = (PGAPC_HISTORY) & pm->phs; PGAPC_CONFIG pcfg = (PGAPC_CONFIG) pm->gp; PLGRAPH plg = NULL; gint i_page = 0, i_series = 0, h_index = 0; GtkWidget *label = NULL, *box = NULL; gchar *pch = NULL; gchar *pch_colors[6]; gchar *pch_legend[] = { "LINEV", "LOADPCT", "TIMELEFT", "BCHARGE", "BATTV" }; g_return_val_if_fail(pm != NULL, -1); /* * Prepare the environment */ pphs->gp = (gpointer) pm; pphs->d_xinc = pm->d_refresh * pm->d_graph; lg_graph_debug = FALSE; for (h_index = 0; h_index < GAPC_LINEGRAPH_MAX_SERIES; h_index++) { if (pm->phs.sq[h_index].gm_graph != NULL) { g_mutex_free(pm->phs.sq[h_index].gm_graph); } pm->phs.sq[h_index].gm_graph = g_mutex_new(); } /* get values from graph properties */ pch_colors[0] = gtk_color_selection_palette_to_string ( &pcfg->color_linev, 1); pch_colors[1] = gtk_color_selection_palette_to_string ( &pcfg->color_loadpct, 1); pch_colors[2] = gtk_color_selection_palette_to_string ( &pcfg->color_timeleft, 1); pch_colors[3] = gtk_color_selection_palette_to_string ( &pcfg->color_bcharge, 1); pch_colors[4] = gtk_color_selection_palette_to_string ( &pcfg->color_battv, 1); pch_colors[5] = NULL; /* * Create notebook page page */ box = gtk_vbox_new(FALSE, 0); g_object_set_data ( G_OBJECT(box), "pcfg-pointer", pm->gp); label = gtk_label_new("Historical Summary"); i_page = gtk_notebook_append_page(GTK_NOTEBOOK(notebook), box, label); gtk_widget_show(GTK_WIDGET(box)); gtk_widget_show(label); /* * Create Chart surface */ plg = pphs->plg = lg_graph_create ( box, 300, 200 ); if (plg != NULL) { for (i_series = 0; i_series < GAPC_LINEGRAPH_MAX_SERIES; i_series++) { lg_graph_data_series_add (plg, pch_legend[i_series], pch_colors[i_series]); g_free (pch_colors[i_series]); } pch = g_strdup_printf( "sampled every %3.1f seconds", pm->phs.d_xinc); lg_graph_set_x_label_text (plg, pch); g_free(pch); lg_graph_set_chart_title (plg, pm->ch_title_info); } pm->tid_graph_refresh = gtk_timeout_add(((guint) (pphs->d_xinc * GAPC_REFRESH_FACTOR_1K )), (GSourceFunc) cb_util_line_chart_refresh, pphs); /* collect one right away */ pphs->b_startup = TRUE; g_timeout_add((guint) (pm->d_refresh * GAPC_REFRESH_FACTOR_1K + 75), (GSourceFunc) cb_util_line_chart_refresh, pphs); return i_page; } /* * Add a new data point until xrange is reached * then rotate back the y points and add new point to end * return TRUE is successful, FALSE other wise */ static gboolean cb_util_line_chart_refresh(PGAPC_HISTORY pg) { gint h_index = 0; PLGRAPH plg = NULL; PGAPC_MONITOR pm = NULL; g_return_val_if_fail(pg != NULL, FALSE); pm = (PGAPC_MONITOR) pg->gp; plg = pg->plg; g_return_val_if_fail(plg != NULL, FALSE); g_return_val_if_fail(pm != NULL, FALSE); if (!pm->b_run) /* stop this timer */ return FALSE; if (pm->b_graph_control) { g_timeout_add(100, (GSourceFunc) cb_util_line_chart_refresh_control, pm); return FALSE; } gdk_threads_enter(); for (h_index = 0; h_index < plg->i_num_series; h_index++) { lg_graph_data_series_add_value (plg, h_index, gapc_util_point_filter_reset(&(pg->sq[h_index])) ); } if (plg->i_points_available >= plg->x_range.i_max_scale ) { lg_graph_draw ( plg ); } else { lg_graph_data_series_draw_all (plg, TRUE); lg_graph_redraw ( plg ); } gdk_flush(); gdk_threads_leave(); if (pg->b_startup) { pg->b_startup = FALSE; return FALSE; } /* first data point collected */ return TRUE; } /* * Create and Initialize a Line Chart */ static PLGRAPH lg_graph_create (GtkWidget * box, gint width, gint height) { PLGRAPH plg = NULL; PGAPC_CONFIG pcfg = NULL; GtkWidget *drawing_area = NULL; GdkColor color; PangoFontDescription *font_desc = NULL; gchar *pstring = NULL; pcfg = (PGAPC_CONFIG)g_object_get_data (G_OBJECT(box), "pcfg-pointer"); g_return_val_if_fail (pcfg != NULL, NULL); plg = g_new0 (LGRAPH, 1); g_return_val_if_fail (plg != NULL, NULL); plg->cb_id = CB_GRAPH_ID; plg->x_range.cb_id = CB_RANGE_ID; plg->y_range.cb_id = CB_RANGE_ID; plg->b_tooltip_active = TRUE; /* * These must be set before the first drawing_area configure event */ lg_graph_set_chart_title (plg, "Waiting for Update"); lg_graph_set_y_label_text (plg, "Precentage of 100% normal"); lg_graph_set_x_label_text (plg, "Waiting for Update"); g_snprintf (plg->ch_tooltip_text, sizeof (plg->ch_tooltip_text), "%s", "Waiting for Graphable Data..."); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_title, 1); lg_graph_set_chart_title_color (plg, pstring); g_free (pstring); lg_graph_set_chart_scales_color (plg, "black"); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_chart, 1); lg_graph_set_chart_window_fg_color (plg, pstring); g_free (pstring); pstring = gtk_color_selection_palette_to_string ( &pcfg->color_window, 1); lg_graph_set_chart_window_bg_color (plg, pstring); g_free (pstring); /* Xminor divisions, Xmajor divisions, Xbotton scale, Xtop scale, ...y */ lg_graph_set_ranges (plg, 1, 2, 0, 40, 2, 10, 0, 110); drawing_area = plg->drawing_area = gtk_drawing_area_new (); gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), width, height); gtk_box_pack_start (GTK_BOX (box), drawing_area, TRUE, TRUE, 0); font_desc = pango_font_description_from_string ("Monospace 10"); gtk_widget_modify_font (drawing_area, font_desc); pango_font_description_free (font_desc); gtk_widget_realize (drawing_area); gtk_widget_show (drawing_area); plg->series_gc = gdk_gc_new (drawing_area->window); plg->window_gc = gdk_gc_new (drawing_area->window); plg->box_gc = gdk_gc_new (drawing_area->window); plg->scale_gc = gdk_gc_new (drawing_area->window); plg->title_gc = gdk_gc_new (drawing_area->window); gdk_gc_copy (plg->series_gc, drawing_area->style->fg_gc[GTK_WIDGET_STATE (drawing_area)]); gdk_gc_copy (plg->window_gc, drawing_area->style->bg_gc[GTK_WIDGET_STATE (drawing_area)]); gdk_gc_copy (plg->box_gc, drawing_area->style->fg_gc[GTK_WIDGET_STATE (drawing_area)]); gdk_gc_copy (plg->scale_gc, drawing_area->style->fg_gc[GTK_WIDGET_STATE (drawing_area)]); gdk_gc_copy (plg->title_gc, drawing_area->style->text_aa_gc[GTK_WIDGET_STATE (drawing_area)]); gdk_color_parse (plg->ch_color_window_bg, &color); gdk_gc_set_rgb_fg_color (plg->window_gc, &color); gdk_color_parse (plg->ch_color_chart_bg, &color); gdk_gc_set_rgb_fg_color (plg->box_gc, &color); gdk_color_parse (plg->ch_color_scale_fg, &color); gdk_gc_set_rgb_fg_color (plg->scale_gc, &color); gdk_color_parse (plg->ch_color_title_fg, &color); gdk_gc_set_rgb_fg_color (plg->title_gc, &color); /* --- Signals used to handle backing pixmap --- */ gtk_signal_connect (GTK_OBJECT (drawing_area), "configure_event", (GtkSignalFunc) lg_graph_configure_event_cb, plg); gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", (GtkSignalFunc) lg_graph_expose_event_cb, plg); gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", (GtkSignalFunc) lg_graph_motion_notify_event_cb, plg); gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", (GtkSignalFunc) lg_graph_button_press_event_cb, plg); return plg; } /* * Detailed Information Notebook Page */ static gint gapc_monitor_information_page(PGAPC_MONITOR pm, GtkWidget * notebook) { GtkWidget *frame, *label, *pbox, *lbox, *rbox, *gbox; GtkWidget *tbox, *tlbox, *trbox; gint i_page = 0; /* Create a Notebook Page */ gbox = gtk_frame_new(NULL); gtk_container_set_border_width(GTK_CONTAINER(gbox), 4); gtk_frame_set_shadow_type(GTK_FRAME(gbox), GTK_SHADOW_NONE); label = gtk_label_new("Detailed Information"); i_page = gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gbox, label); gtk_widget_show(gbox); tbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(gbox), tbox); gtk_widget_show(tbox); /* * create basic frame */ tlbox = gtk_vbox_new(TRUE, 2); gtk_box_pack_start(GTK_BOX(tbox), tlbox, TRUE, TRUE, 0); gtk_widget_show(tlbox); trbox = gtk_vbox_new(TRUE, 2); gtk_box_pack_end(GTK_BOX(tbox), trbox, TRUE, TRUE, 0); gtk_widget_show(trbox); frame = gtk_frame_new("Performance Summary"); gtk_frame_set_label_align(GTK_FRAME(frame), 0.1, 0.8); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); label = gtk_frame_get_label_widget(GTK_FRAME(frame)); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(tlbox), frame, TRUE, TRUE, 0); gtk_widget_show(frame); pbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(frame), pbox); gtk_widget_show(pbox); lbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pbox), lbox, FALSE, TRUE, 0); gtk_widget_show(lbox); rbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_end(GTK_BOX(pbox), rbox, TRUE, TRUE, 0); gtk_widget_show(rbox); label = gtk_label_new("Selftest running\n" "Number of transfers\n" "Reason last transfer\n" "Last transfer to battery\n" "Last transfer off battery\n" "Time on battery\n" "Cummulative on battery"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment((GtkMisc *) label, 1.0, 0.5); gtk_box_pack_start(GTK_BOX(lbox), label, FALSE, FALSE, 0); gtk_widget_show(label); label = gtk_label_new("Waiting for refresh\n"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment((GtkMisc *) label, 0.0, 0.0); gtk_box_pack_start(GTK_BOX(rbox), label, TRUE, TRUE, 0); g_hash_table_insert(pm->pht_Widgets, g_strdup("PerformanceSummary"), label); gtk_widget_show(label); frame = gtk_frame_new("Software Information"); gtk_frame_set_label_align(GTK_FRAME(frame), 0.1, 0.8); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); label = gtk_frame_get_label_widget(GTK_FRAME(frame)); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_end(GTK_BOX(tlbox), frame, TRUE, TRUE, 0); gtk_widget_show(frame); pbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(frame), pbox); gtk_widget_show(pbox); lbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pbox), lbox, FALSE, FALSE, 0); gtk_widget_show(lbox); rbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_end(GTK_BOX(pbox), rbox, TRUE, TRUE, 0); gtk_widget_show(rbox); label = gtk_label_new("APCUPSD version\n" "Monitored UPS name\n" "Cable Driver type\n" "Configuration mode\n" "Last started\n" "UPS State"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment((GtkMisc *) label, 1.0, 0.5); gtk_box_pack_start(GTK_BOX(lbox), label, FALSE, FALSE, 0); gtk_widget_show(label); label = gtk_label_new("Waiting for refresh\n"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment((GtkMisc *) label, 0.0, 0.0); gtk_box_pack_start(GTK_BOX(rbox), label, TRUE, TRUE, 0); g_hash_table_insert(pm->pht_Widgets, g_strdup("SoftwareInformation"), label); gtk_widget_show(label); frame = gtk_frame_new("UPS Metrics"); gtk_frame_set_label_align(GTK_FRAME(frame), 0.1, 0.8); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); label = gtk_frame_get_label_widget(GTK_FRAME(frame)); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(trbox), frame, TRUE, TRUE, 0); gtk_widget_show(frame); gbox = gtk_vbox_new(TRUE, 2); gtk_container_add(GTK_CONTAINER(frame), gbox); gtk_widget_show(gbox); gapc_util_barchart_create(pm, gbox, "HBar1", 10.8, "Waiting for refresh"); gapc_util_barchart_create(pm, gbox, "HBar2", 40.8, "Waiting for refresh"); gapc_util_barchart_create(pm, gbox, "HBar3", 0.8, "Waiting for refresh"); gapc_util_barchart_create(pm, gbox, "HBar4", 40.8, "Waiting for refresh"); gapc_util_barchart_create(pm, gbox, "HBar5", 10.8, "Waiting for refresh"); frame = gtk_frame_new("Product Information"); gtk_frame_set_label_align(GTK_FRAME(frame), 0.1, 0.8); gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); label = gtk_frame_get_label_widget(GTK_FRAME(frame)); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_box_pack_end(GTK_BOX(trbox), frame, TRUE, TRUE, 0); gtk_widget_show(frame); pbox = gtk_hbox_new(FALSE, 4); gtk_container_add(GTK_CONTAINER(frame), pbox); gtk_widget_show(pbox); lbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(pbox), lbox, FALSE, FALSE, 0); gtk_widget_show(lbox); rbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_end(GTK_BOX(pbox), rbox, TRUE, TRUE, 0); gtk_widget_show(rbox); label = gtk_label_new("Device\n" "Serial\n" "Manf date\n" "Firmware\n" "Batt date\n" "Wattage"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_RIGHT); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment((GtkMisc *) label, 1.0, 0.5); gtk_box_pack_start(GTK_BOX(lbox), label, FALSE, FALSE, 0); gtk_widget_show(label); label = gtk_label_new("Waiting for refresh\n"); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_misc_set_alignment((GtkMisc *) label, 0.0, 0.0); gtk_box_pack_start(GTK_BOX(rbox), label, TRUE, TRUE, 0); g_hash_table_insert(pm->pht_Widgets, g_strdup("ProductInformation"), label); gtk_widget_show(label); return i_page; } /* * Events and Status Report Pages */ static gint gapc_monitor_text_report_page(PGAPC_MONITOR pm, GtkWidget * notebook, gchar * pchTitle, gchar * pchKey) { PangoFontDescription *font_desc; GtkWidget *scrolled, *view, *label; gint i_page = 0; scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); label = gtk_label_new(pchTitle); i_page = gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled, label); gtk_widget_show(scrolled); view = gtk_text_view_new(); gtk_container_add(GTK_CONTAINER(scrolled), view); gtk_widget_show(view); /* Change default font throughout the widget */ font_desc = pango_font_description_from_string("Monospace 9"); gtk_widget_modify_font(view, font_desc); pango_font_description_free(font_desc); gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE); gtk_text_view_set_left_margin(GTK_TEXT_VIEW(view), 5); g_hash_table_insert(pm->pht_Widgets, g_strdup(pchKey), view); return i_page; } static gint gapc_panel_glossary_page(PGAPC_CONFIG pcfg, GtkWidget * notebook) { GtkWidget *scrolled, *label, *vbox; gint i_page = 0; gchar *ptext = GAPC_GLOSSARY; GdkColor color; gdk_color_parse("white", &color); vbox = gtk_vbox_new(FALSE, 0); label = gtk_label_new("Glossary"); i_page = gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox, label); gtk_widget_show(vbox); scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled), GTK_SHADOW_ETCHED_IN); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); gtk_container_add(GTK_CONTAINER(vbox), scrolled); gtk_widget_show(GTK_WIDGET(scrolled)); label = gtk_label_new(ptext); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_FILL); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), label); gtk_widget_show(label); gtk_widget_modify_bg(gtk_widget_get_parent(label), GTK_STATE_NORMAL, &color); return i_page; } static gint gapc_panel_graph_property_page(PGAPC_CONFIG pcfg, GtkWidget * notebook) { GtkWidget *s_frame, *w_frame, *label, *s_box, *w_box, *frame, *hbox, *pbox; GtkWidget *cb_linev, *cb_loadpct, *cb_timeleft, *cb_bcharge, *cb_battv; GtkWidget *cb_window, *cb_chart, *cb_text; GtkWidget *bbox, *b_undo; gint i_page = 0; frame = gtk_vbox_new(FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(frame), 4); label = gtk_label_new("Graph Properties"); i_page = gtk_notebook_append_page(GTK_NOTEBOOK(notebook), frame, label); gtk_widget_show(frame); /* * Prepare the top color choice area */ hbox = gtk_hbox_new(FALSE, 2); gtk_container_add ( GTK_CONTAINER (frame), hbox ); gtk_widget_show(hbox); /* * Prepare the bottom button/message area */ bbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_end ( GTK_BOX (frame), bbox, TRUE, TRUE, 2); gtk_widget_show(bbox); b_undo = gtk_button_new_from_stock (GTK_STOCK_UNDO); gtk_box_pack_start ( GTK_BOX (bbox), b_undo, FALSE, TRUE, 2); gtk_widget_show(b_undo); g_signal_connect (GTK_OBJECT(b_undo), "clicked", G_CALLBACK(cb_panel_property_color_reset), pcfg); label = gtk_label_new("These values will be used during the" " creation of a monitor. Disable and " "enable existing monitors to push values now."); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_box_pack_end ( GTK_BOX (bbox), label, TRUE, TRUE, 2); gtk_widget_show(label); /* * Prepare the top color choice area */ s_frame = gtk_frame_new("Series Color"); gtk_container_set_border_width(GTK_CONTAINER(s_frame), 4); gtk_frame_set_shadow_type(GTK_FRAME(s_frame), GTK_SHADOW_IN); gtk_box_pack_start(GTK_BOX(hbox), s_frame, TRUE, TRUE, 0); gtk_widget_show(s_frame); s_box = gtk_vbox_new(FALSE, 0); gtk_container_add ( GTK_CONTAINER (s_frame), s_box ); gtk_widget_show(s_box); pbox = gtk_hbox_new(TRUE, 4); gtk_box_pack_start(GTK_BOX(s_box), pbox, FALSE, FALSE, 0); label = gtk_label_new("LINEV"); gtk_box_pack_start(GTK_BOX(pbox), label, FALSE, FALSE, 0); gtk_widget_show(label); cb_linev = gtk_color_button_new_with_color( &pcfg->color_linev); gtk_color_button_set_title (GTK_COLOR_BUTTON(cb_linev), "LINEV"); gtk_box_pack_start(GTK_BOX(pbox), cb_linev, FALSE, FALSE, 0); gtk_widget_show(cb_linev); g_object_set_data (G_OBJECT(cb_linev), "gconf-client", pcfg->client ); g_signal_connect ( GTK_OBJECT(cb_linev), "color-set", G_CALLBACK(cb_panel_property_color_change), GAPC_COLOR_LINEV_KEY); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("color-linev"), cb_linev); pbox = gtk_hbox_new(TRUE, 4); gtk_box_pack_start(GTK_BOX(s_box), pbox, FALSE, FALSE, 0); label = gtk_label_new("LOADPCT"); gtk_box_pack_start(GTK_BOX(pbox), label, FALSE, FALSE, 0); gtk_widget_show(label); cb_loadpct = gtk_color_button_new_with_color( &pcfg->color_loadpct); gtk_color_button_set_title (GTK_COLOR_BUTTON(cb_loadpct), "LOADPCT"); gtk_box_pack_start(GTK_BOX(pbox), cb_loadpct, FALSE, FALSE, 0); gtk_widget_show(cb_loadpct); g_object_set_data (G_OBJECT(cb_loadpct), "gconf-client", pcfg->client ); g_signal_connect ( GTK_OBJECT(cb_loadpct), "color-set", G_CALLBACK(cb_panel_property_color_change), GAPC_COLOR_LOADPCT_KEY); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("color-loadpct"), cb_loadpct); pbox = gtk_hbox_new(TRUE, 4); gtk_box_pack_start(GTK_BOX(s_box), pbox, FALSE, FALSE, 0); label = gtk_label_new("TIMELEFT"); gtk_box_pack_start(GTK_BOX(pbox), label, FALSE, FALSE, 0); gtk_widget_show(label); cb_timeleft = gtk_color_button_new_with_color( &pcfg->color_timeleft); gtk_color_button_set_title (GTK_COLOR_BUTTON(cb_timeleft), "TIMELEFT"); gtk_box_pack_start(GTK_BOX(pbox), cb_timeleft, FALSE, FALSE, 0); gtk_widget_show(cb_timeleft); g_object_set_data (G_OBJECT(cb_timeleft), "gconf-client", pcfg->client ); g_signal_connect ( GTK_OBJECT(cb_timeleft), "color-set", G_CALLBACK(cb_panel_property_color_change), GAPC_COLOR_TIMELEFT_KEY); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("color-timeleft"), cb_timeleft); pbox = gtk_hbox_new(TRUE, 4); gtk_box_pack_start(GTK_BOX(s_box), pbox, FALSE, FALSE, 0); label = gtk_label_new("BCHARGE"); gtk_box_pack_start(GTK_BOX(pbox), label, FALSE, FALSE, 0); gtk_widget_show(label); cb_bcharge = gtk_color_button_new_with_color( &pcfg->color_bcharge); gtk_color_button_set_title (GTK_COLOR_BUTTON(cb_bcharge), "BCHARGE"); gtk_box_pack_start(GTK_BOX(pbox), cb_bcharge, FALSE, FALSE, 0); gtk_widget_show(cb_bcharge); g_object_set_data (G_OBJECT(cb_bcharge), "gconf-client", pcfg->client ); g_signal_connect ( GTK_OBJECT(cb_bcharge), "color-set", G_CALLBACK(cb_panel_property_color_change), GAPC_COLOR_BCHARGE_KEY); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("color-bcharge"), cb_bcharge); pbox = gtk_hbox_new(TRUE, 4); gtk_box_pack_start(GTK_BOX(s_box), pbox, FALSE, FALSE, 0); label = gtk_label_new("BATTV"); gtk_box_pack_start(GTK_BOX(pbox), label, FALSE, FALSE, 0); gtk_widget_show(label); cb_battv = gtk_color_button_new_with_color( &pcfg->color_battv); gtk_color_button_set_title (GTK_COLOR_BUTTON(cb_battv), "BATTV"); gtk_box_pack_start(GTK_BOX(pbox), cb_battv, FALSE, FALSE, 0); gtk_widget_show(cb_battv); g_object_set_data (G_OBJECT(cb_battv), "gconf-client", pcfg->client ); g_signal_connect ( GTK_OBJECT(cb_battv), "color-set", G_CALLBACK(cb_panel_property_color_change), GAPC_COLOR_BATTV_KEY); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("color-battv"), cb_battv); w_frame = gtk_frame_new("Window Colors"); gtk_container_set_border_width(GTK_CONTAINER(w_frame), 4); gtk_frame_set_shadow_type(GTK_FRAME(w_frame), GTK_SHADOW_IN); gtk_box_pack_start(GTK_BOX(hbox), w_frame, TRUE, TRUE, 0); gtk_widget_show(w_frame); w_box = gtk_vbox_new(FALSE, 0); gtk_container_add ( GTK_CONTAINER (w_frame), w_box ); gtk_widget_show(w_box); pbox = gtk_hbox_new(TRUE, 4); gtk_box_pack_start(GTK_BOX(w_box), pbox, FALSE, FALSE, 0); label = gtk_label_new("Window Background"); gtk_box_pack_start(GTK_BOX(pbox), label, FALSE, FALSE, 0); gtk_widget_show(label); cb_window = gtk_color_button_new_with_color( &pcfg->color_window); gtk_color_button_set_title (GTK_COLOR_BUTTON(cb_window), "Window Background"); gtk_box_pack_start(GTK_BOX(pbox), cb_window, FALSE, FALSE, 0); gtk_widget_show(cb_window); g_object_set_data (G_OBJECT(cb_window), "gconf-client", pcfg->client ); g_signal_connect ( GTK_OBJECT(cb_window), "color-set", G_CALLBACK(cb_panel_property_color_change), GAPC_COLOR_WINDOW_KEY); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("color-window"), cb_window); pbox = gtk_hbox_new(TRUE, 4); gtk_box_pack_start(GTK_BOX(w_box), pbox, FALSE, FALSE, 0); label = gtk_label_new("Chart Background"); gtk_box_pack_start(GTK_BOX(pbox), label, FALSE, FALSE, 0); gtk_widget_show(label); cb_chart = gtk_color_button_new_with_color( &pcfg->color_chart); gtk_color_button_set_title (GTK_COLOR_BUTTON(cb_chart), "Chart Background"); gtk_box_pack_start(GTK_BOX(pbox), cb_chart, FALSE, FALSE, 0); gtk_widget_show(cb_chart); g_object_set_data (G_OBJECT(cb_chart), "gconf-client", pcfg->client ); g_signal_connect ( GTK_OBJECT(cb_chart), "color-set", G_CALLBACK(cb_panel_property_color_change), GAPC_COLOR_CHART_KEY); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("color-chart"), cb_chart); pbox = gtk_hbox_new(TRUE, 4); gtk_box_pack_start(GTK_BOX(w_box), pbox, FALSE, FALSE, 0); label = gtk_label_new("Title Texts"); gtk_box_pack_start(GTK_BOX(pbox), label, FALSE, FALSE, 0); gtk_widget_show(label); cb_text = gtk_color_button_new_with_color( &pcfg->color_title); gtk_color_button_set_title (GTK_COLOR_BUTTON(cb_text), "Title Texts"); gtk_box_pack_start(GTK_BOX(pbox), cb_text, FALSE, FALSE, 0); gtk_widget_show(cb_text); g_object_set_data (G_OBJECT(cb_text), "gconf-client", pcfg->client ); g_signal_connect ( GTK_OBJECT(cb_text), "color-set", G_CALLBACK(cb_panel_property_color_change), GAPC_COLOR_TITLE_KEY); g_hash_table_insert(pcfg->pht_Widgets, g_strdup("color-title"), cb_text); return i_page; } /* * Creates monitor interface with the normal panels */ static GtkWidget *gapc_monitor_interface_create(PGAPC_CONFIG pcfg, gint i_monitor, GtkTreeIter * iter) { GtkWindow *window = NULL; GdkPixbuf *pixbuf = NULL; GtkWidget *sbar = NULL, *notebook = NULL, *menu = NULL, *menu_item = NULL; GtkWidget *label = NULL, *button = NULL; GtkWidget *bbox = NULL, *lbox = NULL, *nbox = NULL, *box = NULL; PGAPC_MONITOR pm = NULL; gint z_monitor = 0; g_return_val_if_fail(pcfg != NULL, NULL); pm = g_new0(GAPC_MONITOR, 1); g_return_val_if_fail(pm != NULL, NULL); pm->cb_id = CB_MONITOR_ID; pm->cb_monitor_num = i_monitor; pm->gp = (gpointer) pcfg; pm->phs.gp = (gpointer) pm; pm->phs.cb_id = CB_HISTORY_ID; pm->phs.sq[0].cb_id = CB_SUMM_ID; pm->phs.sq[1].cb_id = CB_SUMM_ID; pm->phs.sq[2].cb_id = CB_SUMM_ID; pm->phs.sq[3].cb_id = CB_SUMM_ID; pm->phs.sq[4].cb_id = CB_SUMM_ID; pm->my_icons = pcfg->my_icons; pm->pht_Status = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); pm->pht_Widgets = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); pm->phs.b_startup = TRUE; pm->cb_enabled = TRUE; pm->b_visible = FALSE; pm->b_run = TRUE; pm->i_icon_index = GAPC_ICON_DEFAULT; pm->i_old_icon_index = GAPC_ICON_ONLINE; pm->tray_icon = NULL; pm->tray_image = NULL; if (pm->pch_host != NULL) { g_free(pm->pch_host); } gtk_tree_model_get(GTK_TREE_MODEL(pcfg->prefs_model), iter, GAPC_PREFS_SYSTRAY, &(pm->cb_use_systray), GAPC_PREFS_PORT, &(pm->i_port), GAPC_PREFS_WATT, &(pm->i_watt), GAPC_PREFS_GRAPH, &(pm->d_graph), GAPC_PREFS_HOST, &(pm->pch_host), GAPC_PREFS_REFRESH, &(pm->d_refresh), GAPC_PREFS_MONITOR, &z_monitor, -1); pixbuf = pm->my_icons[GAPC_ICON_DEFAULT]; pm->tooltips = gtk_tooltips_new(); g_object_ref (pm->tooltips); gtk_object_sink (GTK_OBJECT(pm->tooltips)); pm->gm_update = g_mutex_new(); pm->client = pcfg->client; pm->i_old_icon_index = GAPC_ICON_DEFAULT; pm->monitor_model = pcfg->monitor_model; g_snprintf(pm->ch_title_info, GAPC_MAX_TEXT, "%s {%s}", GAPC_WINDOW_TITLE, pm->pch_host); if (pm->d_refresh < GAPC_REFRESH_MIN_INCREMENT) { pm->d_refresh = GAPC_REFRESH_DEFAULT; } if (pm->d_graph < GAPC_REFRESH_MIN_INCREMENT) { pm->d_graph = GAPC_LINEGRAPH_REFRESH_FACTOR; } /* * Start the central network thread */ pm->q_network = g_async_queue_new(); g_return_val_if_fail(pm->q_network != NULL, NULL); pm->b_thread_stop = FALSE; pm->tid_thread_qwork = g_thread_create((GThreadFunc) gapc_net_thread_qwork, pm, TRUE, NULL); /* * Create the top level window for the notebook to be packed into.*/ window = g_object_new(GTK_TYPE_WINDOW, "border-width", 0, "destroy-with-parent", TRUE, "icon", pixbuf, "resizable", TRUE, "title", pm->ch_title_info, "type", GTK_WINDOW_TOPLEVEL, "type-hint", GDK_WINDOW_TYPE_HINT_NORMAL, "window-position", GTK_WIN_POS_NONE, NULL); pm->window = GTK_WIDGET(window); g_signal_connect(window, "destroy", G_CALLBACK(cb_monitor_interface_destroy), pm); g_signal_connect(window, "delete-event", G_CALLBACK(cb_monitor_interface_delete_event), pm); g_signal_connect(window, "show", G_CALLBACK(cb_monitor_interface_show), pm); g_signal_connect(window, "hide", G_CALLBACK(cb_monitor_interface_hide), pm); g_signal_connect(window, "window-state-event", G_CALLBACK(cb_util_manage_iconify_event), pm); g_snprintf(pm->ch_title_info, GAPC_MAX_TEXT, "%s\n{%s}", GAPC_WINDOW_TITLE, pm->pch_host); lbox = gtk_vbox_new(FALSE, 2); gtk_container_add(GTK_CONTAINER(window), lbox); gtk_widget_show(lbox); /* */ /* Notebook Box */ bbox = gtk_vbox_new(FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(bbox), 6); gtk_box_pack_start(GTK_BOX(lbox), bbox, TRUE, TRUE, 2); gtk_widget_show(bbox); nbox = gtk_hbox_new(TRUE, 0); gtk_box_pack_start(GTK_BOX(bbox), nbox, TRUE, TRUE, 0); gtk_widget_show(nbox); /* create the status bar */ sbar = gtk_statusbar_new(); gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(sbar), FALSE); g_hash_table_insert(pm->pht_Widgets, g_strdup("StatusBar"), sbar); gtk_box_pack_end(GTK_BOX(lbox), sbar, FALSE, TRUE, 0); gtk_widget_show(sbar); pm->i_info_context = gtk_statusbar_get_context_id(GTK_STATUSBAR(sbar), "Informational"); /* buttons Box */ bbox = gtk_hbox_new(FALSE, 0); gtk_container_set_border_width(GTK_CONTAINER(bbox), 0); gtk_box_pack_end(GTK_BOX(lbox), bbox, FALSE, FALSE, 0); gtk_widget_show(bbox); box = gtk_hbutton_box_new(); gtk_hbutton_box_set_layout_default(GTK_BUTTONBOX_SPREAD); gtk_container_set_border_width(GTK_CONTAINER(box), 4); gtk_box_pack_end(GTK_BOX(bbox), box, TRUE, TRUE, 0); gtk_widget_show(box); /* Create the top-level notebook */ pm->notebook = notebook = gtk_notebook_new(); gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook), GTK_POS_TOP); gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook), TRUE); gtk_notebook_set_homogeneous_tabs(GTK_NOTEBOOK(notebook), FALSE); gtk_box_pack_start(GTK_BOX(nbox), notebook, TRUE, TRUE, 0); gtk_widget_show(notebook); /* Create the main pages */ gapc_monitor_history_page(pm, notebook); gapc_monitor_information_page(pm, notebook); gapc_monitor_text_report_page(pm, notebook, "Power Events", "EventsPage"); gapc_monitor_text_report_page(pm, notebook, "Full UPS Status", "StatusPage"); /* Create the main pages */ label = gtk_label_new(pm->ch_title_info); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); gtk_label_set_line_wrap(GTK_LABEL(label), FALSE); gtk_box_pack_start(GTK_BOX(bbox), label, TRUE, TRUE, 0); gtk_widget_show(label); g_hash_table_insert(pm->pht_Widgets, g_strdup("TitleStatus"), label); /* refresh Control button */ button = gtk_button_new_from_stock(GTK_STOCK_REFRESH); GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT); g_signal_connect(button, "clicked", G_CALLBACK(cb_monitor_interface_button_refresh), pm); gtk_box_pack_end(GTK_BOX(box), button, TRUE, TRUE, 0); gtk_widget_show(button); gtk_widget_grab_default(button); /* button = gtk_button_new_from_stock(GTK_STOCK_CLOSE); g_signal_connect(button, "clicked", G_CALLBACK(cb_monitor_interface_button_close), pm); gtk_box_pack_end(GTK_BOX(box), button, TRUE, TRUE, 0); gtk_widget_show(button); */ gtk_notebook_set_current_page(GTK_NOTEBOOK(notebook), 0); gapc_panel_monitor_model_rec_add(pcfg, pm); gapc_panel_systray_icon_create(pm); g_async_queue_push(pm->q_network, (gpointer) pm); pm->tid_automatic_refresh = g_timeout_add((guint) (pm->d_refresh * GAPC_REFRESH_FACTOR_1K), (GSourceFunc) cb_monitor_automatic_refresh, pm); pm->menu = menu = gtk_menu_new(); menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_JUMP_TO, NULL); g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(cb_util_popup_menu_response_jumpto), pm); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); gtk_widget_show(menu_item); menu_item = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, NULL); g_signal_connect(G_OBJECT(menu_item), "activate", G_CALLBACK(cb_util_popup_menu_response_exit), pm); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menu_item); gtk_widget_show(menu_item); gtk_widget_show(menu); sbar = g_hash_table_lookup (pcfg->pht_Widgets, "StatusBar"); if (sbar) { gchar *pch = NULL; gtk_statusbar_pop(GTK_STATUSBAR(sbar), pcfg->i_info_context); pch = g_strdup_printf ("Monitor for %s Created!...", pm->pch_host); gtk_statusbar_push(GTK_STATUSBAR(sbar), pcfg->i_info_context, pch); g_free(pch); } return GTK_WIDGET(window); } /* * Creates monitor interface with the normal panels */ static void gapc_monitor_interface_destroy(PGAPC_CONFIG pcfg, gint i_monitor) { GtkTreeIter iter; PGAPC_MONITOR pm = NULL; g_return_if_fail(pcfg != NULL); if (gapc_util_treeview_get_iter_from_monitor(pcfg->monitor_model, &iter, i_monitor)) { gtk_tree_model_get(pcfg->monitor_model, &iter, GAPC_MON_POINTER, &pm, -1); } if ((pm == NULL) || (pm->window == NULL)) { return; } if (!pm->cb_enabled) { return; } pm->b_run = FALSE; gtk_list_store_remove(GTK_LIST_STORE(pcfg->monitor_model), &iter); if (pm->cb_use_systray) { gapc_panel_systray_icon_remove(pm); } if (pm->menu != NULL) { gtk_widget_destroy(pm->menu); } if (pm->window != NULL) { gtk_widget_destroy(pm->window); } return; } /* * Main entry point */ extern int main(int argc, char *argv[]) { PGAPC_CONFIG pcfg = NULL; GtkWidget *window = NULL; /* * Initialize GLib thread support, and GTK */ g_type_init(); g_thread_init(NULL); gdk_threads_init(); gtk_init(&argc, &argv); pcfg = g_new0(GAPC_CONFIG, 1); pcfg->cb_id = CB_CONTROL_ID; /* * Get the instance number for this execution */ if (gapc_main_interface_parse_args(argc, argv, pcfg)) { return 1; /* exit if user only wanted help */ } gapc_util_load_icons(pcfg); gapc_panel_gconf_init(pcfg); window = gapc_main_interface_create(pcfg); if (!pcfg->b_use_systray) { pcfg->b_visible = TRUE; g_object_set(pcfg->window, "skip-pager-hint", FALSE, "skip-taskbar-hint", FALSE, NULL); gtk_window_present(GTK_WINDOW(pcfg->window)); } gapc_panel_gconf_watch(pcfg); /* * enter the GTK main loop */ gdk_threads_enter(); gtk_main(); gdk_flush(); gdk_threads_leave(); return (0); } apcupsd-3.14.14/src/gapcmon/gapcmon.desktop000066400000000000000000000005471274230402600205630ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Type=Application Version=1.0 Exec=gapcmon Icon=apcupsd Name=APCUPSD Monitor GenericName=gapcmon Comment=Gtk/GUI Monitor program for (U)ninterruptible (P)ower (S)upply under the management of the APCUPSD.sourceforge.net package, also available at gapcmon.sourceforge.net Terminal=false Categories=GTK;Application;System;Monitor; apcupsd-3.14.14/src/gapcmon/gapcmon.h000066400000000000000000000456341274230402600173470ustar00rootroot00000000000000/* gapcmon.h serial-0087-0 ************************************ GKT+ GUI with Notification Area (System Tray) support. Program for monitoring the apcupsd.sourceforge.net package. Copyright (C) 2006 James Scott, Jr. 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef GAPC_H_ #define GAPC_H_ G_BEGIN_DECLS #ifndef VERSION #define GAPC_VERSION "0.8.7-0" #else #define GAPC_VERSION VERSION #endif #ifndef ICON_DIR #define ICON_DIR "/usr/share" #endif #define GAPC_PROG_NAME "gapcmon" #define GAPC_GROUP_TITLE " Uninterruptible Power Supply Monitor...\n for APCUPSD" #define GAPC_WINDOW_TITLE "gapcmon: UPS Information Panels" #define GAPC_CP_GROUP_KEY "/apps/gapcmon/controller" #define GAPC_CP_SYSTRAY_KEY "/apps/gapcmon/controller/use_systray" #define GAPC_CP_PAGERS_KEY "/apps/gapcmon/controller/skip_pagers" #define GAPC_COLOR_LINEV_KEY "/apps/gapcmon/controller/color_linev" #define GAPC_COLOR_LOADPCT_KEY "/apps/gapcmon/controller/color_loadpct" #define GAPC_COLOR_TIMELEFT_KEY "/apps/gapcmon/controller/color_timeleft" #define GAPC_COLOR_BCHARGE_KEY "/apps/gapcmon/controller/color_bcharge" #define GAPC_COLOR_BATTV_KEY "/apps/gapcmon/controller/color_battv" #define GAPC_COLOR_WINDOW_KEY "/apps/gapcmon/controller/color_window" #define GAPC_COLOR_CHART_KEY "/apps/gapcmon/controller/color_chart" #define GAPC_COLOR_TITLE_KEY "/apps/gapcmon/controller/color_title" #define GAPC_MID_GROUP_KEY "/apps/gapcmon/monitor" #define GAPC_ENABLE_KEY "/apps/gapcmon/monitor/%d/enabled" #define GAPC_SYSTRAY_KEY "/apps/gapcmon/monitor/%d/use_systray" #define GAPC_PAGER_KEY "/apps/gapcmon/monitor/%d/skip_pagers" /* not used */ #define GAPC_PORT_KEY "/apps/gapcmon/monitor/%d/port_number" #define GAPC_REFRESH_KEY "/apps/gapcmon/monitor/%d/network_interval" #define GAPC_GRAPH_KEY "/apps/gapcmon/monitor/%d/graph_interval" #define GAPC_HOST_KEY "/apps/gapcmon/monitor/%d/host_name" #define GAPC_WATT_KEY "/apps/gapcmon/monitor/%d/ups_wattage" #define GAPC_MAX_ARRAY 256 /* for arrays or lists */ #define GAPC_MAX_TEXT 256 /* for strings */ #define GAPC_ICON_SIZE 24 /* Ideal size of icons */ #define GAPC_MAX_BUFFER 512 /* Size of a text buffer or local string */ #define GAPC_REFRESH_FACTOR_1K 1000 /* micro.secs for visual refresh */ #define GAPC_REFRESH_FACTOR_ONE_TIME 500 #define GAPC_HOST_DEFAULT "localhost" #define GAPC_PORT_DEFAULT 3551 #define GAPC_WATT_DEFAULT 600 #define GAPC_REFRESH_DEFAULT 8.0 #define GAPC_REFRESH_MIN_INCREMENT 1.0 /* Minimum refresh cycle seconds */ #define GAPC_LINEGRAPH_XMAX 40 #define GAPC_LINEGRAPH_YMAX 110 #define GAPC_LINEGRAPH_MAX_SERIES 5 #define GAPC_LINEGRAPH_REFRESH_FACTOR 30.0 /* Num refreshes per collection */ #define SKNET_HUGE_ARRAY 4096 #define SKNET_REG_ARRAY 1024 #define SKNET_STR_ARRAY 256 typedef struct _SKNET_Control_Data { gint cb_id; GIOChannel *ioc; /* socket io channel */ gint fd_server; /* our local server-socket */ gint i_port; /* dest host port */ gboolean b_network_control; /* TRUE signals resolve address needed */ gchar ch_ip_string[SKNET_STR_ARRAY]; /* dest host ip addr or dns name */ gchar ch_ip_client[SKNET_STR_ARRAY]; /* incoming host ip addr or dns name */ gchar ch_ip_client_port[SKNET_STR_ARRAY]; /* incoming host ip port */ gchar ch_session_message[SKNET_HUGE_ARRAY]; gchar ch_error_msg[SKNET_REG_ARRAY]; gpointer gip; /* struct sockaddr_in -- resolved tcp-ip address */ gpointer gp_reserved; /* reserved private pointer for me */ gpointer gp_user_data; /* private pointer for YOU or user */ gint i_byte_counter; /* public byte counter */ } SKNET_COMMS, *PSKCOMM; typedef enum _Control_Block_id { CB_SERIES_ID, CB_RANGE_ID, CB_GRAPH_ID, CB_HISTORY_ID, CB_MONITOR_ID, CB_CONTROL_ID, CB_COLUMN_ID, CB_SUMM_ID, CB_PSKCOMM_ID, CB_N_ID } GAPCDataID; typedef enum _State_Icons_IDs { GAPC_ICON_ONLINE, GAPC_ICON_ONBATT, GAPC_ICON_CHARGING, GAPC_ICON_DEFAULT, GAPC_ICON_UNPLUGGED, GAPC_ICON_NETWORKERROR, GAPC_N_ICONS } GAPC_IconType; typedef enum _Timer_IDs { GAPC_TIMER_AUTO, GAPC_TIMER_DEDICATED, GAPC_TIMER_CONTROL, GAPC_N_TIMERS } GAPC_TimerType; typedef enum _Prefs_Store_IDs { GAPC_PREFS_MONITOR, GAPC_PREFS_ENABLED, GAPC_PREFS_SYSTRAY, GAPC_PREFS_PORT, GAPC_PREFS_REFRESH, GAPC_PREFS_GRAPH, GAPC_PREFS_HOST, GAPC_PREFS_WATT, GAPC_N_PREFS_COLUMNS } GAPC_PrefsType; typedef enum _Monitor_Store_IDs { GAPC_MON_MONITOR, GAPC_MON_ICON, GAPC_MON_STATUS, GAPC_MON_POINTER, GAPC_MON_UPSSTATE, GAPC_N_MON_COLUMNS } GAPC_MonitorType; typedef struct _Preferences_Key_Records { gchar k_enabled[GAPC_MAX_TEXT]; gchar k_use_systray[GAPC_MAX_TEXT]; gchar k_port_number[GAPC_MAX_TEXT]; gchar k_network_interval[GAPC_MAX_TEXT]; gchar k_graph_interval[GAPC_MAX_TEXT]; gchar k_host_name[GAPC_MAX_TEXT]; gchar v_host_name[GAPC_MAX_TEXT]; } GAPC_PKEYS, *PGAPC_PKEYS; /* Control structure for TreeView columns and callbacks */ typedef struct _Prefs_Column_Data { GAPCDataID cb_id; /* This is REQUIRED TO BE 1ST in struct */ guint cb_monitor_num; /* monitor number 1-based */ guint i_col_num; GConfClient *client; GtkTreeModel *prefs_model; /* GtkListStore */ } GAPC_PREFS_COLUMN, *PGAPC_PREFS_COLUMN; typedef struct _Monitor_Column_Data { GAPCDataID cb_id; /* This is REQUIRED TO BE 1ST in struct */ guint cb_monitor_num; /* monitor number 1-based */ guint i_col_num; GConfClient *client; GtkTreeModel *monitor_model; /* GtkListStore */ } GAPC_MON_COLUMN, *PGAPC_MON_COLUMN; typedef struct _GAPC_H_CHART { GAPCDataID cb_id; gdouble d_value; gboolean b_center_text; gchar c_text[GAPC_MAX_TEXT]; GdkRectangle rect; } GAPC_BAR_H, *PGAPC_BAR_H; typedef struct _GAPC_SUM_SQUARES { GAPCDataID cb_id; gint point_count; gdouble this_point; gdouble this_answer; gdouble last_point; gdouble last_answer; gdouble answer_summ; gdouble point_min; gdouble point_max; GMutex *gm_graph; /* Control mutex for graphics filter */ } GAPC_SUMS, *PGAPC_SUMS; typedef struct _LGRAPH_SERIES { GAPCDataID cb_id; gint i_series_id; /* is this series number 1 2 or 3, ZERO based */ gint i_point_count; /* 1 based */ gint i_max_points; /* 1 based */ gchar ch_legend_text[GAPC_MAX_TEXT]; gchar ch_legend_color[GAPC_MAX_TEXT]; GdkColor legend_color; gdouble d_max_value; gdouble d_min_value; gdouble *lg_point_dvalue; /* array of doubles y values zero based, x = index */ GdkPoint *point_pos; /* last gdk position each point - recalc on evey draw */ } LG_SERIES, *PLG_SERIES; typedef struct _LGRAPH_RANGES { GAPCDataID cb_id; gint i_inc_minor_scale_by; /* minor increments */ gint i_inc_major_scale_by; /* major increments */ gint i_min_scale; /* minimum scale value - ex: 0 */ gint i_max_scale; /* maximum scale value - ex: 100 */ gint i_num_minor; /* number of minor points */ gint i_num_major; /* number of major points */ gint i_minor_inc; /* pixels per minor increment */ gint i_major_inc; /* pixels per major increment */ } LG_RANGE , *PLG_RANGE; typedef struct _LG_GRAPH { GAPCDataID cb_id; GtkWidget *drawing_area; GdkPixmap *pixmap; /* --- Backing pixmap for drawing area --- */ GdkGC *window_gc; GdkGC *box_gc; GdkGC *scale_gc; GdkGC *title_gc; GdkGC *series_gc; /* data points and tooltip info */ gint i_num_series; /* 1 based */ GList *lg_series; /* double-linked list of data series PLG_SERIES */ GList *lg_series_time; /* time_t of each sample */ gint i_points_available; gboolean b_tooltip_active; /* actual size of graph area */ gint width; gint height; /* buffer around all sides */ gint x_border; gint y_border; /* current mouse position */ gboolean b_mouse_onoff; GdkPoint mouse_pos; GdkModifierType mouse_state; /* top/left or baseline of labels and titles */ gchar ch_color_window_bg[GAPC_MAX_TEXT]; gchar ch_color_chart_bg[GAPC_MAX_TEXT]; gchar ch_color_title_fg[GAPC_MAX_BUFFER]; GdkRectangle x_label; GdkRectangle y_label; GdkRectangle x_title; GdkRectangle x_tooltip; gchar ch_tooltip_text[GAPC_MAX_BUFFER]; gchar *x_label_text; gchar *y_label_text; gchar *x_title_text; /* position and area of main graph plot area */ GdkRectangle plot_box; gchar ch_color_scale_fg[GAPC_MAX_TEXT]; LG_RANGE x_range; LG_RANGE y_range; } LGRAPH , *PLGRAPH; /* * Control structure for GtkExtra Charts in Information Window */ typedef struct _History_Page_Data { GAPCDataID cb_id; /* This is REQUIRED TO BE 1ST in struct */ guint cb_monitor_num; /* monitor number 1-based */ gpointer *gp; /* ptr back to the monitor */ LGRAPH *plg; /* Line Graph pointer */ GAPC_SUMS sq[GAPC_LINEGRAPH_MAX_SERIES + 4]; /* data point collector */ gdouble d_xinc; /* base refresh increment for graph */ gboolean b_startup; } GAPC_HISTORY, *PGAPC_HISTORY; /* * Control structure per active monitor icon in panel */ typedef struct _Monitor_Instance_Data { GAPCDataID cb_id; /* This is REQUIRED TO BE 1ST in struct */ guint cb_monitor_num; /* Begin Preference values 1-based */ gboolean cb_enabled; gboolean cb_use_systray; gchar *pch_host; gint i_port; gint i_watt; /* rated wattage of UPS*/ gfloat d_refresh; gfloat d_graph; /* End Preference values */ gchar ch_title_info[GAPC_MAX_TEXT]; GtkWidget *window; /* information window */ GtkWidget *menu; /* Popup Menu */ GtkWidget *notebook; /* information Notebook */ gboolean b_visible; /* is the info window visible */ guint i_info_context; /* StatusBar message Context */ gboolean b_run; /* controller for all monitor resources -- except thread */ gboolean b_thread_stop; /* single flag to stop thread */ GThread *tid_thread_qwork; /* Background Thread */ GMutex *gm_update; /* Control mutex for hashtables and thread */ GAsyncQueue *q_network; guint i_netbusy_counter; guint tid_automatic_refresh; /* monitor refresh timer id */ guint tid_graph_refresh; gboolean b_data_available; /* Flag from thread indicating data ready */ gboolean b_network_control; /* TRUE signals resolve address needed */ gboolean b_timer_control; /* TRUE signals change in refresh interval */ gboolean b_graph_control; /* TRUE signals change in refresh interval */ gboolean b_refresh_button; /* Flag to thread to immediately update */ GHashTable *pht_Status; /* Private hashtable status key=values */ GHashTable *pht_Widgets; /* Private hashtable holding widget ptrs */ GtkTooltips *tooltips; guint i_icon_index; gint i_old_icon_index; gint i_icon_size; gint i_icon_height; gint i_icon_width; GdkPixbuf **my_icons; EggTrayIcon *tray_icon; GtkWidget *tray_image; GList *data_status; /* Holds line of status text */ GList *data_events; /* Holds line of event text */ gchar *pach_status[GAPC_MAX_ARRAY]; /* Holds line of status text */ gchar *pach_events[GAPC_MAX_ARRAY]; /* Holds line of event text */ GConfClient *client; /* GCONF id */ gpointer *gp; /* assumed to point to pcfg */ GtkTreeModel *monitor_model; /* GtkListStore */ GAPC_HISTORY phs; /* structure for history notebook page */ PSKCOMM psk; /* communication structure */ } GAPC_MONITOR, *PGAPC_MONITOR; /* * Control structure for root panel object -- this is the anchor */ typedef struct _System_Control_Data { GAPCDataID cb_id; /* This is REQUIRED TO BE 1ST in struct */ GList *cb_glist_monitors; /* assumed to point to PGAPC_MONITOR */ guint cb_last_monitor; /* last selected from icon list - 1-based */ gboolean b_use_systray; /* gconf parms */ gboolean b_tooltips; gboolean b_run; /* operational flag */ gchar *pch_gkeys[GAPC_N_PREFS_COLUMNS]; GConfClient *client; /* GCONF id */ guint i_group_id; /* GCONF dir notify ids - controller */ guint i_prefs_id; /* GCONF dir notify ids - prefs-view */ GtkWidget *window; GtkWidget *menu; /* Popup Menu */ gboolean b_visible; /* is the info window visible */ GtkTreeModel *prefs_model; /* GtkListStore */ GtkTreeView *prefs_treeview; GtkTreeSelection *prefs_select; guint prefs_last_monitor; /* assigning monitor numbers */ gint cb_last_monitor_deleted; /* overide gconf inconsistency on kde */ GtkTreeModel *monitor_model; /* GtkListStore */ GtkTreeView *monitor_treeview; GtkTreeSelection *monitor_select; GtkWidget *image; GtkTooltips *tooltips; EggTrayIcon *tray_icon; GtkWidget *tray_image; GtkTooltips *tray_tooltips; gint i_icon_size; gint i_icon_height; gint i_icon_width; GHashTable *pht_Widgets; /* hashtable holding widget ptrs */ GHashTable *pht_Status; /* hashtable holding status text */ guint i_info_context; /* StatusBar Context */ GdkPixbuf *my_icons[GAPC_N_ICONS + 8]; /* Global graph properties */ GdkColor color_linev; GdkColor color_loadpct; GdkColor color_timeleft; GdkColor color_bcharge; GdkColor color_battv; GdkColor color_window; GdkColor color_chart; GdkColor color_title; } GAPC_CONFIG, *PGAPC_CONFIG; /* ************************************************************************* */ #define GAPC_GLOSSARY "GAPCMON\n \ A monitor for UPS's under the management of APCUPSD.\n\n \ When active, gapcmon provides three visual objects to interact with. \ First is the main control.panel where monitors are defined, enabled, and listed when \ active. Second are notification area icons that manage the visibility of each window or \ panel. The third is an information window showing historical and current details of \ a UPS being monitored. \n\ \n\n\ CONTROL PANEL WINDOW PAGES\n\ ACTIVE MONITORS PAGE\n\ \n\ A short list of the monitors that are currently enabled. The list shows \ each monitor's current icon, its status, and a brief summary of its key metrics. \ Double-clicking a row causes the information window of that monitor to be presented.\n\ \n\ PREFERENCES PAGE\n\ -for the monitors\n\ \n\ Enable:\nCauses the monitor to immediately run, create an info-window, \ and add an entry in the icon list window.\n\ \n\ Use Trayicon:\nAdds a notification area icon which toggles \ the visibility of the monitor info-window when clicked.\n\ \n\ Network refresh:\nThe number of seconds between collections of status and event \ data from the network.\n\ \n\ Graph refresh:\nMultiplied by the network refresh value to determine \ the total number of seconds between graph data collections.\n\ \n\ Hostname or IP Address:\nThe hostname or address where an apcupsd NIS interface \ is running.\n\ \n\ Port:\nThe NIS access port on the APCUPSD host; defaults to 3551.\n\ \n\ Add | Remove Buttons:\nButtons to add or remove a monitor entry from the \ list of monitors above. Add, adds with defaulted values at end of list. Remove, removes \ the currently selected row.\n\ \n\n\ -for the control.panel\n\ \n\ Use Trayicon:\nAdds a notification area icon which toggles \ the visibility of the control panel when clicked. Note: all tray icons \ contain a popup menu with the choices of 'JumpTo' interactive window, and 'Quit' \ which either hides the window or destroys it in the case of the control panel. \ Additionally, when use_trayicon is selected, the title of the window is removed from \ the desktop's windowlist or taskbar.\n\ \n\n\ GRAPH PROPERTIES PAGE\n\ \n\ Allows you to specify the colors to be used for each of the five data series on the \ Historical Summary graph page of each monitor. General window background colors can \ also be specified.\n\ \n\n\ GLOSSARY PAGE\n\ \n\ This page of introductory text.\n\ \n\ ABOUT PAGE\n\ More standard vanity, and my e-mail ID in case something breaks.\n\ \n\n\ MONITOR INFORMATION WINDOW PAGES\n\ HISTORICAL SUMMARY PAGE\n\ A graph showing the last 40 samples of five key data points, scaled to represent all \ points as a percentage of that value's normal range. A data point's value can be \ viewed by moving the mouse over any desired point, a tooltip will appear \ showing the color and value of all points at that interval. Data points are collected \ periodically, based on the product of graph_refresh times network_refresh in seconds. \ These tooltips can be enabled or disabled by clicking anywhere on the graph once.\n\ \n\ DETAILED INFORMATION PAGE\n\ A more in-depth view of the monitored UPS's environmental values. Software, product, \ and operational values are available and updated every 'network_refresh' seconds.\n\ \n\ POWER EVENTS PAGE\n\ A log of all power events recorded by APCUPSD on the server.\n\ \n\ FULL UPS STATUS PAGE\n\ A listing of the output from apcaccess showing the actual state as reported \ by the UPS.\n\ \n\ " /* ************************************************************************* */ G_END_DECLS #endif /*GAPC_H_ */ apcupsd-3.14.14/src/gapcmon/gethostname.c000066400000000000000000000040661274230402600202260ustar00rootroot00000000000000#include #include #include #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) { struct hostent *hp; int herr,res; if (*hstbuflen == 0) { *hstbuflen = 1024; *tmphstbuf = (char *)malloc (*hstbuflen); } while (( res = gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr)) && (errno == ERANGE)) { /* Enlarge the buffer. */ *hstbuflen *= 2; *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen); } if (res) return NULL; return hp; } #endif #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) { struct hostent *hp; int herr; if (*hstbuflen == 0) { *hstbuflen = 1024; *tmphstbuf = (char *)malloc (*hstbuflen); } while ((NULL == ( hp = gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr))) && (errno == ERANGE)) { /* Enlarge the buffer. */ *hstbuflen *= 2; *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen); } return hp; } #endif #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) { if (*hstbuflen == 0) { *hstbuflen = sizeof(struct hostent_data); *tmphstbuf = (char *)malloc (*hstbuflen); } else if (*hstbuflen < sizeof(struct hostent_data)) { *hstbuflen = sizeof(struct hostent_data); *tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen); } memset((void *)(*tmphstbuf),0,*hstbuflen); if (0 != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) return NULL; return hostbuf; } #endif #ifdef HAVE_FUNC_GETHOSTBYNAME_R_0 #warning WARNING! Your system does not have a thread-safe DNS resolver (gethostbyname_r)! #warning WARNING! Name service lookups may be corrupted. Consider switching to #warning WARNING! a more thread-friendly platform. struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) { return gethostbyname(host); } #endif apcupsd-3.14.14/src/gapcmon/onbatt.png000066400000000000000000000003121274230402600175270ustar00rootroot00000000000000PNG  IHDRabKGDtIME9HclIDAT8SA ćiyZ6 mMڴ ^Gsh,$0U+>$HNUt3/+rR& INI9ҰiD~'q6asIENDB`apcupsd-3.14.14/src/gapcmon/online.png000066400000000000000000000003541274230402600175320ustar00rootroot00000000000000PNG  IHDRabKGDtIME:yZ8IDAT8˭R 1;17@S1Ā#C\J!o<#&QB[$t*N`0n03H*mv 班di^U/vDpu%F]wp&c7RnҒ房J?r,1wPdIENDB`apcupsd-3.14.14/src/lib/000077500000000000000000000000001274230402600146605ustar00rootroot00000000000000apcupsd-3.14.14/src/lib/Makefile000066400000000000000000000006751274230402600163300ustar00rootroot00000000000000topdir:=../.. include $(topdir)/autoconf/targets.mak SRCS = apcconfig.c apcerror.c apcevents.c apcexec.c \ apcfile.c apclibnis.c apclock.c apclog.c apcsignal.c \ apcstatus.c asys.c newups.c md5.c statmgr.cpp gethostname.c \ amutex.cpp astring.cpp autil.cpp atimer.cpp athread.cpp \ usbvidpid.cpp cloexec.c $(LIBEXTRAOBJ) all-targets: libapc.a libapc.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/lib/amutex.cpp000066400000000000000000000023101274230402600166630ustar00rootroot00000000000000/* * amutex.cpp * * Simple mutex wrapper class. */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "amutex.h" #include "autil.h" const char *amutex::DEFAULT_NAME = "unnamed_mutex"; amutex::amutex(const char *name, bool recursive) : _name(name) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, recursive ? PTHREAD_MUTEX_RECURSIVE : PTHREAD_MUTEX_NORMAL); pthread_mutex_init(&_mutex, &attr); pthread_mutexattr_destroy(&attr); } amutex::~amutex() { pthread_mutex_destroy(&_mutex); } apcupsd-3.14.14/src/lib/apcconfig.c000066400000000000000000000636221274230402600167660ustar00rootroot00000000000000/* * apcconfig.c * * Config file parser. */ /* * Copyright (C) 2000-2004 Kern Sibbald * Copyright (C) Riccardo Facchetti * Copyright (C) Jonathan H N Chin * Copyright (C) 1996-99 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" char argvalue[MAXSTRING]; /* * We use more complicated defaults for these constants in some cases, * so stick them in arrays that can be modified at runtime. */ char APCCONF[APC_FILENAME_MAX] = SYSCONFDIR APCCONF_FILE; /* ---------------------------------------------------------------------- */ typedef int (HANDLER) (UPSINFO *, int, const GENINFO *, const char *); static HANDLER match_int, match_range, match_str; static HANDLER match_facility, match_index; static HANDLER obsolete; #ifdef UNSUPPORTED_CODE static HANDLER start_ups, end_ups; #endif /* ---------------------------------------------------------------------- */ static const GENINFO onoroff[] = { { "off", "off", FALSE }, { "on", "on", TRUE }, { NULL, "value must be ON or OFF", FALSE }, }; static const GENINFO cables[] = { { "simple", "Custom Cable Simple", CUSTOM_SIMPLE }, { "smart", "Custom Cable Smart", CABLE_SMART }, { "ether", "Ethernet Link", APC_NET }, { "940-0119A", "APC Cable 940-0119A", APC_940_0119A }, { "940-0127A", "APC Cable 940-0127A", APC_940_0127A }, { "940-0128A", "APC Cable 940-0128A", APC_940_0128A }, { "940-0020B", "APC Cable 940-0020B", APC_940_0020B }, { "940-0020C", "APC Cable 940-0020C", APC_940_0020C }, { "940-0023A", "APC Cable 940-0023A", APC_940_0023A }, { "940-0024B", "APC Cable 940-0024B", CABLE_SMART }, { "940-0024C", "APC Cable 940-0024C", CABLE_SMART }, { "940-1524C", "APC Cable 940-1524C", CABLE_SMART }, { "940-0024G", "APC Cable 940-0024G", CABLE_SMART }, { "940-0625A", "APC Cable 940-0625A", CABLE_SMART }, { "940-0095A", "APC Cable 940-0095A", APC_940_0095A }, { "940-0095B", "APC Cable 940-0095B", APC_940_0095B }, { "940-0095C", "APC Cable 940-0095C", APC_940_0095C }, { "MAM-04-02-2000", "MAM Cable 04-02-2000", MAM_CABLE }, { "usb", "USB Cable", USB_CABLE }, { NULL, "*invalid-cable*", NO_CABLE }, }; static const GENINFO upsclasses[] = { { "standalone", "Stand Alone", STANDALONE }, { "shareslave", "ShareUPS Slave", SHARESLAVE }, { "sharemaster", "ShareUPS Master", SHAREMASTER }, { NULL, "*invalid-ups-class*", NO_CLASS }, }; static const GENINFO logins[] = { { "always", "always", ALWAYS }, /* must come first */ { "disable", "disable", NEVER }, { "timeout", "timeout", TIMEOUT }, { "percent", "percent", PERCENT }, { "minutes", "minutes", MINUTES }, { NULL, "*invalid-login-mode*", NO_LOGON }, }; static const GENINFO modes[] = { { "disable", "Network & ShareUPS Disabled", DISABLE }, { "share", "ShareUPS", SHARE }, { NULL, "*invalid-ups-mode*", NO_SHARE_NET }, }; static const GENINFO types[] = { { "dumb", "DUMB UPS Driver", DUMB_UPS }, { "apcsmart", "APC Smart UPS (any)", APCSMART_UPS }, { "usb", "USB UPS Driver", USB_UPS }, { "snmp", "SNMP UPS Driver", SNMPLITE_UPS }, { "net", "NETWORK UPS Driver", NETWORK_UPS }, { "test", "TEST UPS Driver", TEST_UPS }, { "pcnet", "PCNET UPS Driver", PCNET_UPS }, { "modbus", "MODBUS UPS Driver", MODBUS_UPS }, { NULL, "*invalid-ups-type*", NO_UPS }, }; typedef struct { const char *key; HANDLER *handler; size_t offset; const GENINFO *values; } PAIRS; static const PAIRS table[] = { /* General parameters */ {"UPSNAME", match_str, WHERE(upsname), SIZE(upsname)}, {"UPSCABLE", match_range, WHERE(cable), cables}, {"UPSTYPE", match_range, WHERE(mode), types}, {"DEVICE", match_str, WHERE(device), SIZE(device)}, {"POLLTIME", match_int, WHERE(polltime), 0}, /* Paths */ {"LOCKFILE", match_str, WHERE(lockpath), SIZE(lockpath)}, {"SCRIPTDIR", match_str, WHERE(scriptdir), SIZE(scriptdir)}, {"PWRFAILDIR", match_str, WHERE(pwrfailpath), SIZE(pwrfailpath)}, {"NOLOGINDIR", match_str, WHERE(nologinpath), SIZE(nologinpath)}, /* Configuration parameters used during power failures */ {"ANNOY", match_int, WHERE(annoy), 0}, {"ANNOYDELAY", match_int, WHERE(annoydelay), 0}, {"ONBATTERYDELAY", match_int, WHERE(onbattdelay), 0}, {"TIMEOUT", match_int, WHERE(maxtime), 0}, {"NOLOGON", match_range, WHERE(nologin), logins}, {"BATTERYLEVEL", match_int, WHERE(percent), 0}, {"MINUTES", match_int, WHERE(runtime), 0}, {"KILLDELAY", match_int, WHERE(killdelay), 0}, /* Configuration parmeters for network information server */ {"NETSERVER", match_index, WHERE(netstats), onoroff}, {"NISIP", match_str, WHERE(nisip), SIZE(nisip)}, {"NISPORT", match_int, WHERE(statusport), 0}, /* Configuration parameters for event logging */ {"EVENTSFILE", match_str, WHERE(eventfile), SIZE(eventfile)}, {"EVENTSFILEMAX", match_int, WHERE(eventfilemax), 0}, /* Configuration parameters to control system logging */ {"FACILITY", match_facility, 0, 0}, {"STATFILE", match_str, WHERE(statfile), SIZE(statfile)}, {"LOGSTATS", match_index, WHERE(logstats), onoroff}, {"STATTIME", match_int, WHERE(stattime), 0}, {"DATATIME", match_int, WHERE(datatime), 0}, /* Values used to set UPS EPROM for --configure */ {"SELFTEST", match_str, WHERE(selftest), SIZE(selftest)}, {"HITRANSFER", match_int, WHERE(hitrans), 0}, {"LOTRANSFER", match_int, WHERE(lotrans), 0}, {"LOWBATT", match_int, WHERE(dlowbatt), 0}, {"WAKEUP", match_int, WHERE(dwake), 0}, {"RETURNCHARGE", match_int, WHERE(rtnpct), 0}, {"OUTPUTVOLTS", match_int, WHERE(NomOutputVoltage), 0}, {"SLEEP", match_int, WHERE(dshutd), 0}, {"BEEPSTATE", match_str, WHERE(beepstate), SIZE(beepstate)}, {"BATTDATE", match_str, WHERE(battdat), SIZE(battdat)}, {"SENSITIVITY", match_str, WHERE(sensitivity), SIZE(sensitivity)}, /* Configuration statements for network sharing of the UPS */ {"UPSCLASS", match_range, WHERE(upsclass), upsclasses}, {"UPSMODE", match_range, WHERE(sharenet), modes }, {"NETTIME", match_int, WHERE(polltime), 0 }, /* * Obsolete configuration options: To be removed in the future. * The warning string is passed in the GENINFO* field since it is * not used any more for obsoleted options: we are only interested in * printing the message. * There is a new meaning for offset field, too. If TRUE will bail out, * if FALSE it will continue to run apcupsd. This way we can bail out * if an obsolete option is too important to continue running apcupsd. */ {"CONTROL", obsolete, TRUE, (GENINFO *)"CONTROL config directive is obsolete" }, {"NETACCESS", obsolete, TRUE, (GENINFO *)"NETACCESS config directive is obsolete" }, {"MASTER", obsolete, TRUE, (GENINFO *)"MASTER config directive is obsolete" }, {"USERMAGIC", obsolete, FALSE, (GENINFO *)"USERMAGIC config directive is obsolete" }, {"SLAVE", obsolete, FALSE, (GENINFO *)"SLAVE config directive is obsolete" }, {"NETPORT", obsolete, FALSE, (GENINFO *)"NETPORT config directive is obsolete" }, {"NETSTATUS", obsolete, FALSE, (GENINFO *)"NETSTATUS config directive is obsolete" }, {"SERVERPORT", obsolete, FALSE, (GENINFO *)"SERVERPORT config directive is obsolete"}, /* must be last */ {NULL, 0, 0, 0} }; static int obsolete(UPSINFO *ups, int offset, const GENINFO * junk, const char *v) { char *msg = (char *)junk; fprintf(stderr, "%s\n", msg); if (!offset) { fprintf(stderr, "error ignored.\n"); return SUCCESS; } return FAILURE; } static int match_int(UPSINFO *ups, int offset, const GENINFO * junk, const char *v) { int x; if (sscanf(v, "%d", &x)) { *(int *)AT(ups, offset) = x; return SUCCESS; } return FAILURE; } static int match_range(UPSINFO *ups, int offset, const GENINFO * vs, const char *v) { char x[MAXSTRING]; INTERNALGENINFO *t; if (!vs) { /* Shouldn't ever happen so abort if it ever does. */ Error_abort("%s: Bogus configuration table! Fix and recompile.\n", argvalue); } if (!sscanf(v, "%s", x)) return FAILURE; for (; vs->name; vs++) if (!strcasecmp(x, vs->name)) break; t = (INTERNALGENINFO *) AT(ups, offset); /* Copy the structure */ if (vs->name == NULL) { /* * A NULL here means that the config value is bogus, so * print error message (and log it). */ log_event(ups, LOG_WARNING, "%s: Bogus configuration value (%s)\n", argvalue, vs->long_name); fprintf(stderr, "%s: Bogus configuration value (%s)\n", argvalue, vs->long_name); return FAILURE; } /* * THIS IS VERY UGLY. If some idiot like myself doesn't * know enough to define all the appropriate variables * with all the correct ordering and sizes, this will * overwrite memory. */ t->type = vs->type; strlcpy(t->name, vs->name, sizeof(t->name)); strlcpy(t->long_name, vs->long_name, sizeof(t->long_name)); return SUCCESS; } /* * Similar to match range except that it only returns the index of the * item. */ static int match_index(UPSINFO *ups, int offset, const GENINFO * vs, const char *v) { char x[MAXSTRING]; if (!vs) { /* Shouldn't ever happen so abort if it ever does. */ Error_abort("%s: Bogus configuration table! Fix and recompile.\n", argvalue); } if (!sscanf(v, "%s", x)) return FAILURE; for (; vs->name; vs++) if (!strcasecmp(x, vs->name)) break; if (vs->name == NULL) { /* * A NULL here means that the config value is bogus, so * print error message (and log it). */ log_event(ups, LOG_WARNING, "%s: Bogus configuration value (%s)\n", argvalue, vs->long_name); fprintf(stderr, "%s: Bogus configuration value (%s)\n", argvalue, vs->long_name); return FAILURE; } /* put it in ups buffer */ *(int *)AT(ups, offset) = vs->type; return SUCCESS; } /* * We accept strings containing internal whitespace (in order to support * paths with spaces in them) but truncate after '#' since we assume it * marks a comment. */ static int match_str(UPSINFO *ups, int offset, const GENINFO * gen, const char *v) { char x[MAXSTRING]; long size = (long)gen; /* Copy the string so we can edit it in place */ strlcpy(x, v, sizeof(x)); /* Remove trailing comment, if there is one */ char *ptr = strchr(x, '#'); if (ptr) *ptr = '\0'; /* Remove any trailing whitespace */ ptr = x + strlen(x) - 1; while (ptr >= x && isspace(*ptr)) *ptr-- = '\0'; strlcpy((char *)AT(ups, offset), x, (int)size); return SUCCESS; } static int match_facility(UPSINFO *ups, int offset, const GENINFO *junk, const char *v) { const struct { const char *fn; int fi; } facnames[] = { {"daemon", LOG_DAEMON}, {"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1}, {"local2", LOG_LOCAL2}, {"local3", LOG_LOCAL3}, {"local4", LOG_LOCAL4}, {"local5", LOG_LOCAL5}, {"local6", LOG_LOCAL6}, {"local7", LOG_LOCAL7}, {"lpr", LOG_LPR}, {"mail", LOG_MAIL}, {"news", LOG_NEWS}, {"uucp", LOG_UUCP}, {"user", LOG_USER}, {NULL, -1} }; int i; char x[MAXSTRING]; int oldfac; if (!sscanf(v, "%s", x)) return FAILURE; oldfac = ups->sysfac; for (i = 0; facnames[i].fn; i++) { if (!(strcasecmp(facnames[i].fn, x))) { ups->sysfac = facnames[i].fi; /* if it changed, close log file and reopen it */ if (ups->sysfac != oldfac) { closelog(); openlog("apcupsd", LOG_CONS | LOG_PID, ups->sysfac); } return SUCCESS; } } return FAILURE; } /* ---------------------------------------------------------------------- */ /** ** This function has been so buggy, I thought commentary was needed. ** Be careful about changing anything. Make sure you understand what is ** going on first. Even the people who wrote it kept messing it up... 8^) **/ static int ParseConfig(UPSINFO *ups, char *line) { const PAIRS *p; char *key, *value; /** ** Hopefully my notation is obvious enough: ** (a) : a ** a|b : a or b ** a? : zero or one a ** a* : zero or more a ** a+ : one or more a ** ** On entry, situation is expected to be: ** ** line = WS* ((KEY (WS+ VALUE)* WS* (WS+ COMMENT)?) | COMMENT?) (EOL|EOF) ** key = undef ** value = undef ** ** if line is not of this form we will eventually return an error ** line, key, value point to null-terminated strings ** EOF may be end of file, or if it occurs alone signifies null string ** **/ /* skip initial whitespace */ for (key = line; *key && isspace(*key); key++) ; /** ** key = ((KEY (WS+ VALUE)* WS* (WS+ COMMENT)?) | COMMENT?) (EOL|EOF) ** value = undef **/ /* catch EOF (might actually be only an empty line) and comments */ if (!*key || (*key == '#')) return (SUCCESS); /** ** key = (KEY (WS+ VALUE)* WS* (WS+ COMMENT)? (EOL|EOF) ** value = undef **/ /* convert key to UPPERCASE */ for (value = key; *value && !isspace(*value); value++) *value = toupper(*value); /** ** key = KEY (WS+ VALUE)* WS* (WS+ COMMENT)? (EOL|EOF) ** value = (WS+ VALUE)* WS* (WS+ COMMENT)? (EOL|EOF) **/ /* null out whitespace in the string */ for (; *value && isspace(*value); value++) *value = '\0'; /** ** key = KEY ** value = (VALUE (WS+ VALUE)* WS* (WS+ COMMENT)? (EOL|EOF)) ** | (COMMENT (EOL|EOF)) ** | EOF ** ** key is now fully `normalised' (no leading or trailing garbage) ** value contains zero or more whitespace delimited elements and there ** may be a trailing comment. **/ /* look for key in table */ for (p = table; p->key && strcmp(p->key, key); p++) ; /** ** It is *not* the responsibility of a dispatcher (ie. ParseConfig()) ** to parse `value'. ** Parsing `value' is the responsibility of the handler (ie. p->handler()). ** (Although one could conceive of the case where a ParseConfig()-alike ** function were invoked recursively as the handler...!) ** ** Currently all the handler functions (match_int(), match_str(), etc) ** just use sscanf() to pull out the bits they want out of `value'. ** ** In particular, if "%s" is used, leading/trailing whitespace ** is automatically removed. ** ** In addition, unused bits of value are simply discarded if the handler ** does not use them. So trailing garbage on lines is unimportant. **/ if (p->key) { if (p->handler) return (p->handler(ups, p->offset, p->values, value)); else return (SUCCESS); } else { return (FAILURE); } } /* ---------------------------------------------------------------------- */ #define BUF_SIZE 1000 /* * Setup general defaults for the ups structure. * N.B. Do not zero the structure because it already has * pthreads structures initialized. */ void init_ups_struct(UPSINFO *ups) { ups->fd = -1; ups->set_plugged(); strlcpy(ups->nologin.name, logins[0].name, sizeof(ups->nologin.name)); strlcpy(ups->nologin.long_name, logins[0].long_name, sizeof(ups->nologin.long_name)); ups->nologin.type = logins[0].type; ups->annoy = 5 * 60; /* annoy every 5 mins */ ups->annoydelay = 60; /* must be > than annoy to work, why???? */ ups->onbattdelay = 6; ups->maxtime = 0; ups->nologin_time = 0; ups->nologin_file = FALSE; ups->stattime = 0; ups->datatime = 0; ups->polltime = 60; ups->percent = 10; ups->runtime = 5; ups->netstats = TRUE; ups->statusport = NISPORT; ups->upsmodel[0] = 0; /* end of string */ /* EPROM values that can be changed with config directives */ strlcpy(ups->sensitivity, "-1", sizeof(ups->sensitivity)); /* no value */ ups->dwake = -1; ups->dshutd = -1; strlcpy(ups->selftest, "-1", sizeof(ups->selftest)); /* no value */ ups->lotrans = -1; ups->hitrans = -1; ups->rtnpct = -1; ups->dlowbatt = -1; ups->NomOutputVoltage = -1; strlcpy(ups->beepstate, "-1", sizeof(ups->beepstate)); /* no value */ ups->nisip[0] = 0; /* no nis IP file as default */ ups->lockfile = -1; ups->clear_shut_load(); ups->clear_shut_btime(); ups->clear_shut_ltime(); ups->clear_shut_emerg(); ups->clear_shut_remote(); ups->sysfac = LOG_DAEMON; ups->statfile[0] = 0; /* no stats file default */ ups->eventfile[0] = 0; /* no events file as default */ ups->eventfilemax = 10; /* trim the events file at 10K as default */ ups->event_fd = -1; /* no file open */ /* Default paths */ strlcpy(ups->scriptdir, SYSCONFDIR, sizeof(ups->scriptdir)); strlcpy(ups->pwrfailpath, PWRFAILDIR, sizeof(ups->pwrfailpath)); strlcpy(ups->nologinpath, NOLOGDIR, sizeof(ups->nologinpath)); /* Initialize UPS function codes */ ups->UPS_Cmd[CI_STATUS] = APC_CMD_STATUS; ups->UPS_Cmd[CI_LQUAL] = APC_CMD_LQUAL; ups->UPS_Cmd[CI_WHY_BATT] = APC_CMD_WHY_BATT; ups->UPS_Cmd[CI_ST_STAT] = APC_CMD_ST_STAT; ups->UPS_Cmd[CI_VLINE] = APC_CMD_VLINE; ups->UPS_Cmd[CI_VMAX] = APC_CMD_VMAX; ups->UPS_Cmd[CI_VMIN] = APC_CMD_VMIN; ups->UPS_Cmd[CI_VOUT] = APC_CMD_VOUT; ups->UPS_Cmd[CI_BATTLEV] = APC_CMD_BATTLEV; ups->UPS_Cmd[CI_VBATT] = APC_CMD_VBATT; ups->UPS_Cmd[CI_LOAD] = APC_CMD_LOAD; ups->UPS_Cmd[CI_FREQ] = APC_CMD_FREQ; ups->UPS_Cmd[CI_RUNTIM] = APC_CMD_RUNTIM; ups->UPS_Cmd[CI_ITEMP] = APC_CMD_ITEMP; ups->UPS_Cmd[CI_DIPSW] = APC_CMD_DIPSW; ups->UPS_Cmd[CI_SENS] = APC_CMD_SENS; ups->UPS_Cmd[CI_DWAKE] = APC_CMD_DWAKE; ups->UPS_Cmd[CI_DSHUTD] = APC_CMD_DSHUTD; ups->UPS_Cmd[CI_LTRANS] = APC_CMD_LTRANS; ups->UPS_Cmd[CI_HTRANS] = APC_CMD_HTRANS; ups->UPS_Cmd[CI_RETPCT] = APC_CMD_RETPCT; ups->UPS_Cmd[CI_DALARM] = APC_CMD_DALARM; ups->UPS_Cmd[CI_DLBATT] = APC_CMD_DLBATT; ups->UPS_Cmd[CI_IDEN] = APC_CMD_IDEN; ups->UPS_Cmd[CI_STESTI] = APC_CMD_STESTI; ups->UPS_Cmd[CI_MANDAT] = APC_CMD_MANDAT; ups->UPS_Cmd[CI_SERNO] = APC_CMD_SERNO; ups->UPS_Cmd[CI_BATTDAT] = APC_CMD_BATTDAT; ups->UPS_Cmd[CI_NOMBATTV] = APC_CMD_NOMBATTV; ups->UPS_Cmd[CI_HUMID] = APC_CMD_HUMID; ups->UPS_Cmd[CI_REVNO] = APC_CMD_REVNO; ups->UPS_Cmd[CI_REG1] = APC_CMD_REG1; ups->UPS_Cmd[CI_REG2] = APC_CMD_REG2; ups->UPS_Cmd[CI_REG3] = APC_CMD_REG3; ups->UPS_Cmd[CI_EXTBATTS] = APC_CMD_EXTBATTS; ups->UPS_Cmd[CI_ATEMP] = APC_CMD_ATEMP; ups->UPS_Cmd[CI_UPSMODEL] = APC_CMD_UPSMODEL; ups->UPS_Cmd[CI_NOMOUTV] = APC_CMD_NOMOUTV; ups->UPS_Cmd[CI_BADBATTS] = APC_CMD_BADBATTS; ups->UPS_Cmd[CI_EPROM] = APC_CMD_EPROM; ups->UPS_Cmd[CI_ST_TIME] = APC_CMD_ST_TIME; ups->UPS_Cmd[CI_CYCLE_EPROM] = APC_CMD_CYCLE_EPROM; ups->UPS_Cmd[CI_UPS_CAPS] = APC_CMD_UPS_CAPS; } void check_for_config(UPSINFO *ups, char *cfgfile) { FILE *apcconf; char line[MAXSTRING]; int errors = 0; int erpos = 0; int fd; if ((fd = open(cfgfile, O_RDONLY|O_CLOEXEC)) == -1 || (apcconf = fdopen(fd, "r")) == NULL) { Error_abort("Error opening configuration file (%s): %s\n", cfgfile, strerror(errno)); } strlcpy(ups->configfile, cfgfile, sizeof(ups->configfile)); /* Check configuration file format is a suitable version */ if (fgets(line, sizeof(line), apcconf) != NULL) { /* * The -1 in sizeof is there because of the last character * to be checked. In line is '\n' and in APC... is '\0'. * They never match so don't even compare them. */ if (strncmp(line, APC_CONFIG_MAGIC, sizeof(APC_CONFIG_MAGIC) - 1) != 0) { fprintf(stderr, "%s: Warning: old configuration file found.\n\n" "%s: Expected: \"%s\"\n" "%s: Found: \"%s\"\n\n" "%s: Please check new file format and\n" "%s: modify accordingly the first line\n" "%s: of config file.\n\n" "%s: Processing config file anyway.\n", argvalue, argvalue, APC_CONFIG_MAGIC, argvalue, line, argvalue, argvalue, argvalue, argvalue); } /* * Here we have read alredy the first line of configuration * so there may be the case where the first line is a config * parameter and we must not discard it reading another line. * Jump into the reading configuration loop. */ goto jump_into_the_loop; } while (fgets(line, sizeof(line), apcconf) != NULL) { jump_into_the_loop: erpos++; if (ParseConfig(ups, line)) { errors++; Dmsg(100, "%s\n", line); Dmsg(100, "Parsing error at line %d of config file %s.\n", erpos, cfgfile); } } fclose(apcconf); /* * The next step will need a good ups struct. * Of course if here we have errors, the apc struct is not good * so don't bother to post-process it. */ if (errors) { /* * Lock path isn't valid until postprocessing below runs. Since we're * aborting early we need to ensure that no lock file cleanup is * attempted */ ups->lockpath[0] = '\0'; Error_abort("Terminating due to configuration file errors.\n"); } /* post-process the configuration stored in the ups structure */ /* * If annoy time is greater than initial delay, don't bother about * initial delay and set it to 0. */ if (ups->annoy >= ups->annoydelay) ups->annoydelay = 0; if (ups->sharenet.type == SHAREMASTER) { ups->maxtime = 0; ups->percent = 10; ups->runtime = 5; } // Sanitize cable type & UPS mode. Since UPSTYPE (aka mode) and UPSCABLE // can contradict eachother, the rule is that UPSTYPE wins. In all cases // except Dumb and MODBUS we can determine cable type from mode so we ignore // user's configured UPSCABLE and force it ourselves. In the case of Dumb // UPSes we just ensure they picked a simple cable type and for MODBUS we // ensure they picked a smart (or USB) cable type. switch (ups->mode.type) { case USB_UPS: match_range(ups, WHERE(cable), cables, "usb"); break; case SNMPLITE_UPS: case PCNET_UPS: case NETWORK_UPS: match_range(ups, WHERE(cable), cables, "ether"); break; case MODBUS_UPS: // Abort if user specified MODBUS UPS type with dumb cable if (ups->cable.type < CABLE_SMART) Error_abort("Invalid cable specified for MODBUS UPS\n"); break; case APCSMART_UPS: match_range(ups, WHERE(cable), cables, "smart"); break; case DUMB_UPS: // Abort if user specified dumb UPS type with smart cable if (ups->cable.type >= CABLE_SMART) Error_abort("Invalid cable specified for Dumb UPS\n"); break; case TEST_UPS: // Allow anything in test mode break; } /* * apcupsd _must_ have a lock file, mainly for security reasons. * If apcupsd is running and a lock is not there the admin could * mistakenly open a serial device with minicom for using it as a * modem or other device. Think about the implications of sending * extraneous characters to the UPS: a wrong char and the machine * can be powered down. * * No thanks. * * On the other hand if a lock file is there, minicom (like any * other serious serial program) will refuse to open the device. * * About "/var/lock//LCK..." nicety ... the right word IMHO is * simplify, so don't bother. */ if (ups->lockpath[0] == '\0') strlcpy(ups->lockpath, LOCK_DEFAULT, sizeof(ups->lockpath)); /* If APC_NET, the lockfile is not needed. */ if (ups->cable.type != APC_NET) { char *dev = strrchr(ups->device, '/'); strlcat(ups->lockpath, APC_LOCK_PREFIX, sizeof(ups->lockpath)); strlcat(ups->lockpath, dev ? ++dev : ups->device, sizeof(ups->lockpath)); } else { ups->lockpath[0] = 0; ups->lockfile = -1; } /* Append filenames to paths */ Dmsg(200, "After config scriptdir: \"%s\"\n", ups->scriptdir); Dmsg(200, "After config pwrfailpath: \"%s\"\n", ups->pwrfailpath); Dmsg(200, "After config nologinpath: \"%s\"\n", ups->nologinpath); strlcat(ups->nologinpath, NOLOGIN_FILE, sizeof(ups->nologinpath)); strlcat(ups->pwrfailpath, PWRFAIL_FILE, sizeof(ups->pwrfailpath)); switch (ups->nologin.type) { case TIMEOUT: if (ups->maxtime != 0) ups->nologin_time = (int)(ups->maxtime * 0.9); break; case PERCENT: ups->nologin_time = (int)(ups->percent * 1.1); if (ups->nologin_time == ups->percent) ups->nologin_time++; break; case MINUTES: ups->nologin_time = (int)(ups->runtime * 1.1); if (ups->nologin_time == ups->runtime) ups->nologin_time++; break; default: break; } return; } apcupsd-3.14.14/src/lib/apcerror.c000066400000000000000000000034711274230402600166460ustar00rootroot00000000000000/* * apcerror.c * * Error functions. */ /* * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 1999-2000 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" /* * Wraps call thru error_out function pointer so we can model it as no-return * in Coverity to clean up false positives. */ void error_out_wrapper(const char *file, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); error_out(file, line, fmt, args); // Never get here... va_end(args); while(1) ; } /* * Subroutine normally called by macro error_abort() to print * FATAL ERROR message and supplied error message */ void generic_error_out(const char *file, int line, const char *fmt, va_list arg_ptr) { char buf[256]; int i; asnprintf(buf, sizeof(buf), "FATAL ERROR in %s at line %d\n", file, line); i = strlen(buf); avsnprintf((char *)&buf[i], sizeof(buf) - i, (char *)fmt, arg_ptr); fprintf(stdout, "%s", buf); if (error_cleanup) error_cleanup(); exit(1); } void (*error_out) (const char *file, int line, const char *fmt, va_list arg_ptr) = generic_error_out; void (*error_cleanup) (void) = NULL; apcupsd-3.14.14/src/lib/apcevents.c000066400000000000000000000075431274230402600170250ustar00rootroot00000000000000/* * apcevents.c * * Output EVENTS information. */ /* * Copyright (C) 1999-2006 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #define NLE 50 /* number of events to send and keep */ /* * If the ups->eventfile exceeds ups->eventfilemax kilobytes, trim it to * slightly less than that maximum, preserving lines at end of the file. * * Returns: * * -1 if any error occurred * 0 if file did not need to be trimmed * 1 if file was trimmed */ int trim_eventfile(UPSINFO *ups) { int nbytes, maxb, i, rwerror = 0, status = -1; struct stat statbuf; unsigned char *buf; if (ups->eventfilemax == 0 || ups->event_fd < 0 || ups->eventfile[0] == 0) return 0; maxb = ups->eventfilemax * 1024; if (stat(ups->eventfile, &statbuf) < 0) return -1; if (statbuf.st_size <= maxb) return 0; /* file is not yet too large - nothing to do */ maxb = (maxb * 80) / 100; /* file is too large - reduce to 80% of max */ buf = (unsigned char *)malloc(maxb); if (!buf) return -1; write_lock(ups); /* Read the desired number of bytes from end of file */ if (lseek(ups->event_fd, -maxb, SEEK_END) < 0) { log_event(ups, LOG_CRIT, "lseek failed in trim_eventfile."); goto trim_done; } nbytes = 0; while (nbytes < maxb) { int r = read(ups->event_fd, buf + nbytes, maxb - nbytes); if (r < 0) rwerror++; if (r <= 0) break; nbytes += r; } /* Skip to the first new line */ for (i = 0; i < nbytes; i++) { if (buf[i] == '\n') { i++; break; } } nbytes -= i; /* Truncate the file and write the buffer */ lseek(ups->event_fd, 0, SEEK_SET); ftruncate(ups->event_fd, 0); while (nbytes) { int r = write(ups->event_fd, buf + i, nbytes); if (r <= 0) { rwerror++; break; } i += r; nbytes -= r; } status = 1; trim_done: write_unlock(ups); free(buf); if (rwerror) log_event(ups, LOG_CRIT, "read/write failed in trim_eventfile."); return status; } #ifdef HAVE_NISSERVER /* * Send the last events. * Returns: * -1 error or EOF * 0 OK */ int output_events(int sockfd, FILE *events_file) { char *le[NLE]; int i, j; int nrec = 0; int stat = 0; for (i = 0; i < NLE; i++) le[i] = NULL; for (i = 0; i < NLE; i++) if ((le[i] = (char *)malloc(MAXSTRING)) == NULL) goto bailout; i = 0; while (fgets(le[i], MAXSTRING, events_file) != NULL) { nrec++; i++; if (i >= NLE) /* wrap */ i = 0; } if (nrec > NLE) { nrec = NLE; /* number of records to output */ i -= (i / NLE) * NLE; /* first record to output */ } else { i = 0; } for (j = 0; j < nrec; j++) { if (net_send(sockfd, le[i], strlen(le[i])) <= 0) goto bailout; if (++i >= NLE) i = 0; } goto goodout; bailout: stat = -1; goodout: if (net_send(sockfd, NULL, 0) < 0) /* send eof */ stat = -1; for (i = 0; i < NLE; i++) if (le[i] != NULL) free(le[i]); return stat; } #endif /* HAVE_NISSERVER */ apcupsd-3.14.14/src/lib/apcexec.c000066400000000000000000000164511274230402600164430ustar00rootroot00000000000000/* * apcexec.c * * Fork/exec functions. */ /* * Copyright (C) 2000-2004 Kern Sibbald * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 1999-2000 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" static pthread_t thread_id[MAX_THREADS]; static const char *thread_name[MAX_THREADS]; static int num_threads = 0; /* Start a "real" POSIX thread */ int start_thread(UPSINFO *ups, void (*action) (UPSINFO * ups), const char *proctitle, char *argv0) { pthread_t tid; int status, t_index; set_thread_concurrency(); status = pthread_create(&tid, NULL, (void *(*)(void *))action, (void *)ups); if (status != 0) { log_event(ups, LOG_WARNING, "Unable to start thread: ERR=%s\n", strerror(status)); return 0; } t_index = num_threads; if (num_threads < MAX_THREADS) { thread_id[num_threads] = tid; thread_name[num_threads] = proctitle; num_threads++; } else { log_event(ups, LOG_ERR, "Something is wrong, we have %d threads, max is %d\n", num_threads + 1, MAX_THREADS); } return t_index; } /* Cancel all running threads except ourselves */ void clean_threads(void) { int i; pthread_t my_tid; my_tid = pthread_self(); for (i = 0; i < num_threads; i++) { if (!pthread_equal(my_tid, thread_id[i])) { pthread_cancel(thread_id[i]); pthread_detach(thread_id[i]); } } } #ifdef HAVE_MINGW #include "winapi.h" char sbindir[MAXSTRING]; int execute_command(UPSINFO *ups, UPSCOMMANDS cmd) { char cmdline[MAXSTRING]; char *comspec; PROCESS_INFORMATION procinfo; STARTUPINFOA startinfo; BOOL rc; if (cmd.pid && (kill(cmd.pid, 0) == 0)) { /* * Command is already running. No point in running it two * times. */ return SUCCESS; } /* Find command interpreter */ comspec = getenv("COMSPEC"); if (comspec == NULL) return FAILURE; /* Build the command line */ if (g_os_version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { /* Win95/98/ME need environment size parameter and no extra quotes */ asnprintf(cmdline, sizeof(cmdline), "\"%s\" /E:4096 /c \"%s%s\" %s \"%s\" %d %d \"%s\"", comspec, ups->scriptdir, APCCONTROL_FILE, cmd.command, ups->upsname, !ups->is_slave(), ups->is_plugged(), sbindir); } else { /* WinNT/2K/Vista need quotes around the entire sub-command */ asnprintf(cmdline, sizeof(cmdline), "\"%s\" /c \"\"%s%s\" %s \"%s\" %d %d \"%s\"\"", comspec, ups->scriptdir, APCCONTROL_FILE, cmd.command, ups->upsname, !ups->is_slave(), ups->is_plugged(), sbindir); } /* Initialize the STARTUPINFOA struct to hide the console window */ memset(&startinfo, 0, sizeof(startinfo)); startinfo.cb = sizeof(startinfo); startinfo.dwFlags = STARTF_USESHOWWINDOW; startinfo.wShowWindow = SW_HIDE; Dmsg(200, "execute_command: CreateProcessA(NULL, %s, ...)\n", cmdline); /* Execute the process */ rc = CreateProcessA(NULL, cmdline, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited 0, // creation flags NULL, // use parent's environment ups->scriptdir, // working directory &startinfo, // STARTUPINFO pointer &procinfo); // receives PROCESS_INFORMATION if (!rc) { log_event(ups, LOG_WARNING, "execute failed: CreateProcessA(NULL, %s, ...)=%d\n", cmdline, GetLastError()); return FAILURE; } /* Extract pid */ cmd.pid = procinfo.dwProcessId; /* Don't need handles */ CloseHandle(procinfo.hProcess); CloseHandle(procinfo.hThread); return SUCCESS; } #else int execute_command(UPSINFO *ups, UPSCOMMANDS cmd) { const char *argv[6]; char connected[20], powered[20]; char apccontrol[MAXSTRING]; if (cmd.pid && (kill(cmd.pid, 0) == 0)) { /* * Command is already running. No point in running it two * times. */ return SUCCESS; } asnprintf(connected, sizeof(connected), "%d", !ups->is_slave()); asnprintf(powered, sizeof(powered), "%d", (int)ups->is_plugged()); asnprintf(apccontrol, sizeof(apccontrol), "%s%s", ups->scriptdir, APCCONTROL_FILE); #ifdef HAVE_QNX_OS /* fork() is supported only in single-threaded applications */ argv[0] = apccontrol; /* Shell script to execute. */ argv[1] = cmd.command; /* Parameter to script. */ argv[2] = ups->upsname; /* UPS name */ argv[3] = connected; argv[4] = powered; argv[5] = NULL; if (spawnv(P_NOWAIT, apccontrol, (char * const *)argv) == -1) { log_event(ups, LOG_WARNING, "execute: cannot spawn(). ERR=%s", strerror(errno)); return FAILURE; } #else /* fork() and exec() */ switch (cmd.pid = fork()) { case -1: /* error */ log_event(ups, LOG_WARNING, "execute: cannot fork(). ERR=%s", strerror(errno)); return FAILURE; case 0: /* child */ /* Don't leak unnecessary fds to child */ for (int i=0; iupsname; /* UPS name */ argv[3] = connected; argv[4] = powered; argv[5] = NULL; execv(apccontrol, (char **)argv); /* NOT REACHED */ log_event(ups, LOG_WARNING, "Cannot exec %s %s: %s", apccontrol, cmd.command, strerror(errno)); /* Child must exit if fails exec'ing. */ exit(-1); break; default: /* parent */ /* * NOTE, we do a nonblocking waitpid) here to * pick up any previous children. We also] * increment a counter, and then in do_action() * in apcaction.c, we wait again each pass until * all the children are reaped. This is for * BSD systems where SIG_IGN does not prevent * zombies. */ if (ups->num_execed_children < 0) ups->num_execed_children = 1; else ups->num_execed_children++; while (ups->num_execed_children > 0 && waitpid(-1, NULL, WNOHANG) > 0) ups->num_execed_children--; break; } #endif /* HAVE_QNX_OS */ return SUCCESS; } #endif /* HAVE_MINGW */ apcupsd-3.14.14/src/lib/apcfile.c000066400000000000000000000034561274230402600164370ustar00rootroot00000000000000/* * apcfile.c * * Files management. */ /* * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 1999-2000 Riccardo Facchetti * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" /* * If this is a Windows machine, we do NOT create a pid file. * We prevent multiple copies of apcupsd from running by * ensuring that there is only one system tray entry for * apcupsd. */ /* * Create a file in `path'. Used for nologin and powerfail * files. */ int make_file(UPSINFO *ups, const char *path) { int makefd; if ((makefd = open(path, O_CREAT | O_WRONLY | O_CLOEXEC, 0644)) >= 0) { close(makefd); } else { log_event(ups, LOG_ERR, "Unable to create %s: ERR=%s\n", path, strerror(errno)); } return makefd; } /* Create the pid lock file. */ const char *pidfile = APCPID; void make_pid_file(void) { #if !defined(HAVE_MINGW) pid_t pid = getpid(); int pfd, len; char buf[100]; unlink(pidfile); if ((pfd = open(pidfile, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)) >= 0) { len = asnprintf(buf, sizeof(buf), "%ld\n", (long)pid); write(pfd, buf, len); close(pfd); } #endif } apcupsd-3.14.14/src/lib/apclibnis.c000066400000000000000000000235731274230402600170020ustar00rootroot00000000000000/* * apclibnis.c * * Network utility routines. */ /* * Copyright (C) 1999-2006 Kern Sibbald * Copyright (C) 2007-2015 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #ifdef HAVE_NISLIB /* Some Win32 specific screwery */ #ifdef HAVE_MINGW #define close(fd) closesocket(fd) #define getsockopt(s,l,o,d,z) getsockopt((s),(l),(o),(char*)(d),(z)) #define EINPROGRESS WSAEWOULDBLOCK int WSA_Init(void); int dummy = WSA_Init(); #undef errno #define errno WSAGetLastError() #undef h_errno #define h_errno WSAGetLastError() #endif // HAVE_MINGW /* * Read nbytes from the network. * It is possible that the total bytes require in several * read requests */ static int read_nbytes(sock_t fd, char *ptr, int nbytes) { int nleft, nread = 0; struct timeval timeout; int rc; fd_set fds; nleft = nbytes; while (nleft > 0) { do { /* Expect data from the server within 15 seconds */ timeout.tv_sec = 15; timeout.tv_usec = 0; FD_ZERO(&fds); FD_SET(fd, &fds); rc = select(fd + 1, &fds, NULL, NULL, &timeout); switch (rc) { case -1: if (errno == EINTR || errno == EAGAIN) continue; return -errno; /* error */ case 0: return -ETIMEDOUT; /* timeout */ } nread = recv(fd, ptr, nleft, 0); } while (nread == -1 && (errno == EINTR || errno == EAGAIN)); if (nread == 0) return 0; /* EOF */ if (nread < 0) return -errno; /* error */ nleft -= nread; ptr += nread; } return nbytes - nleft; /* return >= 0 */ } /* * Write nbytes to the network. * It may require several writes. */ static int write_nbytes(sock_t fd, const char *ptr, int nbytes) { int nleft, nwritten; nleft = nbytes; while (nleft > 0) { nwritten = send(fd, ptr, nleft, 0); switch (nwritten) { case -1: if (errno == EINTR || errno == EAGAIN) continue; return -errno; /* error */ case 0: return nbytes - nleft; /* EOF */ } nleft -= nwritten; ptr += nwritten; } return nbytes - nleft; } /* * Receive a message from the other end. Each message consists of * two packets. The first is a header that contains the size * of the data that follows in the second packet. * Returns number of bytes read * Returns 0 on end of file * Returns -1 on hard end of file (i.e. network connection close) * Returns -2 on error */ int net_recv(sock_t sockfd, char *buff, int maxlen) { int nbytes; unsigned short pktsiz; /* get data size -- in short */ if ((nbytes = read_nbytes(sockfd, (char *)&pktsiz, sizeof(pktsiz))) <= 0) { /* probably pipe broken because client died */ return nbytes; /* assume hard EOF received */ } if (nbytes != sizeof(pktsiz)) return -EINVAL; pktsiz = ntohs(pktsiz); /* decode no. of bytes that follow */ if (pktsiz > maxlen) return -EINVAL; if (pktsiz == 0) return 0; /* soft EOF */ /* now read the actual data */ if ((nbytes = read_nbytes(sockfd, buff, pktsiz)) <= 0) return nbytes; if (nbytes != pktsiz) return -EINVAL; return nbytes; /* return actual length of message */ } /* * Send a message over the network. The send consists of * two network packets. The first is sends a short containing * the length of the data packet which follows. * Returns number of bytes sent, 0 for EOF * Returns -errno on error */ int net_send(sock_t sockfd, const char *buff, int len) { int rc; short pktsiz; /* send short containing size of data packet */ pktsiz = htons((short)len); rc = write_nbytes(sockfd, (char *)&pktsiz, sizeof(short)); if (rc <= 0) return rc; if (rc != sizeof(short)) return -EINVAL; /* send data packet */ rc = write_nbytes(sockfd, buff, len); if (rc <= 0) return rc; if (rc != len) return -EINVAL; return rc; } /* * Open a TCP connection to the UPS network server * Returns -errno on error * Returns socket file descriptor otherwise */ sock_t net_open(const char *host, char *service, int port) { int nonblock = 1; int block = 0; sock_t sockfd; int rc; struct sockaddr_in tcp_serv_addr; /* socket information */ #ifndef HAVE_MINGW // Every platform has their own magic way to avoid getting a SIGPIPE // when writing to a stream socket where the remote end has closed. // This method works pretty much everywhere which avoids the mess // of figuring out which incantation this platform supports. (Excepting // for win32 which doesn't support signals at all.) struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, NULL); #endif /* * Fill in the structure serv_addr with the address of * the server that we want to connect with. */ memset((char *)&tcp_serv_addr, 0, sizeof(tcp_serv_addr)); tcp_serv_addr.sin_family = AF_INET; tcp_serv_addr.sin_port = htons(port); tcp_serv_addr.sin_addr.s_addr = inet_addr(host); if (tcp_serv_addr.sin_addr.s_addr == INADDR_NONE) { struct hostent he; char *tmphstbuf = NULL; size_t hstbuflen = 0; struct hostent *hp = gethostname_re(host, &he, &tmphstbuf, &hstbuflen); if (!hp) { free(tmphstbuf); Dmsg(100, "%s: gethostname fails: %d\n", __func__, h_errno); return -ENXIO; } if (hp->h_length != sizeof(tcp_serv_addr.sin_addr.s_addr) || hp->h_addrtype != AF_INET) { free(tmphstbuf); Dmsg(100, "%s: Bad address returned from gethostbyname\n", __func__); return -EAFNOSUPPORT; } memcpy(&tcp_serv_addr.sin_addr.s_addr, hp->h_addr, sizeof(tcp_serv_addr.sin_addr.s_addr)); free(tmphstbuf); } /* Open a TCP socket */ if ((sockfd = socket_cloexec(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { rc = -errno; Dmsg(100, "%s: socket fails: %s\n", __func__, strerror(-rc)); return rc; } /* connect to server */ /* Set socket to non-blocking mode */ if (ioctl(sockfd, FIONBIO, &nonblock) != 0) { rc = -errno; close(sockfd); Dmsg(100, "%s: ioctl(FIONBIO,nonblock) fails: %s\n", __func__, strerror(-rc)); return rc; } /* Initiate connection attempt */ rc = connect(sockfd, (struct sockaddr *)&tcp_serv_addr, sizeof(tcp_serv_addr)); if (rc == -1 && errno != EINPROGRESS) { rc = -errno; close(sockfd); Dmsg(100, "%s: connect fails: %s\n", __func__, strerror(-rc)); return rc; } /* If connection is in progress, wait for it to complete */ if (rc == -1) { struct timeval timeout; fd_set fds; int err; socklen_t errlen = sizeof(err); do { /* Expect connection within 5 seconds */ timeout.tv_sec = 5; timeout.tv_usec = 0; FD_ZERO(&fds); FD_SET(sockfd, &fds); /* Wait for connection to complete */ rc = select(sockfd + 1, NULL, &fds, NULL, &timeout); switch (rc) { case -1: /* select error */ if (errno == EINTR || errno == EAGAIN) continue; err = -errno; close(sockfd); Dmsg(100, "%s: select fails: %s\n", __func__, strerror(-err)); return err; case 0: /* timeout */ close(sockfd); Dmsg(100, "%s: select timeout\n", __func__); return -ETIMEDOUT; } } while (rc == -1 && (errno == EINTR || errno == EAGAIN)); /* Connection completed? Check error status. */ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { rc = -errno; close(sockfd); Dmsg(100, "%s: getsockopt fails: %s\n", __func__, strerror(-rc)); return rc; } if (errlen != sizeof(err)) { close(sockfd); Dmsg(100, "%s: getsockopt bad length\n", __func__); return -EINVAL; } if (err) { close(sockfd); Dmsg(100, "%s: connection completion fails: %s\n", __func__, strerror(err)); return -err; } } /* Connection completed successfully. Set socket back to blocking mode. */ if (ioctl(sockfd, FIONBIO, &block) != 0) { rc = -errno; close(sockfd); Dmsg(100, "%s: ioctl(FIONBIO,block) fails: %s\n", __func__, strerror(-rc)); return rc; } return sockfd; } /* Close the network connection */ void net_close(sock_t sockfd) { close(sockfd); } /* * Accept a TCP connection. * Returns -1 on error. * Returns file descriptor of new connection otherwise. */ sock_t net_accept(sock_t fd, struct sockaddr_in *cli_addr) { #ifdef HAVE_MINGW /* kludge because some idiot defines socklen_t as unsigned */ int clilen = sizeof(*cli_addr); #else socklen_t clilen = sizeof(*cli_addr); #endif sock_t newfd; do { newfd = accept_cloexec(fd, (struct sockaddr *)cli_addr, &clilen); } while (newfd == INVALID_SOCKET && (errno == EINTR || errno == EAGAIN)); if (newfd < 0) return -errno; /* error */ return newfd; } #endif /* HAVE_NISLIB */ apcupsd-3.14.14/src/lib/apclock.c000066400000000000000000000151321274230402600164420ustar00rootroot00000000000000/* * apclock.c * * Lock file managing functions. */ /* * Copyright (C) 2000-2006 Kern Sibbald * Copyright (C) 1998-99 Brian Schau * Copyright (C) 1998-99-2000 Riccardo Facchetti * Copyright (C) 1996-99 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" /* * For Windows, we do NOT create a lock file. Even if we did * no other program would respect it since this is not a * Unix system. */ /* Check to see if a serial port lockfile exists. * If so, and the process is no longer running, * blow away the lockfile. */ #if !defined(HAVE_MINGW) static int check_stale_lockfile(UPSINFO *ups) { char pidbuffer[12]; int size; int stalepid; int error; /* * If the daemon is talking with APC_NET, the lock file is not * needed. */ if (ups->cable.type == APC_NET) return LCKNOLOCK; if (ups->lockpath[0] == '\0') { /* * If there's no lockfile configured, return error. * This is a _must_. See my comment in apcconfig.c */ log_event(ups, LOG_ERR, "No lock path configured.\n"); return LCKERROR; } errno = 0; if ((ups->lockfile = open(ups->lockpath, O_RDONLY|O_CLOEXEC)) < 0) { /* * Cannot open the file (may be it doesn't exist and that's okay * for us so return success). */ if (errno == ENOENT) return LCKSUCCESS; /* On any other error, return error. */ log_event(ups, LOG_ERR, "Lock file open error. ERR=%s\n", strerror(errno)); return LCKERROR; } if ((size = read(ups->lockfile, &pidbuffer, 11)) == -1) { /* * If we can not read from file, close it and return error: * the file exist but we can not check for stale. */ error = LCKERROR; log_event(ups, LOG_ERR, "Lock file read error. ERR=%s\n", strerror(errno)); goto out; } if (size == 0 || (sscanf(pidbuffer, "%d", &stalepid) != 1)) { /* * If there's no data in the file or the data written is wrong * we have a process that: * 1 - running but failed to write the lock file * 2 - not running and failed to write the lock file * * Anyway we assume the worst case (1) and return error. */ error = LCKERROR; log_event(ups, LOG_ERR, "Lock file data error: %s\n", pidbuffer); goto out; } /* Check if it is our current pid or the pid of our parent */ if (stalepid == getpid() || stalepid == getppid()) { /* * We are us (may be a crash of the machine ... same pid * because same boot sequence ... leave it alone and go run) */ error = LCKEXIST; goto out; } /* * Okay, now we have a stalepid to check. * kill(pid,0) checks to see if the process is still running. */ if (kill(stalepid, 0) == -1 && errno == ESRCH) { /* * Okay this is a stale lock: * we can unlink even before closing it. */ if (unlink(ups->lockpath) < 0) { log_event(ups, LOG_ERR, "Unable to unlink old lock file %s because %s\n", ups->lockpath, strerror(errno)); error = LCKERROR; } else { error = LCKSUCCESS; } goto out; } /* * We have unfortunately found a perfectly valid lock file. * Don't touch it. */ log_event(ups, LOG_ERR, "Valid lock file for pid=%d, but not ours pid=%d\n", stalepid, getpid()); error = LCKERROR; out: close(ups->lockfile); ups->lockfile = -1; return error; } #endif /* * Create serial port lock file */ int hibernate_ups = FALSE; int shutdown_ups = FALSE; int create_lockfile(UPSINFO *ups) { #if !defined(HAVE_MINGW) char pidbuffer[12]; int error; /* * If this is a hibernate or shutdown execution, we are * probably running with the filesystems read-only, so * don't try to create the lock file. */ if (hibernate_ups || shutdown_ups) return LCKSUCCESS; switch (error = check_stale_lockfile(ups)) { case LCKNOLOCK: /* Lockfile not needed: return success. */ case LCKEXIST: /* Lockfile exists and contains our pid. */ return LCKSUCCESS; case LCKERROR: /* Lockfile exists and is not stale. */ return LCKERROR; case LCKSUCCESS: /* Lockfile does not exist _now_. */ break; } /* * Now the file does not exist any more. * Open it for creation and don't accept any kind of error. */ errno = 0; if ((ups->lockfile = open(ups->lockpath, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, 0644)) < 0) { /* * Okay there is some problem with the lock path or * something like that. */ log_event(ups, LOG_ERR, "Cannot create %s serial port lock file: ERR=%s\n", ups->lockpath, strerror(errno)); return LCKERROR; } if (asnprintf(pidbuffer, sizeof(pidbuffer), "%010ld", (long)getpid()) <= 0) { /* Problems with sprintf */ error = LCKERROR; log_event(ups, LOG_ERR, "Lock file sprintf error.\n"); goto out; } if (write(ups->lockfile, pidbuffer, strlen(pidbuffer) + 1) != (int)strlen(pidbuffer) + 1) { /* Problems with write. */ error = LCKERROR; log_event(ups, LOG_ERR, "Lock file %s write failure. ERR=%s\n", ups->lockpath, strerror(errno)); goto out; } /* Done it. */ error = LCKSUCCESS; out: close(ups->lockfile); ups->lockfile = -1; return error; #else return LCKSUCCESS; #endif } void delete_lockfile(UPSINFO *ups) { #if !defined(HAVE_MINGW) if (ups->lockpath[0] != '\0') { /* * If lockfile is ours, close it and delete it, * otherwise do nothing. */ if (check_stale_lockfile(ups) == LCKEXIST) { if (ups->lockfile != -1) { close(ups->lockfile); ups->lockfile = -1; } unlink(ups->lockpath); } /* * Now ups->lockfile is == -1 so there's no need to * blank ups->lockfile too. */ } #endif } apcupsd-3.14.14/src/lib/apclog.c000066400000000000000000000127411274230402600162760ustar00rootroot00000000000000/* * apclog.c * * Logging functions. */ /* * Copyright (C) 1996-99 Andre M. Hedrick * Copyright (C) 2000-2005 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" int format_date(time_t timestamp, char *dest, size_t destlen) { struct tm tm; localtime_r(×tamp, &tm); #ifdef HAVE_MINGW // Annoyingly, Windows does not properly implement %z (it always spells // out the timezone name) so we need to emulate it manually. int len = strftime(dest, destlen, "%Y-%m-%d %H:%M:%S ", &tm); tzset(); unsigned int offset = abs(_timezone) / 60; len += snprintf(dest+len, destlen-len, "%c%02u%02u ", _timezone < 0 ? '+' : '-', // _timezone is UTC-local offset/60, offset%60); return len; #else return strftime(dest, destlen, "%Y-%m-%d %H:%M:%S %z ", &tm); #endif } void log_event(const UPSINFO *ups, int level, const char *fmt, ...) { va_list arg_ptr; char msg[2 *MAXSTRING]; char datetime[100]; int event_fd; event_fd = ups ? ups->event_fd : -1; va_start(arg_ptr, fmt); avsnprintf(msg, sizeof(msg), fmt, arg_ptr); va_end(arg_ptr); syslog(level, "%s", msg); /* log the event */ Dmsg(100, "%s\n", msg); /* Write out to our temp file. LOG_INFO is DATA logging, so * do not write it to our temp events file. */ if (event_fd >= 0 && level != LOG_INFO) { format_date(time(NULL), datetime, sizeof(datetime)); write(event_fd, datetime, strlen(datetime)); int lm = strlen(msg); if (msg[lm - 1] != '\n') msg[lm++] = '\n'; write(event_fd, msg, lm); } } /* * Subroutine prints a debug message if the level number * is less than or equal the debug_level. File and line numbers * are included for more detail if desired, but not currently * printed. * * If the level is negative, the details of file and line number * are not printed. */ int debug_level = 0; FILE *trace_fd = NULL; bool trace = false; void logf(const char *fmt, ...) { va_list arg_ptr; va_start(arg_ptr, fmt); if (trace) { if (!trace_fd) { char fn[200]; asnprintf(fn, sizeof(fn), "./apcupsd.trace"); int fd = open(fn, O_RDWR|O_APPEND|O_CREAT|O_CLOEXEC, 0666); if (fd != -1) trace_fd = fdopen(fd, "a+"); } if (trace_fd) { vfprintf(trace_fd, fmt, arg_ptr); fflush(trace_fd); } else { /* Some problem, turn off tracing */ trace = false; } } else { /* not tracing */ vfprintf(stdout, fmt, arg_ptr); fflush(stdout); } va_end(arg_ptr); } #define FULL_LOCATION 1 void d_msg(const char *file, int line, int level, const char *fmt, ...) { #ifdef DEBUG char buf[4096]; int i, diff; va_list arg_ptr; bool details = true; struct timeval now; const char *my_name = "apcupsd"; static struct timeval start = {0,0}; if (start.tv_sec == 0 && start.tv_usec == 0) gettimeofday(&start, NULL); if (level < 0) { details = false; level = -level; } if (level <= debug_level) { #ifdef FULL_LOCATION if (details) { gettimeofday(&now, NULL); diff = TV_DIFF_MS(start, now); asnprintf(buf, sizeof(buf), "%lu.%03lu %s: %s:%d ", diff/1000, diff%1000, my_name, file, line); i = strlen(buf); } else { i = 0; } #else i = 0; #endif va_start(arg_ptr, fmt); avsnprintf(buf + i, sizeof(buf) - i, (char *)fmt, arg_ptr); va_end(arg_ptr); logf("%s", buf); } #endif } void h_dump(const char *file, int ln, int level, const void *data, unsigned int len) { unsigned int pos = 0; const unsigned char *dat = (const unsigned char *)data; char buf[4]; // Derivation of line buffer size: // 8 digit address // 2 spaces // 16 hex bytes (2 chars + 1 space each) // 1 additional space between hex and ascii // 16 ASCII chars // 1 NUL terminator char line[8+2+16*3+1+16+1]; if (debug_level < level) return; d_msg(file, ln, level, "Dumping %d bytes @ 0x%08x\n", len, data); while (pos < len) { int num = MIN(16, len-pos); // Begin line with offset snprintf(line, sizeof(line), "%08x ", pos); // Append hex digits for (int i=0; i < 16; i++) { if (i < num) { snprintf(buf, sizeof(buf), "%02x ", dat[pos+i]); strlcat(line, buf, sizeof(line)); } else { strlcat(line, " ", sizeof(line)); } } // Additional space between hex digits and ASCII strlcat(line, " ", sizeof(line)); // Append ASCII buf[1] = '\0'; for (int i=0; i < num; i++) { buf[0] = isgraph(dat[pos+i]) ? dat[pos+i] : '.'; strlcat(line, buf, sizeof(line)); } d_msg(file, ln, level, "%s\n", line); pos += num; } } apcupsd-3.14.14/src/lib/apcsignal.c000066400000000000000000000037301274230402600167700ustar00rootroot00000000000000/* * apcsignal.c * * signal() managing functions */ /* * Copyright (C) 1999-2000 Riccardo Facchetti * Copyright (C) 1996-99 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #ifndef HAVE_MINGW static void *terminate(void *arg) { // Create signal set containing SIGHUP, SIGINT, and SIGTERM sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGHUP); sigaddset(&sigset, SIGINT); sigaddset(&sigset, SIGTERM); // Wait for signal delivery int signum, err; do { err = sigwait(&sigset, &signum); } while(err == EINTR); // Caught a signal; invoke handler void (*handler) (int) = (void (*) (int))arg; handler(signum); return NULL; } #endif void init_signals(void (*handler) (int)) { #ifndef HAVE_MINGW // Block SIGPIPE and termination signals sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGPIPE); // Don't care sigaddset(&sigset, SIGHUP); // Will be handled by terminate thread sigaddset(&sigset, SIGINT); // Will be handled by terminate thread sigaddset(&sigset, SIGTERM); // Will be handled by terminate thread pthread_sigmask(SIG_BLOCK, &sigset, NULL); // Launch thread to synchronously wait for termination signals pthread_t tid; pthread_create(&tid, NULL, terminate, (void*)handler); #endif } apcupsd-3.14.14/src/lib/apcstatus.c000066400000000000000000000273771274230402600170530ustar00rootroot00000000000000/* * apcstatus.c * * Output STATUS information. */ /* * Copyright (C) 1999-2005 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" /* Send the full status of the UPS to the client. */ int output_status(UPSINFO *ups, int sockfd, void s_open(UPSINFO *ups), void s_write(UPSINFO *ups, const char *fmt, ...), int s_close(UPSINFO *ups, int sockfd)) { char datetime[100]; char buf[MAXSTRING]; time_t now = time(NULL); int time_on_batt; char status[100]; s_open(ups); /* * Lock the UPS structure for reading so the driver doesn't haul * off and start updating fields on us. Note that this creates * the potential for a misbehaving client to create long lock * hold times, essentially locking the driver out. This could * be mitigated by making a local copy of UPSINFO under the * lock, then releasing the lock and feeding the client from * the copy. */ read_lock(ups); if (ups->poll_time == 0) /* this is always zero on slave */ ups->poll_time = now; /* put the last UPS poll time on the DATE record */ format_date(ups->poll_time, datetime, sizeof(datetime)); s_write(ups, "DATE : %s\n", datetime); gethostname(buf, sizeof buf); s_write(ups, "HOSTNAME : %s\n", buf); s_write(ups, "VERSION : " APCUPSD_RELEASE " (" ADATE ") " APCUPSD_HOST "\n"); if (*ups->upsname) s_write(ups, "UPSNAME : %s\n", ups->upsname); s_write(ups, "CABLE : %s\n", ups->cable.long_name); s_write(ups, "DRIVER : %s\n", ups->mode.long_name); s_write(ups, "UPSMODE : %s\n", ups->upsclass.long_name); format_date(ups->start_time, datetime, sizeof(datetime)); s_write(ups, "STARTTIME: %s\n", datetime); if (ups->sharenet.type != DISABLE) s_write(ups, "SHARE : %s\n", ups->sharenet.long_name); /* If slave, send last update time/date from master */ if (ups->is_slave()) { /* we must be a slave */ if (ups->last_master_connect_time == 0) { s_write(ups, "MASTERUPD: No connection to Master\n"); } else { format_date(ups->last_master_connect_time, datetime, sizeof(datetime)); s_write(ups, "MASTERUPD: %s\n", datetime); } s_write(ups, "MASTER : %s\n", ups->master_name); } if (ups->UPS_Cap[CI_UPSMODEL]) s_write(ups, "MODEL : %s\n", ups->upsmodel); status[0] = 0; /* Now output human readable form */ if (ups->is_calibration()) strlcat(status, "CAL ", sizeof(status)); if (ups->is_trim()) strlcat(status, "TRIM ", sizeof(status)); if (ups->is_boost()) strlcat(status, "BOOST ", sizeof(status)); if (ups->is_online()) strlcat(status, "ONLINE ", sizeof(status)); if (ups->is_onbatt()) strlcat(status, "ONBATT ", sizeof(status)); if (ups->is_overload()) strlcat(status, "OVERLOAD ", sizeof(status)); if (ups->is_battlow()) strlcat(status, "LOWBATT ", sizeof(status)); if (ups->is_replacebatt()) strlcat(status, "REPLACEBATT ", sizeof(status)); if (!ups->is_battpresent()) strlcat(status, "NOBATT ", sizeof(status)); if (ups->is_slave()) strlcat(status, "SLAVE ", sizeof(status)); if (ups->is_slavedown()) strlcat(status, "SLAVEDOWN", sizeof(status)); /* These override the above */ if (ups->is_commlost()) strlcpy(status, "COMMLOST ", sizeof(status)); if (ups->is_shutdown()) strlcpy(status, "SHUTTING DOWN", sizeof(status)); s_write(ups, "STATUS : %s\n", status); if (ups->UPS_Cap[CI_VLINE]) s_write(ups, "LINEV : %.1f Volts\n", ups->LineVoltage); if (ups->UPS_Cap[CI_LOAD]) s_write(ups, "LOADPCT : %.1f Percent\n", ups->UPSLoad); if (ups->UPS_Cap[CI_LoadApparent]) s_write(ups, "LOADAPNT : %.1f Percent\n", ups->LoadApparent); if (ups->UPS_Cap[CI_BATTLEV]) s_write(ups, "BCHARGE : %.1f Percent\n", ups->BattChg); if (ups->UPS_Cap[CI_RUNTIM]) s_write(ups, "TIMELEFT : %.1f Minutes\n", ups->TimeLeft); s_write(ups, "MBATTCHG : %d Percent\n", ups->percent); s_write(ups, "MINTIMEL : %d Minutes\n", ups->runtime); s_write(ups, "MAXTIME : %d Seconds\n", ups->maxtime); if (ups->UPS_Cap[CI_VMAX]) s_write(ups, "MAXLINEV : %.1f Volts\n", ups->LineMax); if (ups->UPS_Cap[CI_VMIN]) s_write(ups, "MINLINEV : %.1f Volts\n", ups->LineMin); if (ups->UPS_Cap[CI_VOUT]) s_write(ups, "OUTPUTV : %.1f Volts\n", ups->OutputVoltage); if (ups->UPS_Cap[CI_SENS]) { switch ((*ups).sensitivity[0]) { case 'A': /* Matrix only */ s_write(ups, "SENSE : Auto Adjust\n"); break; case 'L': s_write(ups, "SENSE : Low\n"); break; case 'M': s_write(ups, "SENSE : Medium\n"); break; case 'H': s_write(ups, "SENSE : High\n"); break; default: s_write(ups, "SENSE : Unknown\n"); break; } } if (ups->UPS_Cap[CI_DWAKE]) s_write(ups, "DWAKE : %d Seconds\n", ups->dwake); if (ups->UPS_Cap[CI_DSHUTD]) s_write(ups, "DSHUTD : %d Seconds\n", ups->dshutd); if (ups->UPS_Cap[CI_DLBATT]) s_write(ups, "DLOWBATT : %d Minutes\n", ups->dlowbatt); if (ups->UPS_Cap[CI_LTRANS]) s_write(ups, "LOTRANS : %d.0 Volts\n", ups->lotrans); if (ups->UPS_Cap[CI_HTRANS]) s_write(ups, "HITRANS : %d.0 Volts\n", ups->hitrans); if (ups->UPS_Cap[CI_RETPCT]) s_write(ups, "RETPCT : %d.0 Percent\n", ups->rtnpct); if (ups->UPS_Cap[CI_ITEMP]) s_write(ups, "ITEMP : %.1f C\n", ups->UPSTemp); if (ups->UPS_Cap[CI_DALARM]) { switch ((*ups).beepstate[0]) { case 'T': s_write(ups, "ALARMDEL : 30 Seconds\n"); break; case 'L': s_write(ups, "ALARMDEL : Low Battery\n"); break; case 'N': s_write(ups, "ALARMDEL : No alarm\n"); break; case '0': s_write(ups, "ALARMDEL : 5 Seconds\n"); break; default: s_write(ups, "ALARMDEL : Always\n"); break; } } if (ups->UPS_Cap[CI_VBATT]) s_write(ups, "BATTV : %.1f Volts\n", ups->BattVoltage); if (ups->UPS_Cap[CI_FREQ]) s_write(ups, "LINEFREQ : %.1f Hz\n", ups->LineFreq); if (ups->UPS_Cap[CI_OutputCurrent]) s_write(ups, "OUTCURNT : %.2f Amps\n", ups->OutputCurrent); /* Output cause of last transfer to batteries */ switch (ups->lastxfer) { case XFER_NONE: s_write(ups, "LASTXFER : No transfers since turnon\n"); break; case XFER_SELFTEST: s_write(ups, "LASTXFER : Automatic or explicit self test\n"); break; case XFER_FORCED: s_write(ups, "LASTXFER : Forced by software\n"); break; case XFER_UNDERVOLT: s_write(ups, "LASTXFER : Low line voltage\n"); break; case XFER_OVERVOLT: s_write(ups, "LASTXFER : High line voltage\n"); break; case XFER_RIPPLE: s_write(ups, "LASTXFER : Unacceptable line voltage changes\n"); break; case XFER_NOTCHSPIKE: s_write(ups, "LASTXFER : Line voltage notch or spike\n"); break; case XFER_FREQ: s_write(ups, "LASTXFER : Input frequency out of range\n"); break; case XFER_UNKNOWN: s_write(ups, "LASTXFER : UNKNOWN EVENT\n"); break; case XFER_NA: default: /* UPS doesn't report this data */ break; } s_write(ups, "NUMXFERS : %d\n", ups->num_xfers); if (ups->num_xfers > 0) { format_date(ups->last_onbatt_time, datetime, sizeof(datetime)); s_write(ups, "XONBATT : %s\n", datetime); } if (ups->is_onbatt() && ups->last_onbatt_time > 0) time_on_batt = now - ups->last_onbatt_time; else time_on_batt = 0; s_write(ups, "TONBATT : %d Seconds\n", time_on_batt); s_write(ups, "CUMONBATT: %d Seconds\n", ups->cum_time_on_batt + time_on_batt); if (ups->last_offbatt_time > 0) { format_date(ups->last_offbatt_time, datetime, sizeof(datetime)); s_write(ups, "XOFFBATT : %s\n", datetime); } else { s_write(ups, "XOFFBATT : N/A\n"); } if (ups->LastSelfTest != 0) { format_date(ups->LastSelfTest, datetime, sizeof(datetime)); s_write(ups, "LASTSTEST: %s\n", datetime); } /* Status of last self test */ switch (ups->testresult) { case TEST_NONE: s_write(ups, "SELFTEST : NO\n"); break; case TEST_FAILED: s_write(ups, "SELFTEST : NG\n"); break; case TEST_WARNING: s_write(ups, "SELFTEST : WN\n"); break; case TEST_INPROGRESS: s_write(ups, "SELFTEST : IP\n"); break; case TEST_PASSED: s_write(ups, "SELFTEST : OK\n"); break; case TEST_FAILCAP: s_write(ups, "SELFTEST : BT\n"); break; case TEST_FAILLOAD: s_write(ups, "SELFTEST : NG\n"); break; case TEST_UNKNOWN: s_write(ups, "SELFTEST : ??\n"); break; case TEST_NA: default: /* UPS doesn't report this data */ break; } /* Self test interval */ if (ups->UPS_Cap[CI_STESTI]) s_write(ups, "STESTI : %s\n", ups->selftest); /* output raw bits */ s_write(ups, "STATFLAG : 0x%08X\n", ups->Status); if (ups->UPS_Cap[CI_DIPSW]) s_write(ups, "DIPSW : 0x%02X\n", ups->dipsw); if (ups->UPS_Cap[CI_REG1]) s_write(ups, "REG1 : 0x%02X\n", ups->reg1); if (ups->UPS_Cap[CI_REG2]) s_write(ups, "REG2 : 0x%02X\n", ups->reg2); if (ups->UPS_Cap[CI_REG3]) s_write(ups, "REG3 : 0x%02X\n", ups->reg3); if (ups->UPS_Cap[CI_MANDAT]) s_write(ups, "MANDATE : %s\n", ups->birth); if (ups->UPS_Cap[CI_SERNO]) s_write(ups, "SERIALNO : %s\n", ups->serial); if (ups->UPS_Cap[CI_BATTDAT] || ups->UPS_Cap[CI_BattReplaceDate]) s_write(ups, "BATTDATE : %s\n", ups->battdat); if (ups->UPS_Cap[CI_NOMOUTV]) s_write(ups, "NOMOUTV : %d Volts\n", ups->NomOutputVoltage); if (ups->UPS_Cap[CI_NOMINV]) s_write(ups, "NOMINV : %d Volts\n", ups->NomInputVoltage); if (ups->UPS_Cap[CI_NOMBATTV]) s_write(ups, "NOMBATTV : %.1f Volts\n", ups->nombattv); if (ups->UPS_Cap[CI_NOMPOWER]) s_write(ups, "NOMPOWER : %d Watts\n", ups->NomPower); if (ups->UPS_Cap[CI_NomApparent]) s_write(ups, "NOMAPNT : %d VA\n", ups->NomApparentPower); if (ups->UPS_Cap[CI_HUMID]) s_write(ups, "HUMIDITY : %.1f Percent\n", ups->humidity); if (ups->UPS_Cap[CI_ATEMP]) s_write(ups, "AMBTEMP : %.1f C\n", ups->ambtemp); if (ups->UPS_Cap[CI_EXTBATTS]) s_write(ups, "EXTBATTS : %d\n", ups->extbatts); if (ups->UPS_Cap[CI_BADBATTS]) s_write(ups, "BADBATTS : %d\n", ups->badbatts); if (ups->UPS_Cap[CI_REVNO]) s_write(ups, "FIRMWARE : %s\n", ups->firmrev); read_unlock(ups); /* put the current time in the END APC record */ format_date(now, datetime, sizeof(datetime)); s_write(ups, "END APC : %s\n", datetime); return s_close(ups, sockfd); } /* * stat_open(), stat_close(), and stat_write() are called * by output_status() to open,close, and write the status * report. */ void stat_open(UPSINFO *ups) { } int stat_close(UPSINFO *ups, int fd) { return 0; } void stat_print(UPSINFO *ups, const char *fmt, ...) { va_list arg_ptr; va_start(arg_ptr, fmt); vfprintf(stdout, (char *)fmt, arg_ptr); va_end(arg_ptr); } apcupsd-3.14.14/src/lib/astring.cpp000066400000000000000000000072421274230402600170400ustar00rootroot00000000000000/* * astring.cpp * * Simple string management class. Like STL, but lighter. */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include #include #include #include "astring.h" int astring::format(const char *format, ...) { va_list args; va_start(args, format); vformat(format, args); va_end(args); return _len; } int astring::vformat(const char *format, va_list ap) { va_list args; va_copy(args, ap); int len = vsnprintf(NULL, 0, format, args); va_end(args); if (len <= 0) { assign(""); return 0; } delete [] _data; _len = len; _data = new char[_len+1]; va_copy(args, ap); vsnprintf(_data, _len+1, format, args); va_end(args); return _len; } astring &astring::operator=(const astring &rhs) { *this = rhs._data; return *this; } astring &astring::operator=(const char *rhs) { if (rhs != _data) assign(rhs); return *this; } astring &astring::operator=(const char rhs) { assign(&rhs, 1); return *this; } const char &astring::operator[](int index) const { if (index >= 0 && index < _len) return _data[index]; if (index < 0 && index >= -_len) return _data[_len-index]; // Bogus index, bail abort(); } char &astring::operator[](int index) { if (index >= 0 && index < (int)_len) return _data[index]; if (index < 0 && index >= -_len) return _data[_len-index]; // Bogus index, bail abort(); } astring &astring::operator+(const char *rhs) { if (rhs && rhs != _data) { _len += strlen(rhs); realloc(_len); strcat(_data, rhs); } return *this; } astring &astring::operator+(const astring &rhs) { if (&rhs != this) *this += rhs._data; return *this; } astring &astring::operator+(const char rhs) { realloc(_len+1); _data[_len] = rhs; _data[++_len] = '\0'; return *this; } astring &astring::rtrim() { while (_len >= 1 && isspace(_data[_len-1])) _data[--_len] = '\0'; return *this; } astring &astring::ltrim() { size_t trim = strspn(_data, " \t\r\n"); memmove(_data, _data+trim, _len-trim+1); _len -= trim; return *this; } void astring::realloc(unsigned int newsize) { char *data = new char[newsize+1]; strncpy(data, _data, newsize); data[newsize] = '\0'; delete [] _data; _data = data; } void astring::assign(const char *str, int len) { if (!str) len = 0; delete [] _data; _len = (len < 0) ? strlen(str) : len; _data = new char[_len+1]; strncpy(_data, str, _len); _data[_len] = '\0'; } astring astring::substr(int start, int len) const { astring ret; if (start > _len) return ret; if (start < 0) { start += _len; if (start < 0) start = 0; } if (len < 0) { len = _len-start; if (len < 0) len = 0; } ret.assign(_data+start, len); return ret; } int astring::strchr(char ch) const { char *tmp = ::strchr(_data, ch); if (!tmp) return -1; return tmp-_data; } apcupsd-3.14.14/src/lib/asys.c000066400000000000000000000070031274230402600160030ustar00rootroot00000000000000/* * asys.c * * Miscellaneous apcupsd memory and thread safe routines * Generally, these are interfaces to system or standard * library routines. * * Adapted from Bacula source code */ /* * Copyright (C) 2004 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #define BIG_BUF 5000 /* Implement snprintf */ int asnprintf(char *str, size_t size, const char *fmt, ...) { #ifdef HAVE_VSNPRINTF va_list arg_ptr; int len; va_start(arg_ptr, fmt); len = vsnprintf(str, size, fmt, arg_ptr); va_end(arg_ptr); str[size - 1] = 0; return len; #else va_list arg_ptr; int len; char *buf; buf = (char *)malloc(BIG_BUF); va_start(arg_ptr, fmt); len = vsprintf(buf, fmt, arg_ptr); va_end(arg_ptr); if (len >= BIG_BUF) Error_abort("Buffer overflow.\n"); memcpy(str, buf, size); str[size - 1] = 0; free(buf); return len; #endif } /* Implement vsnprintf() */ int avsnprintf(char *str, size_t size, const char *format, va_list ap) { #ifdef HAVE_VSNPRINTF int len; len = vsnprintf(str, size, format, ap); str[size - 1] = 0; return len; #else int len; char *buf; buf = (char *)malloc(BIG_BUF); len = vsprintf(buf, format, ap); if (len >= BIG_BUF) Error_abort("Buffer overflow.\n"); memcpy(str, buf, size); str[size - 1] = 0; free(buf); return len; #endif } /* * These are mutex routines that do error checking * for deadlock and such. Normally not turned on. */ #ifdef DEBUG_MUTEX void _p(char *file, int line, pthread_mutex_t *m) { int errstat; if ((errstat = pthread_mutex_trylock(m))) { e_msg(file, line, M_ERROR, 0, "Possible mutex deadlock.\n"); /* We didn't get the lock, so do it definitely now */ if ((errstat = pthread_mutex_lock(m))) { e_msg(file, line, M_ABORT, 0, "Mutex lock failure. ERR=%s\n", strerror(errstat)); } else { e_msg(file, line, M_ERROR, 0, "Possible mutex deadlock resolved.\n"); } } } void _v(char *file, int line, pthread_mutex_t *m) { int errstat; if ((errstat = pthread_mutex_trylock(m)) == 0) { e_msg(file, line, M_ERROR, 0, "Mutex unlock not locked. ERR=%s\n", strerror(errstat)); } if ((errstat = pthread_mutex_unlock(m))) { e_msg(file, line, M_ABORT, 0, "Mutex unlock failure. ERR=%s\n", strerror(errstat)); } } #endif /* DEBUG_MUTEX */ #ifndef HAVE_STRLCPY size_t strlcpy(char *dst, const char *src, size_t size) { size_t cnt = 0; if (size) { while (*src && cnt < size-1) { *dst++ = *src++; ++cnt; } *dst = '\0'; } while (*src++) ++cnt; return cnt; } #endif #ifndef HAVE_STRLCAT size_t strlcat(char *dst, const char *src, size_t size) { size_t cnt = 0; while (*dst && cnt < size) { ++dst; ++cnt; } cnt += strlcpy(dst, src, size-cnt); return cnt; } #endif apcupsd-3.14.14/src/lib/athread.cpp000066400000000000000000000031061274230402600167740ustar00rootroot00000000000000/* * athread.cpp * * Simple POSIX based thread class */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "athread.h" const int athread::PRIORITY_INHERIT = -1; bool athread::run() { if (_running) return false; pthread_attr_t attr; pthread_attr_init(&attr); int inherit = PTHREAD_INHERIT_SCHED; if (_prio != PRIORITY_INHERIT) { struct sched_param param; param.sched_priority = _prio; pthread_attr_setschedparam(&attr, ¶m); inherit = PTHREAD_EXPLICIT_SCHED; } pthread_attr_setinheritsched(&attr, inherit); int rc = pthread_create(&_tid, &attr, &athread::springboard, this); if (rc == 0) _running = true; pthread_attr_destroy(&attr); return _running; } void *athread::springboard(void *arg) { athread *_this = (athread*)arg; _this->body(); _this->_running = false; return NULL; } bool athread::join() { return pthread_join(_tid, NULL) == 0; } apcupsd-3.14.14/src/lib/atimer.cpp000066400000000000000000000043771274230402600166600ustar00rootroot00000000000000/* * atimer.cpp */ /* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "atimer.h" #include "autil.h" #include atimer::atimer(client &cli, int id) : _client(cli), _id(id), _started(false) { pthread_mutex_init(&_mutex, NULL); pthread_cond_init(&_condvar, NULL); } atimer::~atimer() { stop(); pthread_cond_destroy(&_condvar); pthread_mutex_destroy(&_mutex); } void atimer::start(unsigned long timeout) { pthread_mutex_lock(&_mutex); if (!_started) { calc_abstimeout(timeout, &_abstimeout); _started = true; run(); } pthread_mutex_unlock(&_mutex); } void atimer::stop() { pthread_mutex_lock(&_mutex); if (_started) { _started = false; pthread_cond_signal(&_condvar); pthread_mutex_unlock(&_mutex); join(); } else pthread_mutex_unlock(&_mutex); } void atimer::body() { int rc; pthread_mutex_lock(&_mutex); while (_started) { rc = pthread_cond_timedwait(&_condvar, &_mutex, &_abstimeout); if (rc == ETIMEDOUT) { // Timeout ocurred, invoke callback... // No longer running _started = false; // Unlock around callback to allow restart pthread_mutex_unlock(&_mutex); _client.HandleTimeout(_id); pthread_mutex_lock(&_mutex); } else if (rc != 0) { // Error, exit timer loop _started = false; } else { // Condvar was signaled or we got a spurrious wakeup // In either case, we just ignore it and loop around } } pthread_mutex_unlock(&_mutex); } apcupsd-3.14.14/src/lib/autil.cpp000066400000000000000000000025131274230402600165030ustar00rootroot00000000000000/* * autil.cpp * * Common helper routines for a* classes. */ /* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "autil.h" #include "apc.h" void calc_abstimeout(int msec, struct timespec *abstime) { // It would be best to use clock_gettime here, but it is not // widely available, so use gettimeofday() which we can count on // being available, if not quite as accurate. struct timeval now; gettimeofday(&now, NULL); abstime->tv_sec = now.tv_sec + msec/1000; abstime->tv_nsec = now.tv_usec*1000 + (msec % 1000) * 1000000; if (abstime->tv_nsec >= 1000000000) { abstime->tv_sec++; abstime->tv_nsec -= 1000000000; } } apcupsd-3.14.14/src/lib/cloexec.c000066400000000000000000000042131274230402600164460ustar00rootroot00000000000000/* * cloexec.c * * Utilities for handling CLOEXEC */ /* * Copyright (C) 2015 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" /* Create socket with FD_CLOEXEC set */ sock_t socket_cloexec(int domain, int type, int protocol) { sock_t s; #ifdef SOCK_CLOEXEC s = socket(domain, type | SOCK_CLOEXEC, protocol); if (s == INVALID_SOCKET && errno == EINVAL) { #endif // No SOCK_CLOEXEC, emulatre via fcntl s = socket(domain, type, protocol); #ifdef FD_CLOEXEC if (s != INVALID_SOCKET) { int flags; if ((flags = fcntl(s, F_GETFD)) == -1 || fcntl(s, F_SETFD, flags | FD_CLOEXEC) == -1) { Dmsg(0, "%s: Failed to set CLOEXEC\n", __func__); } } #endif #ifdef SOCK_CLOEXEC } #endif return s; } /* Accept connection with FD_CLOEXEC set */ sock_t accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { sock_t s; #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) s = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC); if (s == INVALID_SOCKET && errno == ENOSYS) { #endif // No accept4, emulate via fcntl s = accept(sockfd, addr, addrlen); #ifdef FD_CLOEXEC if (s != INVALID_SOCKET) { int flags; if ((flags = fcntl(s, F_GETFD)) == -1 || fcntl(s, F_SETFD, flags | FD_CLOEXEC) == -1) { Dmsg(0, "%s: Failed to set CLOEXEC\n", __func__); } } #endif #if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC) } #endif return s; } apcupsd-3.14.14/src/lib/gethostname.c000066400000000000000000000034631274230402600173500ustar00rootroot00000000000000#include "apc.h" #ifdef HAVE_FUNC_GETHOSTBYNAME_R_6 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) { struct hostent *hp; int herr,res; if (*hstbuflen == 0) { *hstbuflen = 1024; *tmphstbuf = (char *)malloc (*hstbuflen); } while (( res = gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&hp,&herr)) && (errno == ERANGE)) { /* Enlarge the buffer. */ *hstbuflen *= 2; *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen); } if (res) return NULL; return hp; } #endif #ifdef HAVE_FUNC_GETHOSTBYNAME_R_5 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) { struct hostent *hp; int herr; if (*hstbuflen == 0) { *hstbuflen = 1024; *tmphstbuf = (char *)malloc (*hstbuflen); } while ((NULL == ( hp = gethostbyname_r(host,hostbuf,*tmphstbuf,*hstbuflen,&herr))) && (errno == ERANGE)) { /* Enlarge the buffer. */ *hstbuflen *= 2; *tmphstbuf = (char *)realloc (*tmphstbuf,*hstbuflen); } return hp; } #endif #ifdef HAVE_FUNC_GETHOSTBYNAME_R_3 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) { if (*hstbuflen == 0) { *hstbuflen = sizeof(struct hostent_data); *tmphstbuf = (char *)malloc (*hstbuflen); } else if (*hstbuflen < sizeof(struct hostent_data)) { *hstbuflen = sizeof(struct hostent_data); *tmphstbuf = (char *)realloc(*tmphstbuf, *hstbuflen); } memset((void *)(*tmphstbuf),0,*hstbuflen); if (0 != gethostbyname_r(host,hostbuf,(struct hostent_data *)*tmphstbuf)) return NULL; return hostbuf; } #endif #ifdef HAVE_FUNC_GETHOSTBYNAME_R_0 struct hostent * gethostname_re (const char *host,struct hostent *hostbuf,char **tmphstbuf,size_t *hstbuflen) { return gethostbyname(host); } #endif apcupsd-3.14.14/src/lib/getopt.c000066400000000000000000000532041274230402600163320ustar00rootroot00000000000000/* Getopt for GNU. NOTE: getopt is now part of the C library, so if you don't know what "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95 Free Software Foundation, Inc. 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO #define _NO_PROTO #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #if !defined (__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ /* Don't include stdlib.h for non-GNU C libraries because some of them contain conflicting prototypes for getopt. */ #include #endif /* GNU C library. */ /* This is for other GNU distributions with internationalized messages. The GNU C Library itself does not yet support such messages. */ #if HAVE_LIBINTL_H # include #else # define gettext(msgid) (msgid) #endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user to intersperse the options with the other arguments. As `getopt' works, it permutes the elements of ARGV so that, when it is done, all the options precede everything else. Thus all application programs are extended to handle flexible argument order. Setting the environment variable POSIXLY_CORRECT disables permutation. Then the behavior is completely standard. GNU application programs can use a third alternative mode in which they can distinguish the relative order of options and other arguments. */ #include "getopt.h" /* For communication from `getopt' to the caller. When `getopt' finds an option that takes an argument, the argument value is returned here. Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller and for communication between successive calls to `getopt'. On entry to `getopt', zero means this is the first call; initialize. When `getopt' returns EOF, this is the index of the first of the non-option elements that the caller should itself scan. Otherwise, `optind' communicates from one call to the next how much of ARGV has been scanned so far. */ /* XXX 1003.2 says this must be 1 before any call. */ int optind = 0; /* The next char to be scanned in the option-element in which the last option character we returned was found. This allows us to pick up the scan where we left off. If this is zero, or a null string, it means resume the scan by advancing to the next ARGV-element. */ static char *nextchar; /* Callers store zero here to inhibit the error message for unrecognized options. */ int opterr = 1; /* Set to an option character which was unrecognized. This must be initialized on some systems to avoid linking in the system's own getopt implementation. */ int optopt = '?'; /* Describe how to deal with options that follow non-option ARGV-elements. If the caller did not specify anything, the default is REQUIRE_ORDER if the environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. REQUIRE_ORDER means don't recognize them as options; stop option processing when the first non-option is seen. This is what Unix does. This mode of operation is selected by either setting the environment variable POSIXLY_CORRECT, or using `+' as the first character of the list of option characters. PERMUTE is the default. We permute the contents of ARGV as we scan, so that eventually all the non-options are at the end. This allows options to be given in any order, even with programs that were not written to expect this. RETURN_IN_ORDER is an option available to programs that were written to expect options and other ARGV-elements in any order and that care about the ordering of the two. We describe each non-option ARGV-element as if it were the argument of an option with character code 1. Using `-' as the first character of the list of option characters selects this mode of operation. The special argument `--' forces an end of option-scanning regardless of the value of `ordering'. In the case of RETURN_IN_ORDER, only `--' can cause `getopt' to return EOF with `optind' != ARGC. */ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; /* Value of POSIXLY_CORRECT environment variable. */ static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries because there are many ways it can cause trouble. On some systems, it contains special magic macros that don't work in GCC. */ #include #define my_index strchr #else /* Avoid depending on library functions or files whose names are inconsistent. */ /* ADK: No, let's just include the darn thing and be done with it. */ /* char *getenv (); */ #include static char * my_index (const char *str, int chr) { while (*str) { if (*str == chr) return (char *) str; str++; } return 0; } /* If using GCC, we can safely declare strlen this way. If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. That was relevant to code that was here before. */ #if !defined (__STDC__) || !__STDC__ /* gcc with -traditional declares the built-in strlen to return int, and has done so at least since version 2.4.5. -- rms. */ extern int strlen (const char *); #endif /* not __STDC__ */ #endif /* __GNUC__ */ #endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ /* Describe the part of ARGV that contains non-options that have been skipped. `first_nonopt' is the index in ARGV of the first of them; `last_nonopt' is the index after the last of them. */ static int first_nonopt; static int last_nonopt; /* Exchange two adjacent subsequences of ARGV. One subsequence is elements [first_nonopt,last_nonopt) which contains all the non-options that have been skipped so far. The other is elements [last_nonopt,optind), which contains all the options processed since those non-options were skipped. `first_nonopt' and `last_nonopt' are relocated so that they describe the new indices of the non-options in ARGV after they are moved. */ static void exchange (char **argv) { int bottom = first_nonopt; int middle = last_nonopt; int top = optind; char *tem; /* Exchange the shorter segment with the far end of the longer segment. That puts the shorter segment into the right place. It leaves the longer segment in the right place overall, but it consists of two parts that need to be swapped next. */ while (top > middle && middle > bottom) { if (top - middle > middle - bottom) { /* Bottom segment is the short one. */ int len = middle - bottom; register int i; /* Swap it with the top part of the top segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[top - (middle - bottom) + i]; argv[top - (middle - bottom) + i] = tem; } /* Exclude the moved bottom segment from further swapping. */ top -= len; } else { /* Top segment is the short one. */ int len = top - middle; register int i; /* Swap it with the bottom part of the bottom segment. */ for (i = 0; i < len; i++) { tem = argv[bottom + i]; argv[bottom + i] = argv[middle + i]; argv[middle + i] = tem; } /* Exclude the moved top segment from further swapping. */ bottom += len; } } /* Update records for the slots the non-options now occupy. */ first_nonopt += (optind - last_nonopt); last_nonopt = optind; } /* Initialize the internal data when the first call is made. */ static const char * _getopt_initialize (const char *optstring) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped non-option ARGV-elements is empty. */ first_nonopt = last_nonopt = optind = 1; nextchar = NULL; posixly_correct = getenv ("POSIXLY_CORRECT"); /* Determine how to handle the ordering of options and nonoptions. */ if (optstring[0] == '-') { ordering = RETURN_IN_ORDER; ++optstring; } else if (optstring[0] == '+') { ordering = REQUIRE_ORDER; ++optstring; } else if (posixly_correct != NULL) ordering = REQUIRE_ORDER; else ordering = PERMUTE; return optstring; } /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. If an element of ARGV starts with '-', and is not exactly "-" or "--", then it is an option element. The characters of this element (aside from the initial '-') are option characters. If `getopt' is called repeatedly, it returns successively each of the option characters from each of the option elements. If `getopt' finds another option character, it returns that character, updating `optind' and `nextchar' so that the next call to `getopt' can resume the scan with the following option character or ARGV-element. If there are no more option characters, `getopt' returns `EOF'. Then `optind' is the index in ARGV of the first ARGV-element that is not an option. (The ARGV-elements have been permuted so that those that are not options now come last.) OPTSTRING is a string containing the legitimate option characters. If an option character is seen that is not listed in OPTSTRING, return '?' after printing an error message. If you set `opterr' to zero, the error message is suppressed but we still return '?'. If a char in OPTSTRING is followed by a colon, that means it wants an arg, so the following text in the same ARGV-element, or the text of the following ARGV-element, is returned in `optarg'. Two colons mean an option that wants an optional arg; if there is text in the current ARGV-element, it is returned in `optarg', otherwise `optarg' is set to zero. If OPTSTRING starts with `-' or `+', it requests different methods of handling the non-option ARGV-elements. See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. Long-named options begin with `--' instead of `-'. Their names may be abbreviated as long as the abbreviation is unique or is an exact match for some defined option. If they have an argument, it follows the option name in the same ARGV-element, separated from the option name by a `=', or else the in next ARGV-element. When `getopt' finds a long-named option, it returns 0 if that option's `flag' field is nonzero, the value of the option's `val' field if the `flag' field is zero. The elements of ARGV aren't really const, because we permute them. But we pretend they're const in the prototype to be compatible with other systems. LONGOPTS is a vector of `struct option' terminated by an element containing a name which is zero. LONGIND returns the index in LONGOPT of the long-named option found. It is only valid when a long-named option has been found by the most recent call. If LONG_ONLY is nonzero, '-' as well as '--' can introduce long-named options. */ int _getopt_internal (int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, int long_only) { optarg = NULL; if (optind == 0) { optstring = _getopt_initialize (optstring); optind = 1; /* Don't scan ARGV[0], the program name. */ } if (nextchar == NULL || *nextchar == '\0') { /* Advance to the next ARGV-element. */ if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, exchange them so that the options come first. */ if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (last_nonopt != optind) first_nonopt = optind; /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0')) optind++; last_nonopt = optind; } /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ if (optind != argc && !strcmp (argv[optind], "--")) { optind++; if (first_nonopt != last_nonopt && last_nonopt != optind) exchange ((char **) argv); else if (first_nonopt == last_nonopt) first_nonopt = optind; last_nonopt = argc; optind = argc; } /* If we have done all the ARGV-elements, stop the scan and back over any non-options that we skipped and permuted. */ if (optind == argc) { /* Set the next-arg-index to point at the non-options that we previously skipped, so the caller will digest them. */ if (first_nonopt != last_nonopt) optind = first_nonopt; return EOF; } /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) { if (ordering == REQUIRE_ORDER) return EOF; optarg = argv[optind++]; return 1; } /* We have found another option-ARGV-element. Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } /* Decode the current option-ARGV-element. */ /* Check whether the ARGV-element is a long option. If long_only and the ARGV-element has the form "-f", where f is a valid short option, don't consider it an abbreviated form of a long option that starts with f. Otherwise there would be no way to give the -f short option. On the other hand, if there's a long option "fubar" and the ARGV-element is "-fu", do consider that an abbreviation of the long option, just like "--fu", and not "-f" with arg "u". This distinction seems to be the most useful approach. */ if (longopts != NULL && (argv[optind][1] == '-' || (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) { char *nameend; const struct option *p; const struct option *pfound = NULL; int exact = 0; int ambig = 0; int indfound = 0; int option_index; for (nameend = nextchar; *nameend && *nameend != '='; nameend++) /* Do nothing. */ ; /* Test all long options for either exact match or abbreviated matches. */ for (p = longopts, option_index = 0; p->name; p++, option_index++) if (!strncmp (p->name, nextchar, nameend - nextchar)) { if (nameend - nextchar == strlen (p->name)) { /* Exact match found. */ pfound = p; indfound = option_index; exact = 1; break; } else if (pfound == NULL) { /* First nonexact match found. */ pfound = p; indfound = option_index; } else /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) fprintf (stderr, gettext ("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; return '?'; } if (pfound != NULL) { option_index = indfound; optind++; if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) optarg = nameend + 1; else { if (opterr) { if (argv[optind - 1][1] == '-') { /* --option */ fprintf (stderr, gettext ("%s: option `--%s' doesn't allow an argument\n"), argv[0], pfound->name); } else { /* +option or -option */ fprintf (stderr, gettext ("%s: option `%c%s' doesn't allow an argument\n"), argv[0], argv[optind - 1][0], pfound->name); } } nextchar += strlen (nextchar); return '?'; } } else if (pfound->has_arg == 1) { if (optind < argc) optarg = argv[optind++]; else { if (opterr) fprintf (stderr, gettext ("%s: option `%s' requires an argument\n"), argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } } nextchar += strlen (nextchar); if (longind != NULL) *longind = option_index; if (pfound->flag) { *(pfound->flag) = pfound->val; return 0; } return pfound->val; } /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ fprintf (stderr, gettext ("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ fprintf (stderr, gettext ("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; optind++; return '?'; } } /* Look at and handle the next short option-character. */ { char c = *nextchar++; char *temp = my_index (optstring, c); /* Increment `optind' when we start to process its last character. */ if (*nextchar == '\0') ++optind; if (temp == NULL || c == ':') { if (opterr) { if (posixly_correct) /* 1003.2 specifies the format of this message. */ fprintf (stderr, gettext ("%s: illegal option -- %c\n"), argv[0], c); else fprintf (stderr, gettext ("%s: invalid option -- %c\n"), argv[0], c); } optopt = c; return '?'; } if (temp[1] == ':') { if (temp[2] == ':') { /* This is an option that accepts an argument optionally. */ if (*nextchar != '\0') { optarg = nextchar; optind++; } else optarg = NULL; nextchar = NULL; } else { /* This is an option that requires an argument. */ if (*nextchar != '\0') { optarg = nextchar; /* If we end this ARGV-element by taking the rest as an arg, we must advance to the next element now. */ optind++; } else if (optind == argc) { if (opterr) { /* 1003.2 specifies the format of this message. */ fprintf (stderr, gettext ("%s: option requires an argument -- %c\n"), argv[0], c); } optopt = c; if (optstring[0] == ':') c = ':'; else c = '?'; } else /* We already incremented `optind' once; increment it again when taking next ARGV-elt as argument. */ optarg = argv[optind++]; nextchar = NULL; } } return c; } } int getopt (int argc, char *const *argv, const char *optstring) { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, (int *) 0, 0); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST /* Compile with -DTEST to make an executable for use in testing the above definition of `getopt'. */ int main (int argc, char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; c = getopt (argc, argv, "abc:d:0123456789"); if (c == EOF) break; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ apcupsd-3.14.14/src/lib/getopt1.c000066400000000000000000000100311274230402600164020ustar00rootroot00000000000000/* getopt_long and getopt_long_only entry points for GNU getopt. Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994 Free Software Foundation, Inc. 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, 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, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "getopt.h" #if !defined (__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const #define const #endif #endif #include /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling and linking in this code is a waste when using the GNU C library (especially if it is a shared library). Rather than having every GNU program understand `configure --with-gnu-libc' and omit the object files, it is simpler to just do this in the source for each such file. */ #if defined (_LIBC) || !defined (__GNU_LIBRARY__) /* This needs to come after some library #include to get __GNU_LIBRARY__ defined. */ #ifdef __GNU_LIBRARY__ #include #else char *getenv (); #endif #ifndef NULL #define NULL 0 #endif int getopt_long (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } /* Like getopt_long, but '-' as well as '--' can indicate a long option. If an option that starts with '-' (not '--') doesn't match a long option, but does match a short option, it is parsed as a short option instead. */ int getopt_long_only (int argc, char *const *argv, const char *options, const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } #endif /* _LIBC or not __GNU_LIBRARY__. */ #ifdef TEST #include int main (int argc, char **argv) { int c; int digit_optind = 0; while (1) { int this_option_optind = optind ? optind : 1; int option_index = 0; static struct option long_options[] = { {"add", 1, 0, 0}, {"append", 0, 0, 0}, {"delete", 1, 0, 0}, {"verbose", 0, 0, 0}, {"create", 0, 0, 0}, {"file", 1, 0, 0}, {0, 0, 0, 0} }; c = getopt_long (argc, argv, "abc:d:0123456789", long_options, &option_index); if (c == EOF) break; switch (c) { case 0: printf ("option %s", long_options[option_index].name); if (optarg) printf (" with arg %s", optarg); printf ("\n"); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (digit_optind != 0 && digit_optind != this_option_optind) printf ("digits occur in two different argv-elements.\n"); digit_optind = this_option_optind; printf ("option %c\n", c); break; case 'a': printf ("option a\n"); break; case 'b': printf ("option b\n"); break; case 'c': printf ("option c with value `%s'\n", optarg); break; case 'd': printf ("option d with value `%s'\n", optarg); break; case '?': break; default: printf ("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { printf ("non-option ARGV-elements: "); while (optind < argc) printf ("%s ", argv[optind++]); printf ("\n"); } exit (0); } #endif /* TEST */ apcupsd-3.14.14/src/lib/inet_pton.c000066400000000000000000000125201274230402600170230ustar00rootroot00000000000000/* Copyright (c) 1996 by Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. */ #if defined(LIBC_SCCS) && !defined(lint) static char rcsid[] = "$Id: inet_pton.c,v 1.7 2006-08-12 00:00:28 adk0212 Exp $"; #endif /* LIBC_SCCS and not lint */ #include "apc.h" #include #include #include #include #include #include #include /* * WARNING: Don't even consider trying to compile this on a system where * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. */ static int inet_pton4 __P((const char *src, u_char *dst)); #ifdef AF_INET6 static int inet_pton6 __P((const char *src, u_char *dst)); #endif /* int * inet_pton(af, src, dst) * convert from presentation format (which usually means ASCII printable) * to network format (which is usually some kind of binary format). * return: * 1 if the address was valid for the specified address family * 0 if the address wasn't valid (`dst' is untouched in this case) * -1 if some other error occurred (`dst' is untouched in this case, too) * author: * Paul Vixie, 1996. */ int inet_pton(int af, const char *src, void *dst) { switch (af) { case AF_INET: return (inet_pton4(src, (u_char*)dst)); #ifdef AF_INET6 case AF_INET6: return (inet_pton6(src, (u_char*)dst)); #endif default: errno = EAFNOSUPPORT; return (-1); } /* NOTREACHED */ } /* int * inet_pton4(src, dst) * like inet_aton() but without all the hexadecimal and shorthand. * return: * 1 if `src' is a valid dotted quad, else 0. * notice: * does not touch `dst' unless it's returning 1. * author: * Paul Vixie, 1996. */ static int inet_pton4(const char *src, u_char *dst) { static const char digits[] = "0123456789"; int saw_digit, octets, ch; u_char tmp[NS_INADDRSZ], *tp; saw_digit = 0; octets = 0; *(tp = tmp) = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr(digits, ch)) != NULL) { u_int nw = *tp * 10 + (pch - digits); if (nw > 255) return (0); *tp = nw; if (! saw_digit) { if (++octets > 4) return (0); saw_digit = 1; } } else if (ch == '.' && saw_digit) { if (octets == 4) return (0); *++tp = 0; saw_digit = 0; } else return (0); } if (octets < 4) return (0); memcpy(dst, tmp, NS_INADDRSZ); return (1); } /* int * inet_pton6(src, dst) * convert presentation level address to network order binary form. * return: * 1 if `src' is a valid [RFC1884 2.2] address, else 0. * notice: * (1) does not touch `dst' unless it's returning 1. * (2) :: in a full address is silently ignored. * credit: * inspired by Mark Andrews. * author: * Paul Vixie, 1996. */ #ifdef AF_INET6 static int inet_pton6(const char *src, u_char *dst) { static const char xdigits_l[] = "0123456789abcdef", xdigits_u[] = "0123456789ABCDEF"; u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; const char *xdigits, *curtok; int ch, saw_xdigit; u_int val; memset((tp = tmp), '\0', NS_IN6ADDRSZ); endp = tp + NS_IN6ADDRSZ; colonp = NULL; /* Leading :: requires some special handling. */ if (*src == ':') if (*++src != ':') return (0); curtok = src; saw_xdigit = 0; val = 0; while ((ch = *src++) != '\0') { const char *pch; if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) pch = strchr((xdigits = xdigits_u), ch); if (pch != NULL) { val <<= 4; val |= (pch - xdigits); if (val > 0xffff) return (0); saw_xdigit = 1; continue; } if (ch == ':') { curtok = src; if (!saw_xdigit) { if (colonp) return (0); colonp = tp; continue; } if (tp + NS_INT16SZ > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; saw_xdigit = 0; val = 0; continue; } if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && inet_pton4(curtok, tp) > 0) { tp += NS_INADDRSZ; saw_xdigit = 0; break; /* '\0' was seen by inet_pton4(). */ } return (0); } if (saw_xdigit) { if (tp + NS_INT16SZ > endp) return (0); *tp++ = (u_char) (val >> 8) & 0xff; *tp++ = (u_char) val & 0xff; } if (colonp != NULL) { /* * Since some memmove()'s erroneously fail to handle * overlapping regions, we'll do the shift by hand. */ const int n = tp - colonp; int i; for (i = 1; i <= n; i++) { endp[- i] = colonp[n - i]; colonp[n - i] = 0; } tp = endp; } if (tp != endp) return (0); memcpy(dst, tmp, NS_IN6ADDRSZ); return (1); } #endif /* AF_INET6 */ apcupsd-3.14.14/src/lib/libsupc++fix.cpp000066400000000000000000000026321274230402600176650ustar00rootroot00000000000000/* * libsupc++fix.cpp * * Workaround for broken libsupc++ on FreeBSD 5.x and early 6.x. * FreeBSD 5.x and early 6.x inadvertantly left out some critical * files from libsupc++.a. See FreeBSD PR 99702: * * * This file is a hack-around I came up with that seems to work. */ /* * Copyright (C) 2010 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include void* operator new[] (std::size_t size) { return malloc(size); } void* operator new (std::size_t size) { return malloc(size); } void operator delete (void *p) { free(p); } void operator delete[] (void *p) { free(p); } namespace __cxxabiv1 { std::terminate_handler __terminate_handler; std::unexpected_handler __unexpected_handler; }; apcupsd-3.14.14/src/lib/localtime_r.c000066400000000000000000000023271274230402600173220ustar00rootroot00000000000000/* * localtime_r.c * * Implementation of reentrant localtime(), for platforms don't * already have it. */ /* * Copyright (C) 1999-2005 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #if !defined(HAVE_LOCALTIME_R) && !defined(localtime_r) struct tm *localtime_r(const time_t *timep, struct tm *tm) { static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; struct tm *ltm; P(mutex); ltm = localtime(timep); if (ltm) memcpy(tm, ltm, sizeof(struct tm)); V(mutex); return ltm ? tm : NULL; } #endif /* !defined(HAVE_LOCALTIME_R) */ apcupsd-3.14.14/src/lib/md5.c000066400000000000000000000302261274230402600155140ustar00rootroot00000000000000/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c,v 1.1 2006-07-22 15:14:15 adk0212 Exp $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #include #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } apcupsd-3.14.14/src/lib/memmove.c000066400000000000000000000020771274230402600164770ustar00rootroot00000000000000/* * memmove.c * * Implementation of memmove(), presumable for platforms that don't * already have it. */ /* * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ char *memmove(char *dst, register char *src, register int n) { register char *svdst; if ((dst > src) && (dst < src + n)) { src += n; for (svdst = dst + n; n-- > 0;) *--svdst = *--src; } else { for (svdst = dst; n-- > 0;) *svdst++ = *src++; } return dst; } apcupsd-3.14.14/src/lib/nanosleep.c000066400000000000000000000035451274230402600170170ustar00rootroot00000000000000/* * sleep.c * * Implementations of sleep-related functions for platforms that * do not already have them. */ /* * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #ifndef HAVE_NANOSLEEP /* * This is a close approximation of nanosleep() for platforms that * do not have it. */ int nanosleep(const struct timespec *req, struct timespec *rem) { static pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t timer = PTHREAD_COND_INITIALIZER; struct timespec timeout; int stat; struct timeval tv; /* Copy relative exit time */ timeout = *req; /* Compute absolute exit time */ gettimeofday(&tv, NULL); timeout.tv_nsec += tv.tv_usec * 1000; timeout.tv_sec += tv.tv_sec; while (timeout.tv_nsec >= 1000000000) { timeout.tv_nsec -= 1000000000; timeout.tv_sec++; } Dmsg(200, "pthread_cond_timedwait sec=%d\n", timeout.tv_sec); /* Mutex is unlocked during the timedwait */ P(timer_mutex); stat = pthread_cond_timedwait(&timer, &timer_mutex, &timeout); Dmsg(200, "pthread_cond_timedwait stat=%d\n", stat); V(timer_mutex); /* Assume no time leftover */ if (rem) { rem->tv_nsec = 0; rem->tv_sec = 0; } return 0; } #endif /* HAVE_NANOSLEEP */ apcupsd-3.14.14/src/lib/newups.c000066400000000000000000000047361274230402600163570ustar00rootroot00000000000000/* * newups.c * * Create UPS structure and do locking/unlocking on it * */ /* * Copyright (C) 2000-2006 Kern Sibbald * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" /* * NOTE! P() locks a mutex, and V() unlocks it. Both abort if there * is a mutex error. So testing return codes is not necessary. */ UPSINFO *new_ups() { int stat; UPSINFO *ups; ups = (UPSINFO *) malloc(sizeof(UPSINFO)); if (!ups) Error_abort("Could not allocate ups memory\n"); memset(ups, 0, sizeof(UPSINFO)); if ((stat = pthread_mutex_init(&ups->mutex, NULL)) != 0) { Error_abort("Could not create pthread mutex. ERR=%s\n", strerror(stat)); free(ups); return NULL; } /* Most drivers do not support this, so preset it to true */ ups->set_battpresent(); ups->refcnt = 1; return ups; } /* Attach to ups structure or create a new one */ UPSINFO *attach_ups(UPSINFO *ups) { if (!ups) return new_ups(); P(ups->mutex); ups->refcnt++; V(ups->mutex); return ups; } void detach_ups(UPSINFO *ups) { P(ups->mutex); ups->refcnt--; if (ups->refcnt == 0) { destroy_ups(ups); return; // no unlock since mutex has been destroyed } V(ups->mutex); } void destroy_ups(UPSINFO *ups) { pthread_mutex_destroy(&ups->mutex); if (ups->refcnt == 0) { free(ups); } } void _read_lock(const char *file, int line, UPSINFO *ups) { Dmsg(100, "read_lock at %s:%d\n", file, line); P(ups->mutex); } void _read_unlock(const char *file, int line, UPSINFO *ups) { Dmsg(100, "read_unlock at %s:%d\n", file, line); V(ups->mutex); } void _write_lock(const char *file, int line, UPSINFO *ups) { Dmsg(100, "write_lock at %s:%d\n", file, line); P(ups->mutex); } void _write_unlock(const char *file, int line, UPSINFO *ups) { Dmsg(100, "write_unlock at %s:%d\n", file, line); V(ups->mutex); } apcupsd-3.14.14/src/lib/statmgr.cpp000066400000000000000000000135011274230402600170450ustar00rootroot00000000000000/* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "statmgr.h" #include StatMgr::StatMgr(const char *host, unsigned short port) : m_host(host), m_port(port), m_socket(INVALID_SOCKET) { memset(m_stats, 0, sizeof(m_stats)); } StatMgr::~StatMgr() { lock(); close(); } bool StatMgr::Update() { lock(); int tries; for (tries = 2; tries; tries--) { if (m_socket == INVALID_SOCKET && !open()) { // Hard failure: bail immediately unlock(); return false; } if (net_send(m_socket, "status", 6) != 6) { // Soft failure: close and try again close(); continue; } memset(m_stats, 0, sizeof(m_stats)); int len = 0; int i = 0; while (i < MAX_STATS && (len = net_recv(m_socket, m_stats[i].data, sizeof(m_stats[i].data)-1)) > 0) { char *key, *value; // NUL-terminate the string m_stats[i].data[len] = '\0'; // Find separator value = strchr(m_stats[i].data, ':'); // Trim whitespace from value if (value) { *value++ = '\0'; value = trim(value); } // Trim whitespace from key; key = trim(m_stats[i].data); m_stats[i].key = key; m_stats[i].value = value; i++; } // Good update, bail now if (i > 0 && len == 0) break; // Soft failure: close and try again close(); } unlock(); return tries > 0; } astring StatMgr::Get(const char* key) { astring ret; lock(); for (int idx=0; idx < MAX_STATS && m_stats[idx].key; idx++) { if (strcmp(key, m_stats[idx].key) == 0) { if (m_stats[idx].value) ret = m_stats[idx].value; break; } } unlock(); return ret; } bool StatMgr::GetAll(alist &keys, alist &values) { keys.clear(); values.clear(); lock(); for (int idx=0; idx < MAX_STATS && m_stats[idx].key; idx++) { keys.append(m_stats[idx].key); values.append(m_stats[idx].value); } unlock(); return true; } bool StatMgr::GetEvents(alist &events) { lock(); if (m_socket == INVALID_SOCKET && !open()) { unlock(); return false; } if (net_send(m_socket, "events", 6) != 6) { close(); unlock(); return false; } events.clear(); char temp[1024]; int len; while ((len = net_recv(m_socket, temp, sizeof(temp)-1)) > 0) { temp[len] = '\0'; rtrim(temp); events.append(temp); } if (len == -1) close(); unlock(); return true; } char *StatMgr::ltrim(char *str) { while(isspace(*str)) *str++ = '\0'; return str; } void StatMgr::rtrim(char *str) { char *tmp = str + strlen(str) - 1; while (tmp >= str && isspace(*tmp)) *tmp-- = '\0'; } char *StatMgr::trim(char *str) { str = ltrim(str); rtrim(str); return str; } void StatMgr::lock() { m_mutex.lock(); } void StatMgr::unlock() { m_mutex.unlock(); } bool StatMgr::open() { if (m_socket != INVALID_SOCKET) close(); m_socket = net_open(m_host, NULL, m_port); if (m_socket < 0) m_socket = INVALID_SOCKET; return m_socket != INVALID_SOCKET; } void StatMgr::close() { if (m_socket != INVALID_SOCKET) { net_close(m_socket); m_socket = INVALID_SOCKET; } } bool StatMgr::GetSummary(int &battstat, astring &statstr, astring &upsname) { // Fetch data from the UPS if (!Update()) { battstat = -1; statstr = "NETWORK ERROR"; return false; } // Lookup the STATFLAG key astring statflag = Get("STATFLAG"); if (statflag.empty()) { battstat = -1; statstr = "ERROR"; return false; } unsigned long status = strtoul(statflag, NULL, 0); // Lookup BCHARGE key astring bcharge = Get("BCHARGE"); // Determine battery charge percent if (status & UPS_onbatt) battstat = 0; else if (!bcharge.empty()) battstat = (int)atof(bcharge); else battstat = 100; // Fetch UPSNAME astring uname = Get("UPSNAME"); if (!uname.empty()) upsname = uname; // Now output status in human readable form statstr = ""; if (status & UPS_calibration) statstr += "CAL "; if (status & UPS_trim) statstr += "TRIM "; if (status & UPS_boost) statstr += "BOOST "; if (status & UPS_online) statstr += "ONLINE "; if (status & UPS_onbatt) statstr += "ONBATT "; if (status & UPS_overload) statstr += "OVERLOAD "; if (status & UPS_battlow) statstr += "LOWBATT "; if (status & UPS_replacebatt) statstr += "REPLACEBATT "; if (!(status & UPS_battpresent)) statstr += "NOBATT "; // This overrides the above if (status & UPS_commlost) { statstr = "COMMLOST"; battstat = -1; } // This overrides the above if (status & UPS_shutdown) statstr = "SHUTTING DOWN"; // This overrides the above if (status & UPS_onbatt) { astring reason = Get("LASTXFER"); if (strstr(reason, "self test")) statstr = "SELFTEST"; } // Remove trailing space, if present statstr.rtrim(); return true; } apcupsd-3.14.14/src/lib/strcasecmp.c000066400000000000000000000100151274230402600171650ustar00rootroot00000000000000/* * Copyright (c) 1987 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ #if defined(LIBC_SCCS) && !defined(lint) static char sccsid[] = "@(#)strcasecmp.c 5.6 (Berkeley) 6/27/88"; #endif /* LIBC_SCCS and not lint */ #if defined(QNX) #include #else #ifndef u_char typedef unsigned char u_char; #endif #endif /* * This array is designed for mapping upper and lower case letter * together for a case independent comparison. The mappings are * based upon ascii character sequences. */ static u_char charmap[] = { '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', }; strcasecmp(s1, s2) char *s1, *s2; { register u_char *cm = charmap, *us1 = (u_char *)s1, *us2 = (u_char *)s2; while (cm[*us1] == cm[*us2++]) if (*us1++ == '\0') return(0); return(cm[*us1] - cm[*--us2]); } strncasecmp(s1, s2, n) char *s1, *s2; register int n; { register u_char *cm = charmap, *us1 = (u_char *)s1, *us2 = (u_char *)s2; while (--n >= 0 && cm[*us1] == cm[*us2++]) if (*us1++ == '\0') return(0); return(n < 0 ? 0 : cm[*us1] - cm[*--us2]); } apcupsd-3.14.14/src/lib/strstr.c000066400000000000000000000032271274230402600163710ustar00rootroot00000000000000/* * strstr.c -- return the offset of one string within another. * * Copyright (C) 1997 Free Software Foundation, Inc. * * 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, 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 02110-1335, USA. */ /* Written by Philippe De Muyter . */ /* * NAME * * strstr -- locate first occurence of a substring * * SYNOPSIS * * char *strstr (char *s1, char *s2) * * DESCRIPTION * * Locates the first occurence in the string pointed to by S1 of the string * pointed to by S2. Returns a pointer to the substring found, or a NULL * pointer if not found. If S2 points to a string with zero length, the * function returns S1. * * BUGS * */ char * strstr (buf, sub) register char *buf; register char *sub; { register char *bp; if (!*sub) return buf; for (;;) { if (!*buf) break; bp = buf; for (;;) { if (!*sub) return buf; if (*bp++ != *sub++) break; } sub -= (unsigned long) bp; sub += (unsigned long) buf; buf += 1; } return 0; } apcupsd-3.14.14/src/lib/usbvidpid.cpp000066400000000000000000000045301274230402600173570ustar00rootroot00000000000000/* * Copyright (C) 2015 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "usb_common.h" static const uint16_t VENDOR_APC = 0x051D; static const uint16_t VENDOR_SCHNEIDER = 0x16DE; static const uint16_t VENDOR_HP = 0x03F0; // // Table of supported USB idVendor/idProduct tuples // // When updating this table, also update platforms including: // * platforms/mingw/winusb/apcupsd.inf // * platforms/darwin/Info.plist // * platforms/sun/Makefile // static const struct { uint16_t vid; uint16_t pid; } SUPPORTED_DEVICES[] = { {VENDOR_APC, 0x0002}, // Older APC UPSes {VENDOR_APC, 0x0003}, // AP9620 LCC and newer UPSes {VENDOR_APC, 0x0004}, // As of Jan 2015, the following are for future APC/Schneider products {VENDOR_APC, 0xC801}, {VENDOR_APC, 0xC802}, {VENDOR_APC, 0xC803}, {VENDOR_APC, 0xC804}, {VENDOR_APC, 0xC805}, {VENDOR_SCHNEIDER, 0xC801}, {VENDOR_SCHNEIDER, 0xC802}, {VENDOR_SCHNEIDER, 0xC803}, {VENDOR_SCHNEIDER, 0xC804}, {VENDOR_SCHNEIDER, 0xC805}, // Some oddballs {VENDOR_APC, 0x0001}, // Early prototype units of AP9620 {VENDOR_APC, 0xffff}, // Early prototype units of AP9620 {VENDOR_APC, 0x0005}, // An SMX750 appears to use PID 5 // The HP T1500 G3 has been shown to work well with apcupsd. // Not sure if it is an APC clone or just "very compatible". {VENDOR_HP, 0x1FE3}, {0} }; bool MatchVidPid(uint16_t vid, uint16_t pid) { for (unsigned int i = 0; SUPPORTED_DEVICES[i].vid; ++i) { if (SUPPORTED_DEVICES[i].vid == vid && SUPPORTED_DEVICES[i].pid == pid) return true; } return false; } apcupsd-3.14.14/src/libusbhid/000077500000000000000000000000001274230402600160575ustar00rootroot00000000000000apcupsd-3.14.14/src/libusbhid/HidUps.cpp000066400000000000000000000300511274230402600177560ustar00rootroot00000000000000/* * HidUps.cpp * * Utility functions for interfacing with the libusbhid userspace * HID parsing library. */ /* * Copyright (C) 2004-2014 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "HidUps.h" #include "usb_common.h" #include "astring.h" #define MAX_SANE_DESCRIPTOR_LEN 4096 HidUps::HidUps() : _fd(NULL), _rdesc(NULL) { } HidUps::~HidUps() { Close(); } bool HidUps::Open(const char *serno) { /* Set libusb debug level */ usb_set_debug(debug_level/100); /* Initialize libusb */ Dmsg(200, "Initializing libusb\n"); usb_init(); /* Enumerate usb busses and devices */ int i = usb_find_busses(); Dmsg(200, "Found %d USB busses\n", i); i = usb_find_devices(); Dmsg(200, "Found %d USB devices\n", i); /* Iterate over all devices */ struct usb_bus *bus = usb_get_busses(); while (bus) { struct usb_device *dev = bus->devices; while (dev) { Dmsg(200, "%s:%s - %04x:%04x\n", bus->dirname, dev->filename, dev->descriptor.idVendor, dev->descriptor.idProduct); if (init_device(dev, serno)) { /* Successfully found and initialized an UPS */ return true; } dev = dev->next; } bus = bus->next; } /* Failed to find an UPS */ return false; } void HidUps::Close() { if (_rdesc) { hid_dispose_report_desc(_rdesc); _rdesc = NULL; } if (_fd) { usb_release_interface(_fd, 0); usb_reset(_fd); usb_close(_fd); _fd = NULL; } } bool HidUps::init_device( struct usb_device *dev, const char *serno) { int rc; unsigned char* rdesc; int rdesclen; /* Check if this is a supported device before we mess with it */ if (!MatchVidPid(dev->descriptor.idVendor, dev->descriptor.idProduct)) { Dmsg(100, "Not an APC device.\n"); return false; } /* Open the device with libusb */ _fd = usb_open(dev); if (!_fd) { Dmsg(100, "Unable to open device.\n"); return false; } #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP /* * Attempt to detach the kernel driver so we can drive * this device from userspace. Don't worry if this fails; * that just means the driver was already detached. */ usb_detach_kernel_driver_np(_fd, 0); #endif /* Check device serial number, if user specified one */ if (serno && serno[0] != '\0') { /* Fetch serial number from device */ const char *tmpser; if (dev->descriptor.iSerialNumber == 0 || (tmpser = GetString(dev->descriptor.iSerialNumber)) == NULL) { usb_close(_fd); _fd = NULL; Dmsg(100, "Device does not report serial number.\n"); return false; } /* Remove leading/trailing whitespace */ astring serial(tmpser); serial.trim(); /* Check against user specification, ignoring case */ Dmsg(100, "device='%s', user='%s'\n", serial.str(), serno); if (strcasecmp(serial, serno)) { usb_close(_fd); _fd = NULL; return false; } } /* Choose config #1 */ rc = usb_set_configuration(_fd, 1); if (rc) { usb_close(_fd); _fd = NULL; Dmsg(100, "Unable to set configuration (%d) %s.\n", rc, usb_strerror()); return false; } /* Claim the interface */ rc = usb_claim_interface(_fd, 0); if (rc) { usb_close(_fd); _fd = NULL; Dmsg(100, "Unable to claim interface (%d) %s.\n", rc, usb_strerror()); return false; } /* Fetch the report descritor */ rdesc = FetchReportDescr(&rdesclen); if (!rdesc) { Dmsg(100, "Unable to fetch report descriptor.\n"); goto error_out; } /* Initialize hid parser with this descriptor */ _rdesc = hid_use_report_desc(rdesc, rdesclen); free(rdesc); if (!_rdesc) { Dmsg(100, "Unable to init parser with report descriptor.\n"); goto error_out; } /* Does this device have an UPS application collection? */ if (!LocateItem( UPS_USAGE, /* Match usage code */ -1, /* Don't care about application */ -1, /* Don't care about physical usage */ -1, /* Don't care about logical */ HID_KIND_COLLECTION, /* Match collection type */ NULL)) { hid_dispose_report_desc(_rdesc); Dmsg(100, "Device does not have an UPS application collection.\n"); goto error_out; } return true; error_out: usb_release_interface(_fd, 0); usb_close(_fd); _fd = NULL; return false; } /* * Fetch a string descriptor from the device given an _fd for the * device's control endpoint and the string index. Returns a pointer * to a static buffer containing the NUL-terminated string or NULL * on failure. */ const char *HidUps::GetString(int index) { int rc; static char string[128]; rc = usb_get_string_simple(_fd, index, string, sizeof(string)); if (rc <= 0) { Dmsg(100, "Error fetching string descriptor: (%d) %s\n", rc, strerror(-rc)); return NULL; } Dmsg(200, "Got string of length=%d\n", rc); return string; } /* Fetch a descriptor from an interface (as opposed to from the device) */ int HidUps::GetIntfDescr( unsigned char type, unsigned char index, void *buf, int size) { memset(buf, 0, size); return usb_control_msg(_fd, USB_ENDPOINT_IN | USB_RECIP_INTERFACE, USB_REQ_GET_DESCRIPTOR, (type << 8) + index, 0, (char*)buf, size, 1000); } /* * Fetch the report descriptor from the device given an _fd for the * device's control endpoint. Descriptor length is written to the * rlen out paramter and a pointer to a malloc'ed buffer containing * the descriptor is returned. Returns NULL on failure. */ unsigned char *HidUps::FetchReportDescr(int *rlen) { unsigned char *ptr; int rdesclen; ptr = (unsigned char*)malloc(MAX_SANE_DESCRIPTOR_LEN); rdesclen = GetIntfDescr(USB_DT_REPORT, 0, ptr, MAX_SANE_DESCRIPTOR_LEN); if (rdesclen <= 0) { Dmsg(100, "Unable to get REPORT descriptor (%d).\n", rdesclen); free(ptr); return NULL; } Dmsg(300, "Report descriptor:\n"); hex_dump(300, ptr, rdesclen); *rlen = rdesclen; return ptr; } /* Push a value onto the collection stack */ #define PUSH_COLLECTION(c, v) \ do \ { \ if (c##_idx= 0) \ c##_idx--; \ } while(0) /* Get the topmost item on the stack */ #define TOP_COLLECTION(c) \ ((c##_idx == -1) ? -1 : c##_stack[c##_idx]) /* Collection types */ #define HIDCOL_PHYSICAL 0 #define HIDCOL_APPLICATION 1 #define HIDCOL_LOGICAL 2 #define MAX_COLLECTION_NESTING 10 /* For pretty printing... */ #define KIND_TO_CHAR(x) \ ((x) == hid_input) ? 'I' : \ ((x) == hid_output) ? 'O' : \ ((x) == hid_feature) ? 'F' : \ ((x) == hid_collection) ? 'C' : \ ((x) == hid_endcollection) ? 'E' : '?' #define COLLECTION_TO_CHAR(x) \ ((x) == 0) ? 'P' : /* Physical */ \ ((x) == 1) ? 'A' : /* Application */ \ ((x) == 2) ? 'L' : /* Logical */ \ ((x) == 3) ? 'R' : /* Report */ \ ((x) == 4) ? 'N' : /* Named Array */ \ ((x) == 5) ? 'S' : /* Usage Switch */ \ ((x) == 6) ? 'M' : '?' /* Usage Modifier */ /* * Locate an item matching the given parameters. If found, the * item is copied to the supplied buffer. Returns true on success, * false on failure. Any of usage, app, phys, logical, and kind * may be set to -1 for "don't care". */ int HidUps::LocateItem(int usage, int app, int phys, int logical, int kind, hid_item_t *outitem) { int rc; hid_data_t cookie; hid_item_t item; int phys_stack[MAX_COLLECTION_NESTING]; int app_stack[MAX_COLLECTION_NESTING]; int logical_stack[MAX_COLLECTION_NESTING]; int phys_idx = -1, app_idx = -1, logical_idx = -1; cookie = hid_start_parse(_rdesc, HID_KIND_ALL, -1); if (!cookie) { Dmsg(100, "Unable to start hid parser\n"); return 0; } while ((rc = hid_get_item(cookie, &item)) > 0) { if (item.kind == hid_collection) { if (item.collection == HIDCOL_PHYSICAL) PUSH_COLLECTION(phys, item.usage); else if (item.collection == HIDCOL_LOGICAL) PUSH_COLLECTION(logical, item.usage); else if (item.collection == HIDCOL_APPLICATION) PUSH_COLLECTION(app, item.usage); } if (usage != -1 && (unsigned int)usage != item.usage) goto next; if (app != -1 && app != TOP_COLLECTION(app)) goto next; if (phys != -1 && phys != TOP_COLLECTION(phys)) goto next; if (logical != -1 && logical != TOP_COLLECTION(logical)) goto next; if (kind != -1 && ((1 << item.kind) & kind) == 0) goto next; if (outitem) memcpy(outitem, &item, sizeof(item)); hid_end_parse(cookie); return 1; next: if (item.kind == hid_endcollection) { if (item.collection == HIDCOL_PHYSICAL) POP_COLLECTION(phys); else if (item.collection == HIDCOL_LOGICAL) POP_COLLECTION(logical); else if (item.collection == HIDCOL_APPLICATION) POP_COLLECTION(app); } } hid_end_parse(cookie); return 0; } #define USB_REQ_GET_REPORT 0x01 #define USB_REQ_SET_REPORT 0x09 /* * Fetch a report from a device given an _fd for the device's control * endpoint, the populated item structure describing the report, a * data buffer in which to store the result, and the report length. * Returns actual report length (in bytes) on success and -1 on failure. */ int HidUps::GetReport(hid_item_t *item, unsigned char *data, int len) { int actlen; Dmsg(200, "get_report: id=0x%02x, kind=%d, length=%d pos=%d\n", item->report_ID, item->kind, len, item->pos); actlen = usb_control_msg(_fd, USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, USB_REQ_GET_REPORT, ((item->kind + 1) << 8) | item->report_ID, 0, (char*)data, len, 1000); if (actlen <= 0) { Dmsg(100, "Error getting report: (%d) %s\n", actlen, strerror(-actlen)); return -1; } hex_dump(300, data, actlen); return actlen; } /* * Send a report to the device given an _fd for the device's control * endpoint, the populated item structure, the data to send, and the * report length. Returns true on success, false on failure. */ int HidUps::SetReport(hid_item_t *item, unsigned char *data, int len) { int actlen; Dmsg(200, "set_report: id=0x%02x, kind=%d, length=%d pos=%d\n", item->report_ID, item->kind, len, item->pos); hex_dump(300, data, len); actlen = usb_control_msg(_fd, USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, USB_REQ_SET_REPORT, ((item->kind + 1) << 8) | item->report_ID, 0, (char*)data, len, 1000); if (actlen != len) { Dmsg(100, "Error setting report: (%d) %s\n", actlen, strerror(-actlen)); return 0; } return 1; } apcupsd-3.14.14/src/libusbhid/Makefile000066400000000000000000000003041274230402600175140ustar00rootroot00000000000000topdir:=../.. include $(topdir)/autoconf/targets.mak SRCS = parse.c data.c descr.c HidUps.cpp all-targets: libusbhid.a libusbhid.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/libusbhid/data.c000066400000000000000000000052531274230402600171410ustar00rootroot00000000000000/* $NetBSD: data.c,v 1.8 2000/04/02 11:10:53 augustss Exp $ */ /* * Copyright (c) 1999 Lennart Augustsson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include "usbhid.h" int hid_get_data(const void *p, const hid_item_t *h) { const unsigned char *buf; unsigned int hpos; unsigned int hsize; int data; int i, end, offs; buf = (const unsigned char *)p; hpos = h->pos; /* bit position of data */ hsize = h->report_size; /* bit length of data */ if (hsize == 0) return (0); offs = hpos / 8; end = (hpos + hsize) / 8 - offs; data = 0; for (i = 0; i <= end; i++) data |= buf[offs + i] << (i*8); data >>= hpos % 8; data &= (1ULL << hsize) - 1; if (h->logical_minimum < 0) { /* Need to sign extend */ hsize = sizeof data * 8 - hsize; data = (data << hsize) >> hsize; } return (data); } void hid_set_data(void *p, const hid_item_t *h, int data) { unsigned char *buf; unsigned int hpos; unsigned int hsize; int i, end, offs, mask; buf = (unsigned char *)p; hpos = h->pos; /* bit position of data */ hsize = h->report_size; /* bit length of data */ if (hsize != 32) { mask = (1 << hsize) - 1; data &= mask; } else mask = ~0; data <<= (hpos % 8); mask <<= (hpos % 8); mask = ~mask; offs = hpos / 8; end = (hpos + hsize) / 8 - offs; for (i = 0; i <= end; i++) buf[offs + i] = (buf[offs + i] & (mask >> (i*8))) | ((data >> (i*8)) & 0xff); } apcupsd-3.14.14/src/libusbhid/descr.c000066400000000000000000000036701274230402600173310ustar00rootroot00000000000000/* $NetBSD: descr.c,v 1.9 2000/09/24 02:13:24 augustss Exp $ */ /* * Copyright (c) 1999 Lennart Augustsson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "usbhid.h" #include "usbvar.h" report_desc_t hid_use_report_desc(unsigned char *data, unsigned int size) { report_desc_t r; r = (report_desc_t)malloc(sizeof(*r) + size); if (r == 0) { errno = ENOMEM; return (NULL); } r->size = size; memcpy(r->data, data, size); return (r); } void hid_dispose_report_desc(report_desc_t r) { free(r); } apcupsd-3.14.14/src/libusbhid/parse.c000066400000000000000000000221501274230402600173350ustar00rootroot00000000000000/* $NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $ */ /* * Copyright (c) 1999, 2001 Lennart Augustsson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include "usbhid.h" #include "usbvar.h" #include "usbcompat.h" #define MAXUSAGE 100 struct hid_data { unsigned char *start; unsigned char *end; unsigned char *p; hid_item_t cur; unsigned int usages[MAXUSAGE]; int nusage; int minset; int logminsize; int multi; int multimax; int kindset; int reportid; /* * The start of collection item has no report ID set, so save * it until we know the ID. */ hid_item_t savedcoll; unsigned char hassavedcoll; /* * Absolute data position (bits) for input/output/feature. * Assumes that hid_input, hid_output and hid_feature have * values 0, 1 and 2. */ unsigned int kindpos[3]; }; static int min(int x, int y) { return x < y ? x : y; } static int hid_get_item_raw(hid_data_t s, hid_item_t *h); static void hid_clear_local(hid_item_t *c) { c->usage = 0; c->usage_minimum = 0; c->usage_maximum = 0; c->designator_index = 0; c->designator_minimum = 0; c->designator_maximum = 0; c->string_index = 0; c->string_minimum = 0; c->string_maximum = 0; c->set_delimiter = 0; } hid_data_t hid_start_parse(report_desc_t d, int kindset, int id) { struct hid_data *s; s = (struct hid_data *)malloc(sizeof *s); memset(s, 0, sizeof *s); s->start = s->p = d->data; s->end = d->data + d->size; s->kindset = kindset; s->reportid = id; s->hassavedcoll = 0; return (s); } void hid_end_parse(hid_data_t s) { while (s->cur.next) { hid_item_t *hi = s->cur.next->next; free(s->cur.next); s->cur.next = hi; } free(s); } int hid_get_item(hid_data_t s, hid_item_t *h) { int r; for (;;) { r = hid_get_item_raw(s, h); if (r <= 0) break; if (h->report_ID == s->reportid || s->reportid == -1) break; } return (r); } #define REPORT_SAVED_COLL \ do { \ if (s->hassavedcoll) { \ *h = s->savedcoll; \ h->report_ID = c->report_ID; \ s->hassavedcoll = 0; \ return (1); \ } \ } while(/*LINTED*/ 0) static int hid_get_item_raw(hid_data_t s, hid_item_t *h) { hid_item_t *c; unsigned int bTag = 0, bType = 0, bSize; unsigned char *data; unsigned int dval; unsigned char *p; hid_item_t *hi; hid_item_t nc; unsigned int i; hid_kind_t retkind; c = &s->cur; top: if (s->multimax) { REPORT_SAVED_COLL; if (c->logical_minimum >= c->logical_maximum) { if (s->logminsize == 1) c->logical_minimum =(signed char)c->logical_minimum; else if (s->logminsize == 2) c->logical_minimum =(signed short)c->logical_minimum; } if (s->multi < s->multimax) { c->usage = s->usages[min(s->multi, s->nusage-1)]; s->multi++; *h = *c; /* * 'multimax' is only non-zero if the current * item kind is input/output/feature */ h->pos = s->kindpos[c->kind]; s->kindpos[c->kind] += c->report_size; h->next = 0; return (1); } else { c->report_count = s->multimax; s->multimax = 0; s->nusage = 0; hid_clear_local(c); } } for (;;) { p = s->p; if (p >= s->end) return (0); bSize = *p++; if (bSize == 0xfe) { /* long item */ bSize = *p++; bSize |= *p++ << 8; bTag = *p++; data = p; p += bSize; } else { /* short item */ bTag = bSize >> 4; bType = (bSize >> 2) & 3; bSize &= 3; if (bSize == 3) bSize = 4; data = p; p += bSize; } s->p = p; /* * The spec is unclear if the data is signed or unsigned. */ switch(bSize) { case 0: dval = 0; break; case 1: dval = *data++; break; case 2: dval = *data++; dval |= *data++ << 8; break; case 4: dval = *data++; dval |= *data++ << 8; dval |= *data++ << 16; dval |= *data++ << 24; break; default: return (-1); } switch (bType) { case 0: /* Main */ switch (bTag) { case 8: /* Input */ retkind = hid_input; ret: if (!(s->kindset & (1 << retkind))) { /* Drop the items of this kind */ s->nusage = 0; continue; } c->kind = retkind; c->flags = dval; if (c->flags & HIO_VARIABLE) { s->multimax = c->report_count; s->multi = 0; c->report_count = 1; if (s->minset) { for (i = c->usage_minimum; i <= c->usage_maximum; i++) { s->usages[s->nusage] = i; if (s->nusage < MAXUSAGE-1) s->nusage++; } c->usage_minimum = 0; c->usage_maximum = 0; s->minset = 0; } goto top; } else { if (s->minset) c->usage = c->usage_minimum; *h = *c; h->next = 0; h->pos = s->kindpos[c->kind]; s->kindpos[c->kind] += c->report_size * c->report_count; hid_clear_local(c); s->minset = 0; return (1); } case 9: /* Output */ retkind = hid_output; goto ret; case 10: /* Collection */ c->kind = hid_collection; c->collection = dval; c->collevel++; nc = *c; hid_clear_local(c); /*c->report_ID = NO_REPORT_ID;*/ s->nusage = 0; if (s->hassavedcoll) { *h = s->savedcoll; h->report_ID = nc.report_ID; s->savedcoll = nc; return (1); } else { s->hassavedcoll = 1; s->savedcoll = nc; } break; case 11: /* Feature */ retkind = hid_feature; goto ret; case 12: /* End collection */ REPORT_SAVED_COLL; c->kind = hid_endcollection; c->collevel--; *h = *c; /*hid_clear_local(c);*/ s->nusage = 0; return (1); default: return (-2); } break; case 1: /* Global */ switch (bTag) { case 0: c->_usage_page = dval << 16; break; case 1: c->logical_minimum = dval; s->logminsize = bSize; break; case 2: c->logical_maximum = dval; break; case 3: c->physical_minimum = dval; break; case 4: c->physical_maximum = dval; break; case 5: c->unit_exponent = dval; break; case 6: c->unit = dval; break; case 7: c->report_size = dval; break; case 8: c->report_ID = dval; s->kindpos[hid_input] = s->kindpos[hid_output] = s->kindpos[hid_feature] = 0; break; case 9: c->report_count = dval; break; case 10: /* Push */ hi = (hid_item_t *)malloc(sizeof *hi); *hi = s->cur; c->next = hi; break; case 11: /* Pop */ hi = c->next; s->cur = *hi; free(hi); break; default: return (-3); } break; case 2: /* Local */ switch (bTag) { case 0: c->usage = c->_usage_page | dval; if (s->nusage < MAXUSAGE) s->usages[s->nusage++] = c->usage; /* else XXX */ break; case 1: s->minset = 1; c->usage_minimum = c->_usage_page | dval; break; case 2: c->usage_maximum = c->_usage_page | dval; break; case 3: c->designator_index = dval; break; case 4: c->designator_minimum = dval; break; case 5: c->designator_maximum = dval; break; case 7: c->string_index = dval; break; case 8: c->string_minimum = dval; break; case 9: c->string_maximum = dval; break; case 10: c->set_delimiter = dval; break; default: return (-4); } break; default: return (-5); } } } int hid_report_size(report_desc_t r, enum hid_kind k, int id) { struct hid_data *d; hid_item_t h; int size; memset(&h, 0, sizeof h); size = 0; for (d = hid_start_parse(r, 1<kindpos[k]; } } hid_end_parse(d); return ((size + 7) / 8); } int hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k, hid_item_t *h, int id) { hid_data_t d; for (d = hid_start_parse(desc, 1<kind == k && !(h->flags & HIO_CONST) && h->usage == u) { hid_end_parse(d); return (1); } } hid_end_parse(d); h->report_size = 0; return (0); } apcupsd-3.14.14/src/libusbhid/usage.c000066400000000000000000000132151274230402600173310ustar00rootroot00000000000000/* $NetBSD: usage.c,v 1.8 2000/10/10 19:23:58 is Exp $ */ /* * Copyright (c) 1999 Lennart Augustsson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "apc.h" #include "usbhid.h" #define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages" struct usage_in_page { const char *name; int usage; }; static struct usage_page { const char *name; int usage; struct usage_in_page *page_contents; int pagesize, pagesizemax; } *pages; static int npages, npagesmax; #ifdef DEBUG void dump_hid_table(void) { int i, j; for (i = 0; i < npages; i++) { printf("%d\t%s\n", pages[i].usage, pages[i].name); for (j = 0; j < pages[i].pagesize; j++) { printf("\t%d\t%s\n", pages[i].page_contents[j].usage, pages[i].page_contents[j].name); } } } #endif void hid_init(const char *hidname) { FILE *f; char line[100], name[100], *p, *n; int no; int lineno; struct usage_page *curpage = 0; if (hidname == 0) hidname = _PATH_HIDTABLE; f = fopen(hidname, "r"); if (f == NULL) err(1, "%s", hidname); for (lineno = 1; ; lineno++) { if (fgets(line, sizeof line, f) == NULL) break; if (line[0] == '#') continue; for (p = line; *p && isspace(*p); p++) ; if (!*p) continue; if (sscanf(line, " * %[^\n]", name) == 1) no = -1; else if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 && sscanf(line, " %d %[^\n]", &no, name) != 2) errx(1, "file %s, line %d, syntax error", hidname, lineno); for (p = name; *p; p++) if (isspace(*p) || *p == '.') *p = '_'; n = strdup(name); if (!n) err(1, "strdup"); if (isspace(line[0])) { if (!curpage) errx(1, "file %s, line %d, syntax error", hidname, lineno); if (curpage->pagesize >= curpage->pagesizemax) { curpage->pagesizemax += 10; curpage->page_contents = (usage_in_page *) realloc(curpage->page_contents, curpage->pagesizemax * sizeof (struct usage_in_page)); if (!curpage->page_contents) err(1, "realloc"); } curpage->page_contents[curpage->pagesize].name = n; curpage->page_contents[curpage->pagesize].usage = no; curpage->pagesize++; } else { if (npages >= npagesmax) { if (pages == 0) { npagesmax = 5; pages = (usage_page *)malloc(npagesmax * sizeof (struct usage_page)); } else { npagesmax += 5; pages = (usage_page *)realloc(pages, npagesmax * sizeof (struct usage_page)); } if (!pages) err(1, "alloc"); } curpage = &pages[npages++]; curpage->name = n; curpage->usage = no; curpage->pagesize = 0; curpage->pagesizemax = 10; curpage->page_contents = (usage_in_page *) malloc(curpage->pagesizemax * sizeof (struct usage_in_page)); if (!curpage->page_contents) err(1, "malloc"); } } fclose(f); #ifdef DEBUG dump_hid_table(); #endif } const char * hid_usage_page(int i) { static char b[10]; int k; if (!pages) errx(1, "no hid table"); for (k = 0; k < npages; k++) if (pages[k].usage == i) return pages[k].name; asnprintf(b, sizeof(b), "0x%04x", i); return b; } #define fmtcheck(x,y) (x) const char * hid_usage_in_page(unsigned int u) { int page = HID_PAGE(u); int i = HID_USAGE(u); static char b[100]; int j, k, us; for (k = 0; k < npages; k++) if (pages[k].usage == page) break; if (k >= npages) goto bad; for (j = 0; j < pages[k].pagesize; j++) { us = pages[k].page_contents[j].usage; if (us == -1) { asnprintf(b, sizeof(b), fmtcheck(pages[k].page_contents[j].name, "%d"), i); return b; } if (us == i) return pages[k].page_contents[j].name; } bad: asnprintf(b, sizeof(b), "0x%04x", i); return b; } int hid_parse_usage_page(const char *name) { int k; if (!pages) errx(1, "no hid table"); for (k = 0; k < npages; k++) if (strcmp(pages[k].name, name) == 0) return pages[k].usage; return -1; } /* XXX handle hex */ int hid_parse_usage_in_page(const char *name) { const char *sep; int k, j; unsigned int l; sep = strchr(name, ':'); if (sep == NULL) return -1; l = sep - name; for (k = 0; k < npages; k++) if (strncmp(pages[k].name, name, l) == 0) goto found; return -1; found: sep++; for (j = 0; j < pages[k].pagesize; j++) if (strcmp(pages[k].page_contents[j].name, sep) == 0) return (pages[k].usage << 16) | pages[k].page_contents[j].usage; return (-1); } apcupsd-3.14.14/src/libusbhid/usbcompat.h000066400000000000000000000027541274230402600202350ustar00rootroot00000000000000/* * usbcompat.h * * Compatibility definitions from FreeBSD, needed to make libusbhid * compile on other platforms. */ #ifndef _USBCOMPAT_H #define _USBCOMPAT_H /* From /usr/include/dev/usb/usb.h */ /* * The USB records contain some unaligned little-endian word * components. The U[SG]ETW macros take care of both the alignment * and endian problem and should always be used to access non-byte * values. */ typedef unsigned char uByte; typedef unsigned char uWord[2]; typedef unsigned char uDWord[4]; #define USETW2(w,h,l) ((w)[0] = (unsigned char)(l), (w)[1] = (unsigned char)(h)) #define UGETW(w) ((w)[0] | ((w)[1] << 8)) #define USETW(w,v) ((w)[0] = (unsigned char)(v), (w)[1] = (unsigned char)((v) >> 8)) #define UGETDW(w) ((w)[0] | ((w)[1] << 8) | ((w)[2] << 16) | ((w)[3] << 24)) #define USETDW(w,v) ((w)[0] = (unsigned char)(v), \ (w)[1] = (unsigned char)((v) >> 8), \ (w)[2] = (unsigned char)((v) >> 16), \ (w)[3] = (unsigned char)((v) >> 24)) struct usb_ctl_report_desc { int ucrd_size; unsigned char ucrd_data[1024]; /* filled data size will vary */ }; /* From /usr/include/dev/usb/libusb.h */ /* Bits in the input/output/feature items */ #define HIO_CONST 0x001 #define HIO_VARIABLE 0x002 #define HIO_RELATIVE 0x004 #define HIO_WRAP 0x008 #define HIO_NONLINEAR 0x010 #define HIO_NOPREF 0x020 #define HIO_NULLSTATE 0x040 #define HIO_VOLATILE 0x080 #define HIO_BUFBYTES 0x100 #endif apcupsd-3.14.14/src/libusbhid/usbhid.3000066400000000000000000000151731274230402600174300ustar00rootroot00000000000000.\" $NetBSD: usb.3,v 1.13 2000/09/24 02:17:52 augustss Exp $ .\" .\" Copyright (c) 1999, 2001 Lennart Augustsson .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD: src/lib/libusbhid/usbhid.3,v 1.16 2003/12/21 14:30:23 rushani Exp $ .\" .Dd December 29, 2001 .Dt USBHID 3 .Os .Sh NAME .Nm usbhid , .Nm hid_get_report_desc , .Nm hid_use_report_desc , .Nm hid_dispose_report_desc , .Nm hid_start_parse , .Nm hid_end_parse , .Nm hid_get_item , .Nm hid_report_size , .Nm hid_locate , .Nm hid_usage_page , .Nm hid_usage_in_page , .Nm hid_init , .Nm hid_get_data , .Nm hid_set_data .Nd USB HID access routines .Sh LIBRARY .Lb libusbhid .Sh SYNOPSIS .In usbhid.h .Ft report_desc_t .Fn hid_get_report_desc "int file" .Ft report_desc_t .Fn hid_use_report_desc "unsigned char *data" "unsigned int size" .Ft void .Fn hid_dispose_report_desc "report_desc_t d" .Ft hid_data_t .Fn hid_start_parse "report_desc_t d" "int kindset" "int id" .Ft void .Fn hid_end_parse "hid_data_t s" .Ft int .Fn hid_get_item "hid_data_t s" "hid_item_t *h" .Ft int .Fn hid_report_size "report_desc_t d" "hid_kind_t k" "int id" .Ft int .Fn hid_locate "report_desc_t d" "u_int usage" "hid_kind_t k" "hid_item_t *h" "int id" .Ft "char *" .Fn hid_usage_page "int i" .Ft "char *" .Fn hid_usage_in_page "u_int u" .Ft int .Fn hid_parse_usage_page "const char *" .Ft "char *" .Fn hid_parse_usage_in_page "const char *" .Ft void .Fn hid_init "char *file" .Ft int .Fn hid_get_data "void *data" "hid_item_t *h" .Ft void .Fn hid_set_data "void *data" "hid_item_t *h" "u_int data" .Sh DESCRIPTION The .Nm library provides routines to extract data from USB Human Interface Devices. .Ss Introduction USB HID devices send and receive data layed out in a device dependent way. The .Nm library contains routines to extract the .Em "report descriptor" which contains the data layout information and then use this information. .Pp The routines can be divided into four parts: extraction of the descriptor, parsing of the descriptor, translating to/from symbolic names, and data manipulation. .Ss Descriptor Functions A report descriptor can be obtained by calling .Fn hid_get_report_desc with a file descriptor obtained by opening a .Xr uhid 4 device. Alternatively a data buffer containing the report descriptor can be passed into .Fn hid_use_report_desc . The data is copied into an internal structure. When the report descriptor is no longer needed it should be freed by calling .Fn hid_dispose_report_desc . The type .Vt report_desc_t is opaque and should be used when calling the parsing functions. If .Fn hid_dispose_report_desc fails it will return .Dv NULL . .Ss Descriptor Parsing Functions To parse the report descriptor the .Fn hid_start_parse function should be called with a report descriptor and a set that describes which items that are interesting. The set is obtained by OR-ing together values .Fa "(1 << k)" where .Fa k is an item of type .Vt hid_kind_t . The report ID (if present) is given by .Fa id . The function returns .Dv NULL if the initialization fails, otherwise an opaque value to be used in subsequent calls. After parsing the .Fn hid_end_parse function should be called to free internal data structures. .Pp To iterate through all the items in the report descriptor .Fn hid_get_item should be called while it returns a value greater than 0. When the report descriptor ends it will returns 0; a syntax error within the report descriptor will cause a return value less than 0. The struct pointed to by .Fa h will be filled with the relevant data for the item. The definition of .Vt hid_item_t can be found in .In usbhid.h and the meaning of the components in the USB HID documentation. .Pp Data should be read/written to the device in the size of the report. The size of a report (of a certain kind) can be computed by the .Fn hid_report_size function. If the report is prefixed by an ID byte it is given by .Fa id . .Pp To locate a single item the .Fn hid_locate function can be used. It should be given the usage code of the item and its kind and it will fill the item and return non-zero if the item was found. .Ss Name Translation Functions The function .Fn hid_usage_page will return the symbolic name of a usage page, and the function .Fn hid_usage_in_page will return the symbolic name of the usage within the page. Both these functions may return a pointer to static data. .Pp The functions .Fn hid_parse_usage_page and .Fn hid_parse_usage_in_page are the inverses of .Fn hid_usage_page and .Fn hid_usage_in_page . They take a usage string and return the number of the usage, or \-1 if it cannot be found. .Pp Before any of these functions can be called the usage table must be parsed, this is done by calling .Fn hid_init with the name of the table. Passing .Dv NULL to this function will cause it to use the default table. .Ss Data Extraction Functions Given the data obtained from a HID device and an item in the report descriptor the .Fn hid_get_data function extracts the value of the item. Conversely .Fn hid_set_data can be used to put data into a report (which must be zeroed first). .Sh EXAMPLES Not yet. .Sh FILES .Bl -tag -width ".Pa /usr/share/misc/usb_hid_usages" .It Pa /usr/share/misc/usb_hid_usages The default HID usage table. .El .Sh BUGS This man page is woefully incomplete. .Sh SEE ALSO The .Tn USB specifications can be found at .Pa http://www.usb.org/developers/docs/ . .Pp .Xr uhid 4 , .Xr usb 4 .Sh HISTORY The .Nm library first appeared in .Nx 1.5 . apcupsd-3.14.14/src/libusbhid/usbhid.h000066400000000000000000000066441274230402600175200ustar00rootroot00000000000000/* $NetBSD: usb.h,v 1.8 2000/08/13 22:22:02 augustss Exp $ */ /* * Copyright (c) 1999 Lennart Augustsson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/lib/libusbhid/usbhid.h,v 1.11 2004/06/03 15:04:24 des Exp $ * */ typedef struct report_desc *report_desc_t; typedef struct hid_data *hid_data_t; typedef enum hid_kind { hid_input = 0, hid_output = 1, hid_feature = 2, hid_collection, hid_endcollection } hid_kind_t; typedef struct hid_item { /* Global */ unsigned int _usage_page; int logical_minimum; int logical_maximum; int physical_minimum; int physical_maximum; int unit_exponent; int unit; int report_size; int report_ID; #define NO_REPORT_ID 0 int report_count; /* Local */ unsigned int usage; unsigned int usage_minimum; unsigned int usage_maximum; int designator_index; int designator_minimum; int designator_maximum; int string_index; int string_minimum; int string_maximum; int set_delimiter; /* Misc */ int collection; int collevel; enum hid_kind kind; unsigned int flags; /* Absolute data position (bits) */ unsigned int pos; /* */ struct hid_item *next; } hid_item_t; #define HID_PAGE(u) (((u) >> 16) & 0xffff) #define HID_USAGE(u) ((u) & 0xffff) /* Obtaining a report descriptor, descr.c: */ report_desc_t hid_get_report_desc(int file); report_desc_t hid_use_report_desc(unsigned char *data, unsigned int size); void hid_dispose_report_desc(report_desc_t); /* Parsing of a HID report descriptor, parse.c: */ hid_data_t hid_start_parse(report_desc_t d, int kindset, int id); void hid_end_parse(hid_data_t s); int hid_get_item(hid_data_t s, hid_item_t *h); int hid_report_size(report_desc_t d, enum hid_kind k, int id); int hid_locate(report_desc_t d, unsigned int usage, enum hid_kind k, hid_item_t *h, int id); /* Conversion to/from usage names, usage.c: */ const char *hid_usage_page(int i); const char *hid_usage_in_page(unsigned int u); void hid_init(const char *file); int hid_parse_usage_in_page(const char *name); int hid_parse_usage_page(const char *name); /* Extracting/insertion of data, data.c: */ int hid_get_data(const void *p, const hid_item_t *h); void hid_set_data(void *p, const hid_item_t *h, int data); apcupsd-3.14.14/src/libusbhid/usbvar.h000066400000000000000000000030771274230402600175410ustar00rootroot00000000000000/* $NetBSD: usbvar.h,v 1.2 1999/05/11 21:15:46 augustss Exp $ */ /* * Copyright (c) 1999 Lennart Augustsson * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD: src/lib/libusbhid/usbvar.h,v 1.2 2002/03/27 16:07:18 joe Exp $ * */ struct report_desc { unsigned int size; unsigned char data[1]; }; apcupsd-3.14.14/src/options.c000066400000000000000000000160571274230402600157620ustar00rootroot00000000000000/* * options.c * * Command line options parsing routine for apcupsd. */ /* * Copyright (C) 2000-2004 Kern Sibbald * Copyright (C) 1999-2000 Riccardo Facchetti * Copyright (C) 1996-99 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" static const char *const shortoptions = "bhRtTVf:d:pP:ko"; enum { OPT_NOARG, OPT_HELP, OPT_VERSION, OPT_CFGFILE, OPT_DEBUG, OPT_HIBERNATE, OPT_POWEROFF, OPT_TERMONPWRFAIL, OPT_KILLONPWRFAIL, OPT_PIDFILE }; static const struct option longoptions[] = { {"help", no_argument, NULL, OPT_HELP}, {"version", no_argument, NULL, OPT_VERSION}, {"config-file", required_argument, NULL, OPT_CFGFILE}, {"debug", required_argument, NULL, OPT_DEBUG}, {"killpower", no_argument, NULL, OPT_HIBERNATE}, {"hibernate", no_argument, NULL, OPT_HIBERNATE}, {"power-off", no_argument, NULL, OPT_POWEROFF}, {"term-on-powerfail", no_argument, NULL, OPT_TERMONPWRFAIL}, {"kill-on-powerfail", no_argument, NULL, OPT_KILLONPWRFAIL}, {"pid-file", required_argument, NULL, OPT_PIDFILE}, {0, no_argument, NULL, OPT_NOARG} }; /* Globals used by command line options. */ int show_version = FALSE; char *cfgfile = NULL; int terminate_on_powerfail = FALSE; int kill_on_powerfail = FALSE; int dumb_mode_test = FALSE; /* for testing dumb mode */ int go_background = TRUE; extern char *pidfile; extern bool trace; static void print_usage(char *argv[]) { printf("usage: apcupsd [options]\n" " Options are as follows:\n" " -b, don't go into background\n" " -d, --debug set debug level (>0)\n" " -f, --config-file load specified config file\n" " -k, --killpower, --hibernate put UPS into hibernation mode [*]\n" " -o, --power-off turn off UPS completely [*]\n" " -P, --pid-file specify name of PID file\n" " -p, --kill-on-powerfail hibernate UPS on powerfail\n" " -R, put SmartUPS into dumb mode\n" " -t, --term-on-powerfail terminate when battery power fails\n" " -T send debug to ./apcupsd.trace\n" " -V, --version display version info\n" " -h, --help display this help\n" "\n" " [*] Only one parameter of this kind and apcupsd must not already be running.\n" "\n" "Copyright (C) 2004-2009 Adam Kropelin\n" "Copyright (C) 1999-2005 Kern Sibbald\n" "Copyright (C) 1996-1999 Andre Hedrick\n" "Copyright (C) 1999-2001 Riccardo Facchetti\n" "apcupsd is free software and comes with ABSOLUTELY NO WARRANTY\n" "under the terms of the GNU General Public License\n" "\n" "Report bugs to apcupsd Support Center:\n" " apcupsd-users@lists.sourceforge.net\n"); } int parse_options(int argc, char *argv[]) { int options = 0; int oneshot = FALSE; int option_index; int errflag = 0; int c; while (!errflag && (c = getopt_long(argc, argv, shortoptions, longoptions, &option_index)) != -1) { options++; switch (c) { case 'b': /* do not become daemon */ go_background = FALSE; break; case 'R': dumb_mode_test = TRUE; break; case 'V': case OPT_VERSION: show_version = TRUE; oneshot = TRUE; break; case 'f': case OPT_CFGFILE: if (optarg[0] == '-') { /* Following option: no argument set for -f */ errflag++; break; } /* * The reason for this is that loading a different config file * is not something dangerous when we are doing `oneshot' things * and we may even want to load a different config file during * `oneshot's. */ options--; cfgfile = optarg; break; case 'P': case OPT_PIDFILE: if (optarg[0] == '-') { /* Following option: no argument set for -P */ errflag++; break; } options--; pidfile = optarg; break; case 'd': case OPT_DEBUG: if (optarg[0] == '-') { /* Following option: no argument set for -d */ errflag++; break; } /* * The reason of this, is that enabling debugging is * not something dangerous when we are doing `oneshot's */ options--; debug_level = atoi(optarg); break; case 'p': case OPT_KILLONPWRFAIL: kill_on_powerfail = TRUE; break; case 't': case OPT_TERMONPWRFAIL: terminate_on_powerfail = TRUE; break; case 'T': trace = true; break; case 'k': case OPT_HIBERNATE: hibernate_ups = TRUE; oneshot = TRUE; break; case 'o': case OPT_POWEROFF: shutdown_ups = TRUE; oneshot = TRUE; break; case 'h': case OPT_HELP: default: errflag++; } } /* Win32-specific dynamic path handling... */ #ifdef HAVE_MINGW extern char sbindir[MAXSTRING]; /* Obtain full path to this executable */ DWORD len = GetModuleFileName(NULL, sbindir, sizeof(sbindir)-1); sbindir[len] = '\0'; Dmsg(200, "Exepath: %s\n", sbindir); if (len == 0) { /* Failed to get path, so make an assumption */ asnprintf(sbindir, sizeof(sbindir), "C:\\apcupsd\\bin\\apcupsd.exe"); } /* Strip trailing filename component */ char *ptr = strrchr(sbindir, '\\'); if (ptr) *ptr = '\0'; else sbindir[0] = '\0'; /* * If the user did not provide a -f argument to specify * the location of apcupsd.conf, simulate one relative to current * executable path. */ if (cfgfile == APCCONF) { asnprintf(APCCONF, sizeof(APCCONF), "%s\\..\\etc\\apcupsd%s", sbindir, APCCONF_FILE); } #endif if ((oneshot == TRUE) && options > 1) { fprintf(stderr, "\nError: too many arguments.\n\n"); errflag++; } if (errflag) print_usage(argv); return errflag; } apcupsd-3.14.14/src/reports.c000066400000000000000000000121731274230402600157600ustar00rootroot00000000000000/* * apcreports.c * * Event logging functions. */ /* * Copyright (C) 2000-2004 Kern Sibbald * Copyright (C) 1996-1999 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" static char largebuf[4096]; static int stat_recs; static int logstats = 0; static time_t last_time_status; static time_t last_time_logging; static FILE *statusfile = NULL; /* initial value set to NULL for terminate */ void clear_files(void) { if (statusfile != NULL) { fflush(statusfile); fclose(statusfile); statusfile = NULL; } } static void log_status_open(UPSINFO *ups) { largebuf[0] = 0; stat_recs = 0; rewind(statusfile); logstats = ups->logstats; } #define STAT_REV 1 static int log_status_close(UPSINFO *ups, int fd) { int i; char buf[MAXSTRING]; char *sptr, *eptr; i = strlen(largebuf); if (i > (int)sizeof(largebuf) - 1) { log_event(ups, LOG_ERR, "Status buffer overflow %d bytes\n", i - sizeof(largebuf)); return -1; } asnprintf(buf, sizeof(buf), "APC : %03d,%03d,%04d\n", STAT_REV, stat_recs, i); fputs(buf, statusfile); fputs(largebuf, statusfile); fflush(statusfile); /* * Write out the status log to syslog() one record at a * time. */ if (logstats) { buf[strlen(buf) - 1] = 0; log_event(ups, LOG_NOTICE, buf); sptr = eptr = largebuf; for (; i > 0; i--) { if (*eptr == '\n') { *eptr++ = 0; log_event(ups, LOG_NOTICE, sptr); sptr = eptr; } else { eptr++; } } } return 0; } /* * Log one line of the status file; * also send it to system log */ static void log_status_write(UPSINFO *ups, const char *fmt, ...) { va_list ap; char buf[MAXSTRING]; va_start(ap, fmt); avsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); strncat(largebuf, buf, sizeof(largebuf)-strlen(largebuf)-1); largebuf[sizeof(largebuf) - 1] = 0; stat_recs++; } /* * Log current UPS data * * Format of output for SmartUPS * vmin, vmax, vout, vbat, freq, load%,temp,amb-temp,humid, vline * 223.6,230.1,227.5,27.74,50.00,020.8,034.6,,,229.8 * * currently ambient temp and humidity are not included */ static void log_data(UPSINFO *ups) { const char *ptr; static int toggle = 0; if (ups->datatime == 0) return; switch (ups->mode.type) { case DUMB_UPS: if (!ups->is_onbatt()) { if (!ups->is_replacebatt()) { ptr = "OK"; } else { ptr = "REPLACE"; } log_event(ups, LOG_INFO, "LINEFAIL:OK BATTSTAT:%s", ptr); } else { if (!ups->is_battlow()) ptr = "RUNNING"; else ptr = "FAILING"; log_event(ups, LOG_INFO, "LINEFAIL:DOWN BATTSTAT:%s", ptr); } break; case USB_UPS: case TEST_UPS: case NETWORK_UPS: case APCSMART_UPS: case PCNET_UPS: case SNMPLITE_UPS: toggle = !toggle; /* flip bit */ log_event(ups, LOG_INFO, "%05.1f,%05.1f,%05.1f,%05.2f,%05.2f,%04.1f,%04.1f,%05.1f,%05.1f,%05.1f,%05.1f,%d", ups->LineMin, ups->LineMax, ups->OutputVoltage, ups->BattVoltage, ups->LineFreq, ups->UPSLoad, ups->UPSTemp, ups->ambtemp, ups->humidity, ups->LineVoltage, ups->BattChg, toggle); break; default: break; } return; } void do_reports(UPSINFO *ups) { static int first_time = TRUE; time_t now = time(NULL); int fd; if (first_time) { first_time = FALSE; /* Set up logging and status timers. */ last_time_logging = 0; last_time_status = 0; if (ups->stattime != 0) { if ((fd = open(ups->statfile, O_WRONLY|O_TRUNC|O_CREAT|O_CLOEXEC, 0666)) == -1 || (statusfile = fdopen(fd, "w")) == NULL) { log_event(ups, LOG_ERR, "Cannot open STATUS file %s: %s\n", ups->statfile, strerror(errno)); } } else { unlink(ups->statfile); } } /* Check if it is time to log DATA record */ if ((ups->datatime > 0) && (now - last_time_logging) >= ups->datatime) { last_time_logging = now; log_data(ups); } /* Check if it is time to write STATUS file */ if ((statusfile != NULL) && (now - last_time_status) >= ups->stattime) { last_time_status = now; output_status(ups, 0, log_status_open, log_status_write, log_status_close); } /* Trim the EVENTS file */ trim_eventfile(ups); } apcupsd-3.14.14/src/smtp.c000066400000000000000000000222531274230402600152450ustar00rootroot00000000000000/* * smtp.c * * A simple SMTP mail client for apcupsd. * * Derived from a SMTPclient: * * SMTPclient -- simple SMTP client * Copyright (C) 1997 Ralf S. Engelschall, All Rights Reserved. * rse@engelschall.com * www.engelschall.com */ /* * Copyright (C) 2000-2004 Kern Sibbald and John Walker * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #define APCUPSD #ifdef APCUPSD #include # include "apc.h" # undef main # define my_name_is(x, y, z) # define bstrdup(x) strdup(x) # define Pmsg2 Dmsg # define Pmsg1 Dmsg # define Pmsg0 Dmsg # define MY_NAME "smtp" #else # include "bacula.h" # include "jcr.h" # define MY_NAME "bsmtp" #endif #ifndef MAXSTRING # define MAXSTRING 254 #endif static int s; static char *from_addr = NULL; static char *cc_addr = NULL; static char *subject = NULL; static char *err_addr = NULL; static const char *mailhost = NULL; static char *reply_addr = NULL; static int mailport = 25; static char my_hostname[MAXSTRING]; /* Needed by lib/apcconfig.c */ char argvalue[MAXSTRING]; /* like fgets(3), but for a socket */ static char *sockgets(char *buf, int len, int s) { int i=0; /* Inefficient, but simple */ while (i < len-1) { if (recv(s, buf+i, 1, 0) != 1) break; i++; if (buf[i-1] == '\n') break; } buf[i] = '\0'; return i==0 ? NULL : buf; } /* examine message from server */ static void get_response(void) { char buf[MAXSTRING]; Dmsg(50, "Calling sockgets on read socket.\n"); while (sockgets(buf, sizeof(buf), s)) { buf[strlen(buf) - 1] = 0; Dmsg(10, "%s --> %s\n", mailhost, buf); if (!isdigit((int)buf[0]) || buf[0] > '3') { Pmsg2(0, "Fatal malformed reply from %s: %s\n", mailhost, buf); exit(1); } if (buf[3] != '-') break; } } /* like vfprintf(3), but for a socket */ static void vsockwrite(int s, const char *fmt, va_list ap) { static char temp[MAXSTRING]; avsnprintf(temp, sizeof(temp), fmt, ap); send(s, temp, strlen(temp), 0); } /* like fprintf(3), but for a socket */ static void sockwrite(int s, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vsockwrite(s, fmt, ap); va_end(ap); } /* say something to server and check the response */ static void chat(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vsockwrite(s, fmt, ap); if (debug_level >= 10) { fprintf(stdout, "%s --> ", my_hostname); vfprintf(stdout, fmt, ap); } va_end(ap); if (debug_level >= 10) fflush(stdout); get_response(); } static void usage() { fprintf(stderr, "\n" "Usage: %s [-f from] [-h mailhost] [-s subject] [-c copy] [recepient ...]\n" " -c set the Cc: field\n" " -dnn set debug level to nn\n" " -f set the From: field\n" " -h use mailhost:port as the SMTP server\n" " -s set the Subject: field\n" " -? print this message.\n" "\n", MY_NAME); exit(1); } /* Program to send email */ int main(int argc, char *argv[]) { char buf[MAXSTRING]; struct sockaddr_in sin; struct hostent *hp; int i, ch; struct passwd *pwd; char *cp, *p; time_t now = time(NULL); struct tm tm; my_name_is(argc, argv, "bsmtp"); while ((ch = getopt(argc, argv, "c:d:f:h:r:s:?")) != -1) { switch (ch) { case 'c': Dmsg(20, "cc=%s\n", optarg); cc_addr = optarg; break; case 'd': /* set debug level */ debug_level = atoi(optarg); if (debug_level <= 0) debug_level = 1; Dmsg(20, "Debug level = %d\n", debug_level); break; case 'f': /* from */ from_addr = optarg; break; case 'h': /* smtp host */ Dmsg(20, "host=%s\n", optarg); p = strchr(optarg, ':'); if (p) { *p++ = 0; mailport = atoi(p); } mailhost = optarg; break; case 's': /* subject */ Dmsg(20, "subject=%s\n", optarg); subject = optarg; break; case 'r': /* reply address */ reply_addr = optarg; break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc < 1) { Pmsg0(0, "Fatal error: no recipient given.\n"); usage(); exit(1); } /* Determine SMTP server */ if (mailhost == NULL) { if ((cp = getenv("SMTPSERVER")) != NULL) mailhost = cp; else mailhost = "localhost"; } #ifdef HAVE_MINGW int WSA_Init(void); WSA_Init(); #endif /* * Find out my own host name for HELO; * if possible, get the fully qualified domain name */ if (gethostname(my_hostname, sizeof(my_hostname) - 1) == -1) { Pmsg2(0, "Fatal gethostname error: %s ERR=%s\n", my_hostname, strerror(errno)); exit(1); } if ((hp = gethostbyname(my_hostname)) == NULL) { Pmsg2(0, "Fatal gethostbyname for myself failed \"%s\": ERR=%s\n", my_hostname, strerror(errno)); exit(1); } strlcpy(my_hostname, hp->h_name, sizeof(my_hostname)); Dmsg(20, "My hostname is: %s\n", my_hostname); /* Determine from address. */ if (from_addr == NULL) { if ((pwd = getpwuid(getuid())) == 0) asnprintf(buf, sizeof(buf), "userid-%d@%s", (int)getuid(), my_hostname); else asnprintf(buf, sizeof(buf), "%s@%s", pwd->pw_name, my_hostname); from_addr = bstrdup(buf); } Dmsg(20, "From addr=%s\n", from_addr); /* Connect to smtp daemon on mailhost. */ hp: if ((hp = gethostbyname(mailhost)) == NULL) { Pmsg2(0, "Error unknown mail host \"%s\": ERR=%s\n", mailhost, strerror(errno)); if (strcasecmp(mailhost, "localhost") != 0) { Pmsg0(0, "Retrying connection using \"localhost\".\n"); mailhost = "localhost"; goto hp; } exit(1); } if (hp->h_addrtype != AF_INET) { Pmsg1(0, "Fatal error: Unknown address family for smtp host: %d\n", hp->h_addrtype); exit(1); } memset((char *)&sin, 0, sizeof(sin)); memcpy((char *)&sin.sin_addr, hp->h_addr, hp->h_length); sin.sin_family = hp->h_addrtype; sin.sin_port = htons(mailport); if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { Pmsg1(0, "Fatal socket error: ERR=%s\n", strerror(errno)); exit(1); } if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) < 0) { Pmsg2(0, "Fatal connect error to %s: ERR=%s\n", mailhost, strerror(errno)); exit(1); } Dmsg(20, "Connected\n"); /* Send SMTP headers */ get_response(); /* banner */ chat("helo %s\r\n", my_hostname); chat("mail from:<%s>\r\n", from_addr); for (i = 0; i < argc; i++) { Dmsg(20, "rcpt to: %s\n", argv[i]); chat("rcpt to:<%s>\r\n", argv[i]); } if (cc_addr) chat("rcpt to:<%s>\r\n", cc_addr); Dmsg(20, "Data\n"); chat("data\r\n"); /* Send message header */ sockwrite(s, "From: %s\r\n", from_addr); if (subject) sockwrite(s, "Subject: %s\r\n", subject); if (reply_addr) sockwrite(s, "Reply-To: %s\r\n", reply_addr); if (err_addr) sockwrite(s, "Errors-To: %s\r\n", err_addr); if ((pwd = getpwuid(getuid())) == 0) sockwrite(s, "Sender: userid-%d@%s\r\n", (int)getuid(), my_hostname); else sockwrite(s, "Sender: %s@%s\r\n", pwd->pw_name, my_hostname); sockwrite(s, "To: %s", argv[0]); for (i = 1; i < argc; i++) sockwrite(s, ",%s", argv[i]); sockwrite(s, "\r\n"); if (cc_addr) sockwrite(s, "Cc: %s\r\n", cc_addr); /* Add RFC822 date */ localtime_r(&now, &tm); #ifdef HAVE_MINGW // Annoyingly, Windows does not properly implement %z (it always spells // out the timezone name) so we need to emulate it manually. i = strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S ", &tm); tzset(); unsigned int offset = abs(_timezone) / 60; snprintf(buf+i, sizeof(buf)-i, "%c%02u%02u", _timezone < 0 ? '+' : '-', // _timezone is UTC-local offset/60, offset%60); #else strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", &tm); #endif sockwrite(s, "Date: %s\r\n", buf); sockwrite(s, "\r\n"); /* Send message body */ while (fgets(buf, sizeof(buf), stdin)) { buf[strlen(buf) - 1] = 0; if (strcmp(buf, ".") == 0) /* quote lone dots */ sockwrite(s, "..\r\n"); else /* pass body through unchanged */ sockwrite(s, "%s\r\n", buf); } /* Send SMTP quit command */ chat(".\r\n"); chat("quit\r\n"); /* Go away gracefully */ exit(0); } apcupsd-3.14.14/src/win32/000077500000000000000000000000001274230402600150545ustar00rootroot00000000000000apcupsd-3.14.14/src/win32/Makefile000066400000000000000000000017261274230402600165220ustar00rootroot00000000000000topdir:=../.. SUBDIRS = compat include $(topdir)/autoconf/targets.mak # Objects needed by apcupsd daemon SRCS := winmain.cpp winservice.cpp # Objects needed by various windows-specific executables APCTRAY_SRC := apctray.cpp winabout.cpp winevents.cpp winstat.cpp wintray.cpp \ balloonmgr.cpp meter.cpp listview.cpp instmgr.cpp winconfig.cpp winres.res SHUTDOWN_SRC := shutdown.c POPUP_SRC := popup.c EMAIL_SRC := email.c BG_SRC := background.c apctray$(EXE): LIBS += -lrpcrt4 email$(EXE): LIBS += -lmapi32 all-targets: $(OBJS) apctray$(EXE) shutdown$(EXE) popup$(EXE) email$(EXE) background$(EXE) apctray$(EXE): $(call SRC2OBJ, $(APCTRAY_SRC)) $(APCLIBS) $(LINK) $(DRVLIBS) $(BG) shutdown$(EXE): $(call SRC2OBJ, $(SHUTDOWN_SRC)) $(LINK) $(BG) popup$(EXE): $(call SRC2OBJ, $(POPUP_SRC)) $(LINK) $(BG) email$(EXE): $(call SRC2OBJ, $(EMAIL_SRC)) $(APCLIBS) $(LINK) background$(EXE): $(call SRC2OBJ, $(BG_SRC)) $(LINK) $(BG) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/win32/apctray.cpp000066400000000000000000000174551274230402600172370ustar00rootroot00000000000000/* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "winapi.h" #include #include #include "apc.h" #include "wintray.h" #include "resource.h" #include "winups.h" #include "statmgr.h" #include "astring.h" #include "instmgr.h" #include "compat.h" #define CMDOPT_INSTALL "/install" #define CMDOPT_REMOVE "/remove" #define CMDOPT_KILL "/kill" #define CMDOPT_QUIET "/quiet" #define USAGE_TEXT "[" CMDOPT_INSTALL "] " \ "[" CMDOPT_REMOVE "] " \ "[" CMDOPT_KILL "] " \ "[" CMDOPT_QUIET "]" // Global variables static HINSTANCE appinst; // Application handle static bool quiet = false; // Suppress user dialogs void NotifyError(const char *format, ...) { va_list args; char buf[2048]; va_start(args, format); avsnprintf(buf, sizeof(buf), format, args); va_end(args); MessageBox(NULL, buf, "Apctray", MB_OK|MB_ICONEXCLAMATION); } void NotifyUser(const char *format, ...) { va_list args; char buf[2048]; if (!quiet) { va_start(args, format); avsnprintf(buf, sizeof(buf), format, args); va_end(args); MessageBox(NULL, buf, "Apctray", MB_OK|MB_ICONINFORMATION); } } void PostToApctray(DWORD msg) { HWND wnd = FindWindow(APCTRAY_WINDOW_CLASS, NULL); if (wnd) PostMessage(wnd, msg, 0, 0); CloseHandle(wnd); } int Install() { // Get the full path/filename of this executable char path[1024]; GetModuleFileName(NULL, path, sizeof(path)); // Add double quotes char cmd[1024]; asnprintf(cmd, sizeof(cmd), "\"%s\"", path); // Open registry key for auto-run programs HKEY runkey; if (RegCreateKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &runkey) != ERROR_SUCCESS) { NotifyUser("The System Registry could not be updated.\n" "Apctray was not installed."); return 1; } // Attempt to add Apctray key if (RegSetValueEx(runkey, "Apctray", 0, REG_SZ, (unsigned char *)cmd, strlen(cmd)+1) != ERROR_SUCCESS) { RegCloseKey(runkey); NotifyUser("The System Registry could not be updated.\n" "Apctray was not installed."); return 1; } RegCloseKey(runkey); NotifyUser("Apctray was installed successfully and will\n" "automatically run when users log on."); return 0; } int Remove() { // Open registry key apctray HKEY runkey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ|KEY_WRITE, &runkey) == ERROR_SUCCESS) { RegDeleteValue(runkey, "Apctray"); RegCloseKey(runkey); } NotifyUser("Apctray will no longer start automatically."); return 0; } int Kill() { PostToApctray(WM_CLOSE); if (g_os_version >= WINDOWS_2000) { HANDLE evt = OpenEvent(EVENT_MODIFY_STATE, FALSE, APCTRAY_STOP_EVENT_NAME); if (evt != NULL) { SetEvent(evt); CloseHandle(evt); } } return 0; } void Usage(const char *text1, const char* text2) { MessageBox(NULL, text1, text2, MB_OK); MessageBox(NULL, USAGE_TEXT, "Apctray Usage", MB_OK | MB_ICONINFORMATION); } // This thread runs on Windows 2000 and higher. It monitors for the // global exit event to be signaled (/kill). static bool runthread = false; static HANDLE exitevt; DWORD WINAPI EventThread(LPVOID param) { // Create global exit event and allow Adminstrator access to it so any // member of the Administrators group can signal it. exitevt = CreateEvent(NULL, TRUE, FALSE, APCTRAY_STOP_EVENT_NAME); TCHAR name[] = "Administrators"; GrantAccess(exitevt, EVENT_MODIFY_STATE, TRUSTEE_IS_GROUP, name); // Wait for event to be signaled or for an error DWORD rc = WaitForSingleObject(exitevt, INFINITE); if (rc == WAIT_OBJECT_0) PostToApctray(WM_CLOSE); CloseHandle(exitevt); return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR CmdLine, int iCmdShow) { InitWinAPIWrapper(); // Publicize application handle appinst = hInstance; // Check command line options char *arg; char *opt = CmdLine; while ((arg = GetArg(&opt))) { if (strcasecmp(arg, CMDOPT_INSTALL) == 0) { return Install(); } else if (strcasecmp(arg, CMDOPT_REMOVE) == 0) { return Remove(); } else if (strcasecmp(arg, CMDOPT_KILL) == 0) { return Kill(); } else if (strcasecmp(arg, CMDOPT_QUIET) == 0) { quiet = true; } else { Usage(arg, "Unknown option"); return 1; } } // Check to see if we're already running in this session const char *semname = g_os_version < WINDOWS_2000 ? "apctray" : "Local\\apctray"; HANDLE sem = CreateSemaphore(NULL, 0, 1, semname); if (sem == NULL || GetLastError() == ERROR_ALREADY_EXISTS) { NotifyUser("Apctray is already running"); WSACleanup(); return 0; } // On Win2K and above we spawn a thread to watch for exit requests. HANDLE evtthread = NULL; if (g_os_version >= WINDOWS_2000) { runthread = true; evtthread = CreateThread(NULL, 0, EventThread, NULL, 0, NULL); } WPARAM generation = 0; InstanceManager instmgr(appinst); instmgr.CreateMonitors(); // Enter the Windows message handling loop until told to quit MSG msg; while (GetMessage(&msg, NULL, 0, 0) > 0) { TranslateMessage(&msg); switch (LOWORD(msg.message)) { case WM_APCTRAY_REMOVEALL: // Remove all instances (and close) instmgr.RemoveAll(); PostQuitMessage(0); break; case WM_APCTRAY_REMOVE: // Remove the given instance and exit if there are no more instances if (instmgr.RemoveInstance((const char *)msg.lParam) == 0) PostQuitMessage(0); break; case WM_APCTRAY_ADD: // Remove the given instance and exit if there are no more instances instmgr.AddInstance(); break; case WM_APCTRAY_RESET: // Redraw tray icons due to explorer exit/restart // We'll get a RESET message from each tray icon but we only want // to act on the first one. Check the generation and only perform the // reset if the generation matches. if (msg.wParam == generation) { // Bump generation so we ignore redundant reset commands generation++; // Delay while other tray icons refresh. This prevents our icons // from being scattered across the tray. sleep(2); // Now command the instances to reset instmgr.ResetInstances(); } break; default: DispatchMessage(&msg); } } // Wait for event thread to exit cleanly if (g_os_version >= WINDOWS_2000) { runthread = false; SetEvent(exitevt); // Kick exitevt to wake up thread if (WaitForSingleObject(evtthread, 5000) == WAIT_TIMEOUT) TerminateThread(evtthread, 0); CloseHandle(evtthread); } WSACleanup(); return 0; } apcupsd-3.14.14/src/win32/apcupsd.bmp000066400000000000000000001117361274230402600172240ustar00rootroot00000000000000BMޓ6(xi<<YYCC\\ VV$$ssCC RRffEEGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGFFFFFFCCFFGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGapcupsd-3.14.14/src/win32/apcupsd.ico000066400000000000000000000042761274230402600172200ustar00rootroot00000000000000 ( @pppxxxXXX                                                             ?apcupsd-3.14.14/src/win32/background.c000066400000000000000000000025331274230402600173420ustar00rootroot00000000000000#include "windows.h" int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { PROCESS_INFORMATION procinfo; STARTUPINFOA startinfo; BOOL rc; if (*szCmdLine == '\0') { MessageBox(NULL, "Usage: background.exe ", "Invalid usage!", MB_ICONSTOP); return 1; } /* Init the STARTUPINFOA struct. */ memset(&startinfo, 0, sizeof(startinfo)); startinfo.cb = sizeof(startinfo); rc = CreateProcess(NULL, szCmdLine, // command line NULL, // process security attributes NULL, // primary thread security attributes TRUE, // handles are inherited DETACHED_PROCESS, // creation flags NULL, // use parent's environment NULL, // use parent's current directory &startinfo, // STARTUPINFO pointer &procinfo); // receives PROCESS_INFORMATION if (!rc) { MessageBox(NULL, szCmdLine, "Failed to launch command!", MB_ICONSTOP); return 1; } // Cleanup handles CloseHandle(procinfo.hProcess); CloseHandle(procinfo.hThread); ExitProcess(0); } apcupsd-3.14.14/src/win32/balloonmgr.cpp000066400000000000000000000124351274230402600177210ustar00rootroot00000000000000/* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "apc.h" #include "balloonmgr.h" #include "resource.h" #define MAX_TIMEOUT 10000 #define MIN_TIMEOUT 2000 #define ARRAY_SIZE(x) ( sizeof(x) / sizeof((x)[0]) ) BalloonMgr::BalloonMgr() : _exit(false), _active(false) { _mutex = CreateMutex(NULL, false, NULL); _event = CreateEvent(NULL, false, false, NULL); _timer = CreateWaitableTimer(NULL, false, NULL); DWORD tid; _thread = CreateThread(NULL, 0, &BalloonMgr::Thread, this, 0, &tid); } BalloonMgr::~BalloonMgr() { // Request thread exit _exit = true; signal(); // Wait for thread exit and force if necessary if (_thread) { if (WaitForSingleObject(_thread, 5000) == WAIT_TIMEOUT) TerminateThread(_thread, 0); CloseHandle(_thread); } CloseHandle(_mutex); CloseHandle(_event); CloseHandle(_timer); } void BalloonMgr::PostBalloon(HWND hwnd, const char *title, const char *text) { lock(); Balloon balloon = {hwnd, title, text}; _pending.append(balloon); signal(); unlock(); } void BalloonMgr::lock() { WaitForSingleObject(_mutex, INFINITE); } void BalloonMgr::unlock() { ReleaseMutex(_mutex); } void BalloonMgr::signal() { SetEvent(_event); } void BalloonMgr::post() { if (_pending.empty()) return; // No active balloon!? // Post balloon tip Balloon &balloon = _pending.front(); NOTIFYICONDATA nid; nid.hWnd = balloon.hwnd; nid.cbSize = sizeof(nid); nid.uID = IDI_APCUPSD; nid.uFlags = NIF_INFO; strlcpy(nid.szInfo, balloon.text, sizeof(nid.szInfo)); strlcpy(nid.szInfoTitle, balloon.title, sizeof(nid.szInfoTitle)); nid.uTimeout = MAX_TIMEOUT; nid.dwInfoFlags = NIIF_INFO; Shell_NotifyIcon(NIM_MODIFY, &nid); // Set a timeout to clear the balloon LARGE_INTEGER timeout; if (_pending.size() > 1) // More balloons pending: use minimum timeout timeout.QuadPart = -(MIN_TIMEOUT * 10000); else // No other balloons pending: Use maximum timeout timeout.QuadPart = -(MAX_TIMEOUT * 10000); SetWaitableTimer(_timer, &timeout, 0, NULL, NULL, false); // Remember the time at which we started the timer gettimeofday(&_time, NULL); } void BalloonMgr::clear() { if (_pending.empty()) return; // No active balloon!? // Clear active balloon Balloon &balloon = _pending.front(); NOTIFYICONDATA nid; nid.hWnd = balloon.hwnd; nid.cbSize = sizeof(nid); nid.uID = IDI_APCUPSD; nid.uFlags = NIF_INFO; nid.uTimeout = 0; nid.szInfoTitle[0] = '\0'; nid.szInfo[0] = '\0'; nid.dwInfoFlags = 0; Shell_NotifyIcon(NIM_MODIFY, &nid); // Remove vector entry for active balloon _pending.remove_first(); } DWORD WINAPI BalloonMgr::Thread(LPVOID param) { BalloonMgr *_this = (BalloonMgr*)param; HANDLE handles[] = {_this->_event, _this->_timer}; LARGE_INTEGER timeout; struct timeval now; DWORD index; long diff; while (1) { // Wait for timeout or new balloon request index = WaitForMultipleObjects( ARRAY_SIZE(handles), handles, false, INFINITE); // Exit if we've been asked to do so if (_this->_exit) break; switch (index) { // New balloon request has arrived case WAIT_OBJECT_0 + 0: _this->lock(); if (!_this->_active) { // No balloon active: Post new balloon immediately if (!_this->_pending.empty()) { _this->post(); _this->_active = true; } } else { // A balloon is active: Shorten timer to minimum CancelWaitableTimer(_this->_timer); gettimeofday(&now, NULL); diff = TV_DIFF_MS(_this->_time, now); if (diff >= MIN_TIMEOUT) { // Min timeout already expired timeout.QuadPart = -1; } else { // Wait enough additional time to meet minimum timeout timeout.QuadPart = -((MIN_TIMEOUT - diff) * 10000); } SetWaitableTimer(_this->_timer, &timeout, 0, NULL, NULL, false); } _this->unlock(); break; // Timeout ocurred case WAIT_OBJECT_0 + 1: _this->lock(); // Clear active balloon _this->clear(); // Post next balloon if there is one if (!_this->_pending.empty()) { _this->post(); _this->_active = true; } else { _this->_active = false; } _this->unlock(); break; default: // Should never happen...but if it does, sleep a bit to prevent // spinning. Sleep(1000); break; } } return 0; } apcupsd-3.14.14/src/win32/balloonmgr.h000066400000000000000000000026571274230402600173730ustar00rootroot00000000000000/* * Copyright (C) 2007 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef BALLOONMGR_H #define BALLOONMGR_H #include #include "astring.h" #include "alist.h" class BalloonMgr { public: BalloonMgr(); ~BalloonMgr(); void PostBalloon(HWND hwnd, const char *title, const char *text); static DWORD WINAPI Thread(LPVOID param); private: void post(); void clear(); void lock(); void unlock(); void signal(); struct Balloon { HWND hwnd; astring title; astring text; }; alist _pending; HANDLE _mutex; bool _exit; bool _active; HANDLE _event; HANDLE _timer; struct timeval _time; HANDLE _thread; }; #endif // BALLOONMGR_H apcupsd-3.14.14/src/win32/charging.ico000066400000000000000000000004761274230402600173410ustar00rootroot00000000000000((   " " "" """ """"" 0" 0"0 0000 a3 apcupsd-3.14.14/src/win32/commlost.ico000066400000000000000000000025761274230402600174170ustar00rootroot00000000000000h(   #$"35'(125[_bfqvy~PSDbjnuxqvy|$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$########$$#######$$###!##!!!!#$$# #$$######$$#####$$##### #$$  $$$"$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$apcupsd-3.14.14/src/win32/compat/000077500000000000000000000000001274230402600163375ustar00rootroot00000000000000apcupsd-3.14.14/src/win32/compat/Makefile000066400000000000000000000005541274230402600200030ustar00rootroot00000000000000topdir:=../../.. SUBDIRS = include $(topdir)/autoconf/targets.mak SRCS = compat.cpp inet_aton.c winapi.c $(if $(USBDRV),libusb-winusb-bridge.c) \ ioctl.c tcflush.c tcsetattr.c tcgetattr.c syslog.c kill.c pathconf.c \ waitpid.c sleep.c fcntl.c all-targets: libwin32compat.a libwin32compat.a: $(OBJS) $(MAKELIB) # Include dependencies -include $(DEPS) apcupsd-3.14.14/src/win32/compat/arpa/000077500000000000000000000000001274230402600172625ustar00rootroot00000000000000apcupsd-3.14.14/src/win32/compat/arpa/inet.h000066400000000000000000000015031274230402600203710ustar00rootroot00000000000000/* * Copyright (C) 2014 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __ARPA_INET_H_ #define __ARPA_INET_H_ #include "ws2tcpip.h" int inet_aton(const char *cp, struct in_addr *inp); #endif apcupsd-3.14.14/src/win32/compat/compat.cpp000066400000000000000000000100141274230402600203220ustar00rootroot00000000000000// -*- Mode: C++ -*- // compat.cpp -- compatibilty layer to make bacula-fd run // natively under windows // // Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // // Copyright (C) 2004-2006 Kern Sibbald // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // version 2 as amended with additional clauses defined in the // file LICENSE in the main source directory. // // 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 // the file LICENSE for additional details. // // Author : Christopher S. Hull // Created On : Sat Jan 31 15:55:00 2004 // $Id: compat.cpp,v 1.22.2.5 2010-09-10 14:50:12 adk0212 Exp $ #include "apc.h" #include "compat.h" #include "winapi.h" // from MicroSoft SDK (KES) is the diff between Jan 1 1601 and Jan 1 1970 #define WIN32_FILETIME_ADJUST 0x19DB1DED53E8000ULL #define WIN32_FILETIME_SCALE 10000000 // 100ns/second void conv_unix_to_win32_path(const char *name, char *win32_name, DWORD dwSize) { const char *fname = name; while (*name) { /* Check for Unix separator and convert to Win32 */ if (name[0] == '/' && name[1] == '/') { /* double slash? */ name++; /* yes, skip first one */ } if (*name == '/') { *win32_name++ = '\\'; /* convert char */ /* If Win32 separated that is "quoted", remove quote */ } else if (*name == '\\' && name[1] == '\\') { *win32_name++ = '\\'; name++; /* skip first \ */ } else { *win32_name++ = *name; /* copy character */ } name++; } /* Strip any trailing slash, if we stored something */ /* but leave "c:\" with backslash (root directory case */ if (*fname != 0 && win32_name[-1] == '\\' && strlen (fname) != 3) { win32_name[-1] = 0; } else { *win32_name = 0; } } // ///////////////////////////////////////////////////////////////// // convert from Windows concept of time to Unix concept of time // ///////////////////////////////////////////////////////////////// void cvt_utime_to_ftime(const time_t &time, FILETIME &wintime) { uint64_t mstime = time; mstime *= WIN32_FILETIME_SCALE; mstime += WIN32_FILETIME_ADJUST; #ifdef HAVE_MINGW wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffUL); #else wintime.dwLowDateTime = (DWORD)(mstime & 0xffffffffI64); #endif wintime.dwHighDateTime = (DWORD) ((mstime>>32)& 0xffffffffUL); } time_t cvt_ftime_to_utime(const FILETIME &time) { uint64_t mstime = time.dwHighDateTime; mstime <<= 32; mstime |= time.dwLowDateTime; mstime -= WIN32_FILETIME_ADJUST; mstime /= WIN32_FILETIME_SCALE; // convert to seconds. return (time_t) (mstime & 0xffffffff); } // Parse windows-style command line into individual arguments char *GetArg(char **cmdline) { // Skip leading whitespace while (isspace(**cmdline)) (*cmdline)++; // Bail if there's nothing left if (**cmdline == '\0') return NULL; // Find end of this argument char *ret; if (**cmdline == '"') { // Find end of quoted argument ret = ++(*cmdline); while (**cmdline && **cmdline != '"') (*cmdline)++; } else { // Find end of non-quoted argument ret = *cmdline; while (**cmdline && !isspace(**cmdline)) (*cmdline)++; } // NUL-terminate this argument if (**cmdline) *(*cmdline)++ = '\0'; return ret; } int WSA_Init(void) { WORD wVersionRequested = MAKEWORD( 1, 1); WSADATA wsaData; int err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { printf("Can not start Windows Sockets\n"); errno = ENOSYS; return -1; } return 0; } apcupsd-3.14.14/src/win32/compat/compat.h000066400000000000000000000026731274230402600200030ustar00rootroot00000000000000/* -*- Mode: C -*- * compat.h -- */ // Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // // Copyright (C) 2004-2006 Kern Sibbald // // 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., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1335, USA. /* * * Author : Christopher S. Hull * Created On : Fri Jan 30 13:00:51 2004 * Last Modified By: Thorsten Engel * Last Modified On: Fri Apr 22 19:30:00 2004 * Update Count : 218 * $Id: compat.h,v 1.21.2.4 2009-08-01 12:01:59 adk0212 Exp $ */ #ifndef __COMPAT_H_ #define __COMPAT_H_ #ifdef __cplusplus extern "C" { #endif // Parse windows-style command line into individual arguments char *GetArg(char **cmdline); #ifdef __cplusplus }; #endif #endif /* __COMPAT_H_ */ apcupsd-3.14.14/src/win32/compat/errno.h000066400000000000000000000021321274230402600176330ustar00rootroot00000000000000// Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // // Copyright (C) 2004-2006 Kern Sibbald // Copyright (C) 2014 Adam Kropelin // // 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., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1335, USA. #ifndef __COMPAT_ERRNO_H_ #define __COMPAT_ERRNO_H_ #include_next #ifndef EAFNOSUPPORT #define EAFNOSUPPORT WSAEAFNOSUPPORT #endif #endif /* __COMPAT_ERRNO_H_ */ apcupsd-3.14.14/src/win32/compat/fcntl.c000066400000000000000000000014061274230402600176120ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include int fcntl(int fd, int cmd, ...) { return 0; } apcupsd-3.14.14/src/win32/compat/fcntl.h000066400000000000000000000017771274230402600176320ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __COMPAT_FCNTL_H_ #define __COMPAT_FCNTL_H_ #include_next #define O_NOCTTY 0 #ifndef F_GETFL # define F_GETFL 1 #endif #ifndef F_SETFL # define F_SETFL 2 #endif #ifdef __cplusplus extern "C" { #endif int fcntl(int fd, int cmd, ...); #ifdef __cplusplus }; #endif #endif /* __COMPAT_FCNTL_H_ */ apcupsd-3.14.14/src/win32/compat/inet_aton.c000066400000000000000000000035471274230402600204740ustar00rootroot00000000000000// -*- Mode: C++ -*- // compat.cpp -- compatibilty layer to make bacula-fd run // natively under windows // // Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // // Copyright (C) 2004-2006 Kern Sibbald // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // version 2 as amended with additional clauses defined in the // file LICENSE in the main source directory. // // 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 // the file LICENSE for additional details. // // Author : Christopher S. Hull // Created On : Sat Jan 31 15:55:00 2004 // $Id: netcompat.c,v 1.1.2.1 2009-07-31 14:20:35 adk0212 Exp $ #include #include #include /* * Dotted IP address to network address * * Returns 1 if OK * 0 on error */ int inet_aton(const char *a, struct in_addr *inp) { const char *cp = a; uint32_t acc = 0, tmp = 0; int dotc = 0; if (!isdigit(*cp)) { /* first char must be digit */ return 0; /* error */ } do { if (isdigit(*cp)) { tmp = (tmp * 10) + (*cp -'0'); } else if (*cp == '.' || *cp == 0) { if (tmp > 255) { return 0; /* error */ } acc = (acc << 8) + tmp; dotc++; tmp = 0; } else { return 0; /* error */ } } while (*cp++ != 0); if (dotc != 4) { /* want 3 .'s plus EOS */ return 0; /* error */ } inp->s_addr = htonl(acc); /* store addr in network format */ return 1; } apcupsd-3.14.14/src/win32/compat/install000066400000000000000000000002331274230402600177260ustar00rootroot00000000000000#!/bin/sh # # Dumb script to save Kern from typing too much # cp -fp ../baculafd/Release/bacula-fd.exe /bacula/bin ls -l ../baculafd/Release/bacula-fd.exe apcupsd-3.14.14/src/win32/compat/ioctl.c000066400000000000000000000056201274230402600176200ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include #include #include #include #include "winapi.h" static int tiocmbic(int fd, int bits) { DCB dcb; dcb.DCBlength = sizeof(DCB); if (bits & TIOCM_ST) { // Win32 API does not allow manipulating ST errno = EINVAL; return -1; } HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == 0) { errno = EBADF; return -1; } GetCommState(h, &dcb); if (bits & TIOCM_DTR) dcb.fDtrControl = DTR_CONTROL_DISABLE; if (bits & TIOCM_RTS) dcb.fRtsControl = RTS_CONTROL_DISABLE; SetCommState(h, &dcb); return 0; } static int tiocmbis(int fd, int bits) { DCB dcb; dcb.DCBlength = sizeof(DCB); if (bits & TIOCM_SR) { // Win32 API does not allow manipulating SR errno = EINVAL; return -1; } HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == 0) { errno = EBADF; return -1; } GetCommState(h, &dcb); if (bits & TIOCM_DTR) dcb.fDtrControl = DTR_CONTROL_ENABLE; if (bits & TIOCM_RTS) dcb.fRtsControl = RTS_CONTROL_ENABLE; SetCommState(h, &dcb); return 0; } static int tiocmget(int fd, int *bits) { DWORD status; HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == 0) { errno = EBADF; return -1; } GetCommModemStatus(h, &status); *bits = 0; if (status & MS_CTS_ON) *bits |= TIOCM_CTS; if (status & MS_DSR_ON) *bits |= TIOCM_DSR; if (status & MS_RING_ON) *bits |= TIOCM_RI; if (status & MS_RLSD_ON) *bits |= TIOCM_CD; return 0; } int ioctl(int fd, int request, ...) { int rc; u_long v; va_list list; va_start(list, request); /* We only know how to emulate a few ioctls */ switch (request) { case TIOCMBIC: rc = tiocmbic(fd, *va_arg(list, int*)); break; case TIOCMBIS: rc = tiocmbis(fd, *va_arg(list, int*)); break; case TIOCMGET: rc = tiocmget(fd, va_arg(list, int*)); break; case FIONBIO: v = *va_arg(list, int*); rc = ioctlsocket(fd, request, &v); break; default: rc = -1; errno = EINVAL; break; } va_end(list); return rc; } apcupsd-3.14.14/src/win32/compat/kill.c000066400000000000000000000026341274230402600174430ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include "winapi.h" int kill(int pid, int signal) { int rval = 0; DWORD exitcode = 0; switch (signal) { case SIGTERM: /* Terminate the process */ if (!TerminateProcess((HANDLE)pid, (UINT) signal)) { rval = -1; errno = EPERM; } CloseHandle((HANDLE)pid); break; case 0: /* Just check if process is still alive */ if (GetExitCodeProcess((HANDLE)pid, &exitcode) && exitcode != STILL_ACTIVE) { rval = -1; errno = ESRCH; } break; default: /* Don't know what to do, so just fail */ rval = -1; errno = EINVAL; break; } return rval; } apcupsd-3.14.14/src/win32/compat/libusb-winusb-bridge.c000066400000000000000000000263101274230402600225240ustar00rootroot00000000000000/* * libusb-winusb-bridge.c * * Simple backend for libusb using MS WinUsb. Only the basic functions * necessary for apcupsd are implemented, although the others could be added * fairly easily. */ /* * Copyright (C) 2010 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "libusb-winusb-bridge.h" #include #include #include #include "apc.h" // winusb.dll entrypoints DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize, (HANDLE, PWINUSB_INTERFACE_HANDLE)); DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE)); DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface, (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE)); DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR, ULONG, PULONG)); DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings, (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR)); DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation, (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID)); DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, UCHAR)); DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting, (WINUSB_INTERFACE_HANDLE, PUCHAR)); DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, PWINUSB_PIPE_INFORMATION)); DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID)); DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy, (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID)); DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe, (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer, (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG, PULONG, LPOVERLAPPED)); DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe, (WINUSB_INTERFACE_HANDLE, UCHAR)); // GUID for Apcupsd-owned UPSes, as specified in our INF file // Binary equivalent of {8c534620-f7e6-11de-8a39-0800200c9a66} GUID APCUPSD_DEVICE_GUID = { 0x8c534620, 0xf7e6, 0x11de, {0x8a, 0x39, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66} }; #define MAX_USB_DEVICES 10 static struct usb_device devices[MAX_USB_DEVICES]; static struct usb_bus bus = { NULL, NULL, "bus0", devices }; struct usb_dev_handle { HANDLE hnd; WINUSB_INTERFACE_HANDLE fd; }; void usb_init(void) { // Initialize DLL functions if (!WinUsb_Initialize) { DLL_LOAD(winusb.dll, WinUsb_Initialize); DLL_LOAD(winusb.dll, WinUsb_Free); DLL_LOAD(winusb.dll, WinUsb_GetAssociatedInterface); DLL_LOAD(winusb.dll, WinUsb_GetDescriptor); DLL_LOAD(winusb.dll, WinUsb_QueryInterfaceSettings); DLL_LOAD(winusb.dll, WinUsb_QueryDeviceInformation); DLL_LOAD(winusb.dll, WinUsb_SetCurrentAlternateSetting); DLL_LOAD(winusb.dll, WinUsb_GetCurrentAlternateSetting); DLL_LOAD(winusb.dll, WinUsb_QueryPipe); DLL_LOAD(winusb.dll, WinUsb_SetPipePolicy); DLL_LOAD(winusb.dll, WinUsb_GetPipePolicy); DLL_LOAD(winusb.dll, WinUsb_ReadPipe); DLL_LOAD(winusb.dll, WinUsb_WritePipe); DLL_LOAD(winusb.dll, WinUsb_ControlTransfer); DLL_LOAD(winusb.dll, WinUsb_ResetPipe); DLL_LOAD(winusb.dll, WinUsb_AbortPipe); DLL_LOAD(winusb.dll, WinUsb_FlushPipe); } } int usb_find_busses(void) { return 1; } static int usb_get_device_desc(struct usb_device *dev) { struct usb_dev_handle *hnd = usb_open(dev); if (!hnd) return 1; ULONG actlen = 0; if (!WinUsb_GetDescriptor(hnd->fd, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, (unsigned char*)&dev->descriptor, sizeof(dev->descriptor), &actlen) || actlen != sizeof(dev->descriptor)) { return 1; } // Descriptor as read from the device is in little-endian format. No need // to convert since this is guaranteed to be Windows which runs only on // little-endian processors. return usb_close(hnd); } int usb_find_devices(void) { // Get the set of device interfaces that have been matched by our INF HDEVINFO deviceInfo = SetupDiGetClassDevs( &APCUPSD_DEVICE_GUID, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (!deviceInfo) { return 0; } // Iterate over all interfaces int ndevs = 0; int devidx = 0; while (ndevs < MAX_USB_DEVICES) { // Get interface data for next interface and attempt to init it SP_DEVICE_INTERFACE_DATA interfaceData; interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); if (!SetupDiEnumDeviceInterfaces( deviceInfo, NULL, &APCUPSD_DEVICE_GUID, devidx++, &interfaceData)) { break; } // Determine required size for interface detail data ULONG requiredLength = 0; SetupDiGetDeviceInterfaceDetail( deviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL); // Allocate storage for interface detail data PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredLength); detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); // Fetch interface detail data if (!SetupDiGetDeviceInterfaceDetail( deviceInfo, &interfaceData, detailData, requiredLength, &requiredLength, NULL)) { free(detailData); continue; } // Populate device structure struct usb_device *dev = devices+ndevs; memset(dev, 0, sizeof(*dev)); strlcpy(dev->filename, detailData->DevicePath, sizeof(dev->filename)); dev->bus = &bus; if (ndevs) { dev->prev = devices + ndevs - 1; dev->prev->next = dev; } // Fetch device descriptor structure if (usb_get_device_desc(dev) == 0) ndevs++; free(detailData); } SetupDiDestroyDeviceInfoList(deviceInfo); return ndevs; } struct usb_bus *usb_get_busses(void) { return &bus; } usb_dev_handle *usb_open(struct usb_device *dev) { // Open generic handle to device HANDLE hnd = CreateFile(dev->filename, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (hnd == NULL) return NULL; // Initialize WinUSB for this device and get a WinUSB handle for it WINUSB_INTERFACE_HANDLE fd; if (!WinUsb_Initialize(hnd, &fd)) { CloseHandle(hnd); return NULL; } // Device opened successfully. Allocate storage for handles. struct usb_dev_handle *usb = (struct usb_dev_handle *)malloc(sizeof(struct usb_dev_handle)); usb->hnd = hnd; usb->fd = fd; return usb; } int usb_close(usb_dev_handle *dev) { WinUsb_Free(dev->fd); CloseHandle(dev->hnd); free(dev); return 0; } int usb_set_configuration(usb_dev_handle *dev, int configuration) { return 0; } int usb_claim_interface(usb_dev_handle *dev, int iface) { return 0; } int usb_release_interface(usb_dev_handle *dev, int iface) { return 0; } int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout) { // Format parameters into a ctrl setup packet // 'timeout' is ignored; WinUSB has a 5 second default timeout on the ctrl // pipe, which is good enough for us. WINUSB_SETUP_PACKET sp; sp.RequestType = requesttype; sp.Request = request; sp.Value = value; sp.Index = index; sp.Length = size; ULONG actlen = 0; if (!WinUsb_ControlTransfer(dev->fd, sp, (unsigned char*)bytes, size, &actlen, NULL)) return -GetLastError(); return actlen; } int usb_get_string_simple(usb_dev_handle *dev, int index, char *buf, size_t buflen) { unsigned char temp[MAXIMUM_USB_STRING_LENGTH]; ULONG actlen = 0; if (!WinUsb_GetDescriptor(dev->fd, USB_STRING_DESCRIPTOR_TYPE, index, 0x0409, temp, sizeof(temp), &actlen)) { return -GetLastError(); } // Skip first two bytes of result (descriptor id and length), then take // every other byte as a cheap way to convert Unicode to ASCII unsigned int i, j; for (i = 2, j = 0; i < actlen && j < (buflen-1); i+=2, ++j) buf[j] = temp[i]; buf[j] = '\0'; return strlen(buf); } int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) { // Set timeout on endpoint // It might be more efficient to use async i/o here, but MS docs imply that // you have to create a new sync object for every call, which doesn't seem // efficient at all. So just set the pipe timeout and use sync i/o. ULONG tmp = timeout; if (!WinUsb_SetPipePolicy(dev->fd, ep, PIPE_TRANSFER_TIMEOUT, sizeof(tmp), &tmp)) return -EINVAL; // Perform transfer tmp = 0; if (!WinUsb_ReadPipe(dev->fd, ep, (unsigned char*)bytes, size, &tmp, NULL)) { tmp = GetLastError(); if (tmp == ERROR_SEM_TIMEOUT) return -ETIMEDOUT; else return -EINVAL; } return tmp; } int usb_interrupt_write(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout) { // Set timeout on endpoint // It might be more efficient to use async i/o here, but MS docs imply that // you have to create a new sync object for every call, which doesn't seem // efficient at all. So just set the pipe timeout and use sync i/o. ULONG tmp = timeout; if (!WinUsb_SetPipePolicy(dev->fd, ep, PIPE_TRANSFER_TIMEOUT, sizeof(tmp), &tmp)) return -EINVAL; // Perform transfer tmp = 0; if (!WinUsb_WritePipe(dev->fd, ep, (unsigned char*)bytes, size, &tmp, NULL)) { tmp = GetLastError(); if (tmp == ERROR_SEM_TIMEOUT) return -ETIMEDOUT; else return -EINVAL; } return tmp; } char *usb_strerror(void) { static char buf[256]; snprintf(buf, sizeof(buf), "Windows Error #%lu", GetLastError()); return buf; } int usb_reset(usb_dev_handle *dev) { return 0; } void usb_set_debug(int level) { } apcupsd-3.14.14/src/win32/compat/libusb-winusb-bridge.h000066400000000000000000000062131274230402600225310ustar00rootroot00000000000000/* * libusb-winusb-bridge.h * * Simple backend for libusb using MS WinUsb. Only the basic functions * necessary for apcupsd are implemented, although the others could be added * fairly easily. */ /* * Copyright (C) 2010 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __LIBUSB_WINUSB_BRIDGE_H #define __LIBUSB_WINUSB_BRIDGE_H #include "winusb.h" #include // Make old libusb constants from WinUSB constants #define USB_ENDPOINT_IN USB_ENDPOINT_DIRECTION_MASK #define USB_ENDPOINT_OUT 0 #define USB_RECIP_INTERFACE (BMREQUEST_TO_INTERFACE << 0) #define USB_TYPE_CLASS (BMREQUEST_CLASS << 5) #define USB_REQ_GET_DESCRIPTOR USB_REQUEST_GET_DESCRIPTOR #define USB_DT_REPORT 0x22 #define USB_REQ_GET_REPORT 0x01 #define USB_REQ_SET_REPORT 0x09 // usb device descriptor struct usb_device_descriptor { UCHAR bLength; UCHAR bDescriptorType; USHORT bcdUSB; UCHAR bDeviceClass; UCHAR bDeviceSubClass; UCHAR bDeviceProtocol; UCHAR bMaxPacketSize0; USHORT idVendor; USHORT idProduct; USHORT bcdDevice; UCHAR iManufacturer; UCHAR iProduct; UCHAR iSerialNumber; UCHAR bNumConfigurations; }; // libusb structures, abbreviated struct usb_bus; struct usb_device { struct usb_device *next, *prev; char filename[PATH_MAX + 1]; struct usb_bus *bus; struct usb_device_descriptor descriptor; }; struct usb_bus { struct usb_bus *next, *prev; char dirname[PATH_MAX + 1]; struct usb_device *devices; }; struct usb_dev_handle; typedef struct usb_dev_handle usb_dev_handle; // libusb function prototypes (just the ones we support) usb_dev_handle *usb_open(struct usb_device *dev); int usb_close(usb_dev_handle *dev); int usb_get_string_simple( usb_dev_handle *dev, int index, char *buf, size_t buflen); int usb_interrupt_read( usb_dev_handle *dev, int ep, char *bytes, int size, int timeout); int usb_interrupt_write( usb_dev_handle *dev, int ep, char *bytes, int size, int timeout); int usb_control_msg( usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout); int usb_set_configuration(usb_dev_handle *dev, int configuration); int usb_claim_interface(usb_dev_handle *dev, int iface); int usb_release_interface(usb_dev_handle *dev, int iface); int usb_reset(usb_dev_handle *dev); char *usb_strerror(void); void usb_init(void); void usb_set_debug(int level); int usb_find_busses(void); int usb_find_devices(void); struct usb_bus *usb_get_busses(void); #endif // __LIBUSB_WINUSB_BRIDGE_H apcupsd-3.14.14/src/win32/compat/mswinver.h000066400000000000000000000024771274230402600203740ustar00rootroot00000000000000#ifndef __MSWINVER_H_ #define __MSWINVER_H_ #include "winbase.h" #define MS_MAJOR_WINDOWS_3 3 #define MS_MAJOR_WINDOWS_95 4 #define MS_MAJOR_WINDOWS_98 4 #define MS_MAJOR_WINDOWS_ME 4 #define MS_MAJOR_WINDOWS_NT4 4 #define MS_MAJOR_WINDOWS_2K 5 #define MS_MAJOR_WINDOWS_XP 5 #define MS_MAJOR_WINDOWS_S2003 5 #define MS_MINOR_WINDOWS_3 51 #define MS_MINOR_WINDOWS_95 0 #define MS_MINOR_WINDOWS_98 10 #define MS_MINOR_WINDOWS_ME 90 #define MS_MINOR_WINDOWS_NT4 0 #define MS_MINOR_WINDOWS_2K 0 #define MS_MINOR_WINDOWS_XP 1 #define MS_MINOR_WINDOWS_S2003 2 #define _mkversion(p, m, r) (((p)<<24)|((m)<<8)|(r)) #define MS_WINDOWS_95 _mkversion(VER_PLATFORM_WIN32_WINDOWS, MS_MAJOR_WINDOWS_95, MS_MINOR_WINDOWS_95) #define MS_WINDOWS_98 _mkversion(VER_PLATFORM_WIN32_WINDOWS, MS_MAJOR_WINDOWS_98, MS_MINOR_WINDOWS_98) #define MS_WINDOWS_ME _mkversion(VER_PLATFORM_WIN32_WINDOWS, MS_MAJOR_WINDOWS_ME, MS_MINOR_WINDOWS_ME) #define MS_WINDOWS_NT4 _mkversion(VER_PLATFORM_WIN32_NT, MS_MAJOR_WINDOWS_NT4, MS_MINOR_WINDOWS_NT4) #define MS_WINDOWS_2K _mkversion(VER_PLATFORM_WIN32_NT, MS_MAJOR_WINDOWS_2K, MS_MINOR_WINDOWS_2K) #define MS_WINDOWS_XP _mkversion(VER_PLATFORM_WIN32_NT, MS_MAJOR_WINDOWS_XP, MS_MINOR_WINDOWS_XP) #define MS_WINDOWS_S2003 _mkversion(VER_PLATFORM_WIN32_NT, MS_MAJOR_WINDOWS_S2003, MS_MINOR_WINDOWS_S2003) #endif apcupsd-3.14.14/src/win32/compat/netdb.h000066400000000000000000000000661274230402600176060ustar00rootroot00000000000000// winsock2.h has gethostbyname #include apcupsd-3.14.14/src/win32/compat/netinet/000077500000000000000000000000001274230402600200055ustar00rootroot00000000000000apcupsd-3.14.14/src/win32/compat/netinet/in.h000066400000000000000000000000261274230402600205620ustar00rootroot00000000000000#include "ws2tcpip.h" apcupsd-3.14.14/src/win32/compat/pathconf.c000066400000000000000000000023351274230402600203100ustar00rootroot00000000000000// Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // // Copyright (C) 2004-2006 Kern Sibbald // Copyright (C) 2014 Adam Kropelin // // 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., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1335, USA. #include #include #include long pathconf(const char *path, int name) { switch(name) { case _PC_PATH_MAX : if (strncmp(path, "\\\\?\\", 4) == 0) return 32767; case _PC_NAME_MAX : return 255; } errno = ENOSYS; return -1; } apcupsd-3.14.14/src/win32/compat/pwd.h000066400000000000000000000014051274230402600173020ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __PWD_H_ #define __PWD_H_ #define getpwuid(x) NULL #endif apcupsd-3.14.14/src/win32/compat/signal.h000066400000000000000000000022321274230402600177640ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __COMPAT_SIGNAL_H_ #define __COMPAT_SIGNAL_H_ /* Pull in mingw signal.h */ #include_next struct sigaction { int sa_flags; void (*sa_handler)(int); }; #define SIGKILL 9 #define SIGUSR2 9999 #define SIGALRM 0 #define SIGHUP 0 #define SIGCHLD 0 #define SIGPIPE 0 #ifdef __cplusplus extern "C" { #endif #define sigfillset(x) #define sigaction(a, b, c) int kill(int pid, int signo); #ifdef __cplusplus }; #endif #endif /* __COMPAT_SIGNAL_H_ */ apcupsd-3.14.14/src/win32/compat/sleep.c000066400000000000000000000014761274230402600176230ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include "winapi.h" unsigned int sleep(unsigned int seconds) { Sleep(seconds * 1000); return 0; } apcupsd-3.14.14/src/win32/compat/string.h000066400000000000000000000017361274230402600200250ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __COMPAT_STRING_H_ #define __COMPAT_STRING_H_ #include_next /* Should use strtok_s but mingw doesn't have it. strtok is thread-safe on * Windows via TLS, so this substitution should be ok... */ #define strtok_r(a,b,c) strtok(a,b) #endif /* __COMPAT_STRING_H_ */ apcupsd-3.14.14/src/win32/compat/sys/000077500000000000000000000000001274230402600171555ustar00rootroot00000000000000apcupsd-3.14.14/src/win32/compat/sys/ioctl.h000066400000000000000000000003301274230402600204340ustar00rootroot00000000000000#ifndef __IOCTL_COMPAT_H #define __IOCTL_COMPAT_H #define TIOCMBIC 1 #define TIOCMBIS 2 #ifdef __cplusplus extern "C" { #endif int ioctl(int, int, ...); #ifdef __cplusplus }; #endif #endif // __IOCTL_COMPAT_H apcupsd-3.14.14/src/win32/compat/sys/socket.h000066400000000000000000000000271274230402600206150ustar00rootroot00000000000000#include "ws2tcpip.h" apcupsd-3.14.14/src/win32/compat/sys/termios.h000066400000000000000000000152201274230402600210100ustar00rootroot00000000000000/* sys/termios.h Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ /* sys/termios.h */ #ifndef _SYS_TERMIOS_H #define _SYS_TERMIOS_H #define TIOCMGET 0x5415 #define TIOCMSET 0x5418 #define TIOCINQ 0x541B /* TIOCINQ is utilized instead of FIONREAD which has been accupied for other purposes under CYGWIN. Other UNIX ioctl requests has been omited because effects of their work one can achive by standard POSIX commands */ #define TIOCSBRK 0x5427 #define TIOCCBRK 0x5428 #define TIOCM_LE 0x001 #define TIOCM_DTR 0x002 #define TIOCM_RTS 0x004 #define TIOCM_ST 0x008 #define TIOCM_SR 0x010 #define TIOCM_CTS 0x020 #define TIOCM_CAR 0x040 #define TIOCM_RNG 0x080 #define TIOCM_DSR 0x100 #define TIOCM_CD TIOCM_CAR #define TIOCM_RI TIOCM_RNG #define TCOOFF 0 #define TCOON 1 #define TCIOFF 2 #define TCION 3 #define TCGETA 5 #define TCSETA 6 #define TCSETAW 7 #define TCSETAF 8 #define TCIFLUSH 0 #define TCOFLUSH 1 #define TCIOFLUSH 2 #define TCFLSH 3 #define TCSAFLUSH 1 #define TCSANOW 2 #define TCSADRAIN 3 #define TCSADFLUSH 4 #define TIOCPKT 6 #define TIOCPKT_DATA 0 #define TIOCPKT_FLUSHREAD 1 #define TIOCPKT_FLUSHWRITE 2 #define TIOCPKT_STOP 4 #define TIOCPKT_START 8 #define TIOCPKT_NOSTOP 16 #define TIOCPKT_DOSTOP 32 #define CTRL(ch) ((ch)&0x1F) #define CNUL 0 #define CDEL 0x0007f #define CESC '\\' #define CINTR CTRL('C') #define CQUIT 0x0001c #define CERASE CTRL('H') #define CKILL CTRL('U') #define CEOT CTRL('D') #define CEOL 0 #define CEOL2 0 #define CEOF CTRL('D') #define CSTART CTRL('Q') #define CSTOP CTRL('S') #define CSWTCH 0x0001a #define NSWTCH 0 #define CSUSP CTRL('Z') #define CDSUSP CTRL('Y') #define CRPRNT CTRL('R') #define CFLUSH CTRL('O') #define CWERASE CTRL('W') #define CLNEXT CTRL('V') /* iflag bits */ #define IGNBRK 0x00001 #define BRKINT 0x00002 #define IGNPAR 0x00004 #define IMAXBEL 0x00008 #define INPCK 0x00010 #define ISTRIP 0x00020 #define INLCR 0x00040 #define IGNCR 0x00080 #define ICRNL 0x00100 #define IXON 0x00400 #define IXOFF 0x01000 #define IUCLC 0x04000 #define IXANY 0x08000 #define PARMRK 0x10000 /* oflag bits */ #define OPOST 0x00001 #define OLCUC 0x00002 #define OCRNL 0x00004 #define ONLCR 0x00008 #define ONOCR 0x00010 #define ONLRET 0x00020 #define OFILL 0x00040 #define CRDLY 0x00180 #define CR0 0x00000 #define CR1 0x00080 #define CR2 0x00100 #define CR3 0x00180 #define NLDLY 0x00200 #define NL0 0x00000 #define NL1 0x00200 #define BSDLY 0x00400 #define BS0 0x00000 #define BS1 0x00400 #define TABDLY 0x01800 #define TAB0 0x00000 #define TAB1 0x00800 #define TAB2 0x01000 #define TAB3 0x01800 #define XTABS 0x01800 #define VTDLY 0x02000 #define VT0 0x00000 #define VT1 0x02000 #define FFDLY 0x04000 #define FF0 0x00000 #define FF1 0x04000 #define OFDEL 0x08000 /* cflag bits */ /* Baud rate values. These must fit in speed_t, which is unsigned char. See also the extended baud rates below. These baud rates set an additional bit. */ #define CBAUD 0x0100f #define B0 0x00000 #define B50 0x00001 #define B75 0x00002 #define B110 0x00003 #define B134 0x00004 #define B150 0x00005 #define B200 0x00006 #define B300 0x00007 #define B600 0x00008 #define B1200 0x00009 #define B1800 0x0000a #define B2400 0x0000b #define B4800 0x0000c #define B9600 0x0000d #define B19200 0x0000e #define B38400 0x0000f #define CSIZE 0x00030 #define CS5 0x00000 #define CS6 0x00010 #define CS7 0x00020 #define CS8 0x00030 #define CSTOPB 0x00040 #define CREAD 0x00080 #define PARENB 0x00100 #define PARODD 0x00200 #define HUPCL 0x00400 #define CLOCAL 0x00800 #define CBAUDEX 0x0100f #define B57600 0x01001 #define B115200 0x01002 #define B128000 0x01003 #define B230400 0x01004 #define B256000 0x01005 #define CRTSXOFF 0x04000 #define CRTSCTS 0x08000 /* lflag bits */ #define ISIG 0x0001 #define ICANON 0x0002 #define ECHO 0x0004 #define ECHOE 0x0008 #define ECHOK 0x0010 #define ECHONL 0x0020 #define NOFLSH 0x0040 #define TOSTOP 0x0080 #define IEXTEN 0x0100 #define FLUSHO 0x0200 #define ECHOKE 0x0400 #define ECHOCTL 0x0800 #define VDISCARD 1 #define VEOL 2 #define VEOL2 3 #define VEOF 4 #define VERASE 5 #define VINTR 6 #define VKILL 7 #define VLNEXT 8 #define VMIN 9 #define VQUIT 10 #define VREPRINT 11 #define VSTART 12 #define VSTOP 13 #define VSUSP 14 #define VSWTC 15 #define VTIME 16 #define VWERASE 17 #define NCCS 18 /* `c_cc' member of 'struct termios' structure can be disabled by using the value _POSIX_VDISABLE. */ #define _POSIX_VDISABLE '\0' /* Compare a character C to a value VAL from the `c_cc' array in a `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it. */ #define CCEQ(val, c) ((c) == (val) && (val) != _POSIX_VDISABLE) typedef unsigned char cc_t; typedef unsigned int tcflag_t; typedef unsigned int speed_t; typedef unsigned short otcflag_t; typedef unsigned char ospeed_t; struct termios { tcflag_t c_iflag; tcflag_t c_oflag; tcflag_t c_cflag; tcflag_t c_lflag; char c_line; cc_t c_cc[NCCS]; speed_t c_ispeed; speed_t c_ospeed; }; #define termio termios #define cfgetospeed(tp) ((tp)->c_ospeed) #define cfgetispeed(tp) ((tp)->c_ispeed) #define cfsetospeed(tp,s) (((tp)->c_ospeed = (s)), 0) #define cfsetispeed(tp,s) (((tp)->c_ispeed = (s)), 0) #ifdef __cplusplus extern "C" { #endif int tcgetattr (int, struct termios *); int tcsetattr (int, int, const struct termios *); int tcsendbreak (int, int); int tcdrain (int); int tcflush (int, int); int tcflow (int, int); #ifdef __cplusplus } #endif /* Extra stuff to make porting stuff easier. */ struct winsize { unsigned short ws_row, ws_col; unsigned short ws_xpixel, ws_ypixel; }; #define TIOCGWINSZ (('T' << 8) | 1) #define TIOCSWINSZ (('T' << 8) | 2) #define TIOCLINUX (('T' << 8) | 3) #endif /* _SYS_TERMIOS_H */ apcupsd-3.14.14/src/win32/compat/sys/types.h000066400000000000000000000021611274230402600204720ustar00rootroot00000000000000// Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // // Copyright (C) 2004-2006 Kern Sibbald // Copyright (C) 2014 Adam Kropelin // // 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., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1335, USA. #ifndef __COMPAT_SYS_TYPES_H_ #define __COMPAT_SYS_TYPES_H_ #include_next struct passwd { char *pw_name; }; struct group { char *foo; }; #endif /* __COMPAT_SYS_TYPES_H_ */ apcupsd-3.14.14/src/win32/compat/sys/wait.h000066400000000000000000000016761274230402600203040ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __WAIT_H_ #define __WAIT_H_ #define WNOHANG 0 #define WIFEXITED(x) 0 #define WEXITSTATUS(x) x #define WIFSIGNALED(x) 0 #ifdef __cplusplus extern "C" { #endif int waitpid(int, int *, int); #ifdef __cplusplus }; #endif #endif /* __WAIT_H_ */ apcupsd-3.14.14/src/win32/compat/syslog.c000066400000000000000000000044261274230402600200310ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include "winapi.h" /* Implement syslog() using Win32 Event Service */ void openlog(const char *app, int, int) {} void closelog(void) {} void syslog(int type, const char *fmt, ...) { va_list arg_ptr; char message[1024]; HANDLE heventsrc; char* strings[32]; WORD wtype; va_start(arg_ptr, fmt); message[0] = '\n'; message[1] = '\n'; vsnprintf(message+2, sizeof(message)-2, fmt, arg_ptr); va_end(arg_ptr); strings[0] = message; // Convert syslog type to Win32 type. This mapping is somewhat arbitrary // since there are many more LOG_* types than EVENTLOG_* types. switch (type) { case LOG_ERR: wtype = EVENTLOG_ERROR_TYPE; break; case LOG_CRIT: case LOG_ALERT: case LOG_WARNING: wtype = EVENTLOG_WARNING_TYPE; break; default: wtype = EVENTLOG_INFORMATION_TYPE; break; } // Use event logging to log the error heventsrc = RegisterEventSource(NULL, "Apcupsd"); if (heventsrc != NULL) { ReportEvent( heventsrc, // handle of event source wtype, // event type 0, // event category 0, // event ID NULL, // current user's SID 1, // strings in 'strings' 0, // no bytes of raw data (const char **)strings, // array of error strings NULL); // no raw data DeregisterEventSource(heventsrc); } } apcupsd-3.14.14/src/win32/compat/syslog.h000066400000000000000000000013401274230402600200260ustar00rootroot00000000000000#ifndef _SYSLOG_H #define _SYSLOG_H #define LOG_DAEMON 0 #define LOG_ERR 1 #define LOG_CRIT 2 #define LOG_ALERT 3 #define LOG_WARNING 4 #define LOG_NOTICE 5 #define LOG_INFO 6 #define LOG_LOCAL0 10 #define LOG_LOCAL1 11 #define LOG_LOCAL2 12 #define LOG_LOCAL3 13 #define LOG_LOCAL4 14 #define LOG_LOCAL5 15 #define LOG_LOCAL6 16 #define LOG_LOCAL7 17 #define LOG_LPR 20 #define LOG_MAIL 21 #define LOG_NEWS 22 #define LOG_UUCP 23 #define LOG_USER 24 #define LOG_CONS 0 #define LOG_PID 0 #ifdef __cplusplus extern "C" { #endif void syslog(int type, const char *fmt, ...); void openlog(const char *app, int, int); void closelog(void); #ifdef __cplusplus }; #endif #endif /* _SYSLOG_H */ apcupsd-3.14.14/src/win32/compat/tcflush.c000066400000000000000000000023331274230402600201540ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include #include "winapi.h" int tcflush(int fd, int queue_selector) { HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == 0) { errno = EBADF; return -1; } DWORD flags = 0; switch (queue_selector) { case TCIFLUSH: flags |= PURGE_RXCLEAR; break; case TCOFLUSH: flags |= PURGE_TXCLEAR; break; case TCIOFLUSH: flags |= PURGE_RXCLEAR; flags |= PURGE_TXCLEAR; break; } PurgeComm(h, flags); return 0; } apcupsd-3.14.14/src/win32/compat/tcgetattr.c000066400000000000000000000045641274230402600205150ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include #include "winapi.h" /* Convert Win32 baud constants to POSIX constants */ static int posixbaud(DWORD baud) { switch(baud) { case CBR_110: return B110; case CBR_300: return B300; case CBR_600: return B600; case CBR_1200: return B1200; case CBR_2400: default: return B2400; case CBR_4800: return B4800; case CBR_9600: return B9600; case CBR_19200: return B19200; case CBR_38400: return B38400; case CBR_57600: return B57600; case CBR_115200: return B115200; case CBR_128000: return B128000; case CBR_256000: return B256000; } } /* Convert Win32 bytesize constants to POSIX constants */ static int posixsize(BYTE size) { switch(size) { case 5: return CS5; case 6: return CS6; case 7: return CS7; case 8: default: return CS8; } } int tcgetattr (int fd, struct termios *out) { DCB dcb; dcb.DCBlength = sizeof(DCB); HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == 0) { errno = EBADF; return -1; } GetCommState(h, &dcb); memset(out, 0, sizeof(*out)); out->c_cflag |= posixbaud(dcb.BaudRate); out->c_cflag |= posixsize(dcb.ByteSize); if (dcb.StopBits == TWOSTOPBITS) out->c_cflag |= CSTOPB; if (dcb.fParity) { out->c_cflag |= PARENB; if (dcb.Parity == ODDPARITY) out->c_cflag |= PARODD; } if (!dcb.fOutxCtsFlow && !dcb.fOutxDsrFlow && !dcb.fDsrSensitivity) out->c_cflag |= CLOCAL; if (dcb.fOutX) out->c_iflag |= IXON; if (dcb.fInX) out->c_iflag |= IXOFF; return 0; } apcupsd-3.14.14/src/win32/compat/tcsetattr.c000066400000000000000000000055571274230402600205340ustar00rootroot00000000000000/* * Copyright (C) 2006 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include #include "winapi.h" /* Convert POSIX baud constants to Win32 constants */ static DWORD winbaud(int baud) { switch(baud) { case B110: return CBR_110; case B300: return CBR_300; case B600: return CBR_600; case B1200: return CBR_1200; case B2400: default: return CBR_2400; case B4800: return CBR_4800; case B9600: return CBR_9600; case B19200: return CBR_19200; case B38400: return CBR_38400; case B57600: return CBR_57600; case B115200: return CBR_115200; case B128000: return CBR_128000; case B256000: return CBR_256000; } } /* Convert POSIX bytesize constants to Win32 constants */ static BYTE winsize(int size) { switch(size) { case CS5: return 5; case CS6: return 6; case CS7: return 7; case CS8: default: return 8; } } int tcsetattr (int fd, int optional_actions, const struct termios *in) { DCB dcb; dcb.DCBlength = sizeof(DCB); HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == 0) { errno = EBADF; return -1; } GetCommState(h, &dcb); dcb.fBinary = 1; dcb.BaudRate = winbaud(in->c_cflag & CBAUD); dcb.ByteSize = winsize(in->c_cflag & CSIZE); dcb.StopBits = in->c_cflag & CSTOPB ? TWOSTOPBITS : ONESTOPBIT; if (in->c_cflag & PARENB) { dcb.fParity = 1; dcb.Parity = in->c_cflag & PARODD ? ODDPARITY : EVENPARITY; } else { dcb.fParity = 0; dcb.Parity = NOPARITY; } if (in->c_cflag & CLOCAL) { dcb.fOutxCtsFlow = 0; dcb.fOutxDsrFlow = 0; dcb.fDsrSensitivity = 0; } dcb.fOutX = !!(in->c_iflag & IXON); dcb.fInX = !!(in->c_iflag & IXOFF); SetCommState(h, &dcb); /* If caller wants a read() timeout, set that up */ if (in->c_cc[VMIN] == 0 && in->c_cc[VTIME] != 0) { COMMTIMEOUTS ct; ct.ReadIntervalTimeout = MAXDWORD; ct.ReadTotalTimeoutMultiplier = MAXDWORD; ct.ReadTotalTimeoutConstant = in->c_cc[VTIME] * 100; ct.WriteTotalTimeoutMultiplier = 0; ct.WriteTotalTimeoutConstant = 0; SetCommTimeouts(h, &ct); } return 0; } apcupsd-3.14.14/src/win32/compat/termios.h000066400000000000000000000001341274230402600201700ustar00rootroot00000000000000#ifdef __cplusplus extern "C" { #endif #include #ifdef __cplusplus } #endif apcupsd-3.14.14/src/win32/compat/unistd.h000066400000000000000000000024611274230402600200210ustar00rootroot00000000000000// Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // // Copyright (C) 2004-2006 Kern Sibbald // Copyright (C) 2014 Adam Kropelin // // 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., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1335, USA. #ifndef __COMPAT_UNISTD_H_ #define __COMPAT_UNISTD_H_ #include_next #define _PC_PATH_MAX 1 #define _PC_NAME_MAX 2 #ifdef __cplusplus extern "C" { #endif long pathconf(const char *, int); #define getpid _getpid #define getppid() 0 unsigned int sleep(unsigned int seconds); #define getuid() 0 #define getgid() 0 #ifdef __cplusplus }; #endif #endif /* __COMPAT_UNISTD_H_ */ apcupsd-3.14.14/src/win32/compat/waitpid.c000066400000000000000000000020261274230402600201440ustar00rootroot00000000000000// Copyright transferred from Raider Solutions, Inc to // Kern Sibbald and John Walker by express permission. // // Copyright (C) 2004-2006 Kern Sibbald // Copyright (C) 2014 Adam Kropelin // // 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., 51 Franklin Street, Fifth Floor, Boston, // MA 02110-1335, USA. #include #include int waitpid(int, int*, int) { errno = ENOSYS; return -1; } apcupsd-3.14.14/src/win32/compat/winapi.c000066400000000000000000000136511274230402600200000ustar00rootroot00000000000000/* * Windows APIs that are different for each system. * We use pointers to the entry points so that a * single binary will run on all Windows systems. * * Kern Sibbald MMIII */ /* Copyright (C) 2003-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as amended with additional clauses defined in the file LICENSE in the main source directory. 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 the file LICENSE for additional details. */ #include "apc.h" #include "winapi.h" /* Platform version info */ OSVERSIONINFO g_os_version_info; OSVERSION g_os_version; /* API Pointers */ t_OpenProcessToken p_OpenProcessToken = NULL; t_AdjustTokenPrivileges p_AdjustTokenPrivileges = NULL; t_LookupPrivilegeValue p_LookupPrivilegeValue = NULL; t_SetProcessShutdownParameters p_SetProcessShutdownParameters = NULL; t_CreateFileA p_CreateFileA = NULL; t_CreateDirectoryA p_CreateDirectoryA; t_GetFileAttributesA p_GetFileAttributesA = NULL; t_GetFileAttributesExA p_GetFileAttributesExA = NULL; t_SetFileAttributesA p_SetFileAttributesA = NULL; t_FindFirstFileA p_FindFirstFileA = NULL; t_FindNextFileA p_FindNextFileA = NULL; t_SetCurrentDirectoryA p_SetCurrentDirectoryA = NULL; t_GetCurrentDirectoryA p_GetCurrentDirectoryA = NULL; void InitWinAPIWrapper() { HMODULE hLib = LoadLibraryA("KERNEL32.DLL"); if (hLib) { /* create file calls */ p_CreateFileA = (t_CreateFileA) GetProcAddress(hLib, "CreateFileA"); p_CreateDirectoryA = (t_CreateDirectoryA) GetProcAddress(hLib, "CreateDirectoryA"); /* attribute calls */ p_GetFileAttributesA = (t_GetFileAttributesA) GetProcAddress(hLib, "GetFileAttributesA"); p_GetFileAttributesExA = (t_GetFileAttributesExA) GetProcAddress(hLib, "GetFileAttributesExA"); p_SetFileAttributesA = (t_SetFileAttributesA) GetProcAddress(hLib, "SetFileAttributesA"); /* process calls */ p_SetProcessShutdownParameters = (t_SetProcessShutdownParameters) GetProcAddress(hLib, "SetProcessShutdownParameters"); /* find files */ p_FindFirstFileA = (t_FindFirstFileA) GetProcAddress(hLib, "FindFirstFileA"); p_FindNextFileA = (t_FindNextFileA) GetProcAddress(hLib, "FindNextFileA"); /* set and get directory */ p_SetCurrentDirectoryA = (t_SetCurrentDirectoryA) GetProcAddress(hLib, "SetCurrentDirectoryA"); p_GetCurrentDirectoryA = (t_GetCurrentDirectoryA) GetProcAddress(hLib, "GetCurrentDirectoryA"); FreeLibrary(hLib); } hLib = LoadLibraryA("ADVAPI32.DLL"); if (hLib) { p_OpenProcessToken = (t_OpenProcessToken) GetProcAddress(hLib, "OpenProcessToken"); p_AdjustTokenPrivileges = (t_AdjustTokenPrivileges) GetProcAddress(hLib, "AdjustTokenPrivileges"); p_LookupPrivilegeValue = (t_LookupPrivilegeValue) GetProcAddress(hLib, "LookupPrivilegeValueA"); FreeLibrary(hLib); } // Get the current OS version memset(&g_os_version_info, 0, sizeof(g_os_version_info)); g_os_version_info.dwOSVersionInfoSize = sizeof(g_os_version_info); GetVersionEx(&g_os_version_info); // Convert OS version to ordered enumeration if (g_os_version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { // VER_PLATFORM_WIN32_WINDOWS... // // WINDOWS 95: 4.0 // WINDOWS 98: 4.10 // WINDOWS ME: 4.90 // switch (g_os_version_info.dwMinorVersion) { case 0: g_os_version = WINDOWS_95; break; case 10: g_os_version = WINDOWS_98; break; default: case 90: g_os_version = WINDOWS_ME; break; } } else // if (g_os_version_info.dwPlatformId == VER_PLATFORM_WIN32_NT) { // VER_PLATFORM_WIN32_NT... // // WINDOWS NT: 4.0 // WINDOWS 2000: 5.0 // WINDOWS XP: 5.1 // WINDOWS 2003: 5.2 // WINDOWS VISTA: 6.0 // switch (g_os_version_info.dwMajorVersion) { case 4: g_os_version = WINDOWS_NT; break; case 5: switch (g_os_version_info.dwMinorVersion) { case 0: g_os_version = WINDOWS_2000; break; case 1: g_os_version = WINDOWS_XP; break; default: case 2: g_os_version = WINDOWS_2003; break; } break; default: case 6: g_os_version = WINDOWS_VISTA; break; } } } // Add the requested access to the given kernel object handle BOOL GrantAccess(HANDLE h, ACCESS_MASK access, TRUSTEE_TYPE type, LPTSTR name) { DWORD rc; // Obtain current DACL from object ACL *dacl; SECURITY_DESCRIPTOR *sd; rc = GetSecurityInfo(h, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, NULL, &sd); if (rc != ERROR_SUCCESS) return false; // Add requested access to DACL EXPLICIT_ACCESS ea; ea.grfAccessPermissions = access; ea.grfAccessMode = GRANT_ACCESS; ea.grfInheritance = NO_INHERITANCE; ea.Trustee.pMultipleTrustee = FALSE; ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; ea.Trustee.TrusteeForm = TRUSTEE_IS_NAME; ea.Trustee.TrusteeType = type; ea.Trustee.ptstrName = name; ACL *newdacl; rc = SetEntriesInAcl(1, &ea, dacl, &newdacl); if (rc != ERROR_SUCCESS) { LocalFree(sd); return false; } // Set new DACL on object rc = SetSecurityInfo(h, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, newdacl, NULL); // Done with structs LocalFree(newdacl); LocalFree(sd); return rc == ERROR_SUCCESS; } apcupsd-3.14.14/src/win32/compat/winapi.h000066400000000000000000000073531274230402600200070ustar00rootroot00000000000000/* * Windows APIs that are different for each system. * We use pointers to the entry points so that a * single binary will run on all Windows systems. * * Kern Sibbald MMIII */ /* Copyright (C) 2003-2006 Kern Sibbald This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as amended with additional clauses defined in the file LICENSE in the main source directory. 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 the file LICENSE for additional details. */ #ifndef __WINAPI_H #define __WINAPI_H #include #include #include #include // OS version enumeration // Keep these in order so >= comparisons work typedef enum { WINDOWS_95, WINDOWS_98, WINDOWS_ME, WINDOWS_NT, WINDOWS_2000, WINDOWS_XP, WINDOWS_2003, WINDOWS_VISTA } OSVERSION; /* Platform version info */ extern OSVERSIONINFO g_os_version_info; extern OSVERSION g_os_version; // unicode enabling of win 32 needs some defines and functions // using an average of 3 bytes per character is probably fine in // practice but I believe that Windows actually uses UTF-16 encoding // as opposed to UCS2 which means characters 0x10000-0x10ffff are // valid and result in 4 byte UTF-8 encodings. #define MAX_PATH_UTF8 MAX_PATH*4 // strict upper bound on UTF-16 to UTF-8 conversion // from // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/fs/getfileattributesex.asp // In the ANSI version of this function, the name is limited to // MAX_PATH characters. To extend this limit to 32,767 wide // characters, call the Unicode version of the function and prepend // "\\?\" to the path. For more information, see Naming a File. #define MAX_PATH_W 32767 /* In ADVAPI32.DLL */ typedef BOOL (WINAPI * t_OpenProcessToken)(HANDLE, DWORD, PHANDLE); typedef BOOL (WINAPI * t_AdjustTokenPrivileges)(HANDLE, BOOL, PTOKEN_PRIVILEGES, DWORD, PTOKEN_PRIVILEGES, PDWORD); typedef BOOL (WINAPI * t_LookupPrivilegeValue)(LPCTSTR, LPCTSTR, PLUID); extern t_OpenProcessToken p_OpenProcessToken; extern t_AdjustTokenPrivileges p_AdjustTokenPrivileges; extern t_LookupPrivilegeValue p_LookupPrivilegeValue; /* In KERNEL32.DLL */ typedef BOOL (WINAPI * t_GetFileAttributesExA)(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID); typedef DWORD (WINAPI * t_GetFileAttributesA)(LPCSTR); typedef BOOL (WINAPI * t_SetFileAttributesA)(LPCSTR, DWORD); typedef HANDLE (WINAPI * t_CreateFileA) (LPCSTR, DWORD ,DWORD, LPSECURITY_ATTRIBUTES, DWORD , DWORD, HANDLE); typedef BOOL (WINAPI * t_CreateDirectoryA) (LPCSTR, LPSECURITY_ATTRIBUTES); typedef BOOL (WINAPI * t_SetProcessShutdownParameters)(DWORD, DWORD); typedef HANDLE (WINAPI * t_FindFirstFileA) (LPCSTR, LPWIN32_FIND_DATAA); typedef BOOL (WINAPI * t_FindNextFileA) (HANDLE, LPWIN32_FIND_DATAA); typedef BOOL (WINAPI * t_SetCurrentDirectoryA) (LPCSTR); typedef DWORD (WINAPI * t_GetCurrentDirectoryA) (DWORD, LPSTR); extern t_GetFileAttributesA p_GetFileAttributesA; extern t_GetFileAttributesExA p_GetFileAttributesExA; extern t_SetFileAttributesA p_SetFileAttributesA; extern t_CreateFileA p_CreateFileA; extern t_CreateDirectoryA p_CreateDirectoryA; extern t_SetProcessShutdownParameters p_SetProcessShutdownParameters; extern t_FindFirstFileA p_FindFirstFileA; extern t_FindNextFileA p_FindNextFileA; extern t_SetCurrentDirectoryA p_SetCurrentDirectoryA; extern t_GetCurrentDirectoryA p_GetCurrentDirectoryA; void InitWinAPIWrapper(); BOOL GrantAccess(HANDLE h, ACCESS_MASK access, TRUSTEE_TYPE type, LPTSTR name); #endif /* __WINAPI_H */ apcupsd-3.14.14/src/win32/compat/winsock.h000066400000000000000000000000251274230402600201620ustar00rootroot00000000000000#include apcupsd-3.14.14/src/win32/compat/winusb.h000066400000000000000000000100031274230402600200110ustar00rootroot00000000000000#ifndef __WINUSB_H #define __WINUSB_H #include "ddk/usb100.h" #include "ddk/usbioctl.h" /* * Some of the EX stuff is not yet in MinGW => define it */ #ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX #define USB_GET_NODE_CONNECTION_INFORMATION_EX 274 #endif #ifndef IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, \ METHOD_BUFFERED, FILE_ANY_ACCESS) #endif #ifndef USB_NODE_CONNECTION_INFORMATION_EX typedef struct _USB_NODE_CONNECTION_INFORMATION_EX { ULONG ConnectionIndex; USB_DEVICE_DESCRIPTOR DeviceDescriptor; UCHAR CurrentConfigurationValue; UCHAR Speed; BOOLEAN DeviceIsHub; USHORT DeviceAddress; ULONG NumberOfOpenPipes; USB_CONNECTION_STATUS ConnectionStatus; USB_PIPE_INFO PipeList[0]; } USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX; #endif #ifndef USB_HUB_CAP_FLAGS typedef union _USB_HUB_CAP_FLAGS { ULONG ul; struct { ULONG HubIsHighSpeedCapable:1; ULONG HubIsHighSpeed:1; ULONG HubIsMultiTtCapable:1; ULONG HubIsMultiTt:1; ULONG HubIsRoot:1; ULONG HubIsArmedWakeOnConnect:1; ULONG ReservedMBZ:26; }; } USB_HUB_CAP_FLAGS, *PUSB_HUB_CAP_FLAGS; #endif #ifndef USB_HUB_CAPABILITIES_EX typedef struct _USB_HUB_CAPABILITIES_EX { USB_HUB_CAP_FLAGS CapabilityFlags; } USB_HUB_CAPABILITIES_EX, *PUSB_HUB_CAPABILITIES_EX; #endif #ifndef USB_GET_HUB_CAPABILITIES_EX #define USB_GET_HUB_CAPABILITIES_EX 276 #endif #ifndef IOCTL_USB_GET_HUB_CAPABILITIES_EX #define IOCTL_USB_GET_HUB_CAPABILITIES_EX \ CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, \ METHOD_BUFFERED, FILE_ANY_ACCESS ) #endif /* * WinUSB macros - from libusb-win32 1.x */ #define DLL_DECLARE(api, ret, name, args) \ typedef ret (api * __dll_##name##_t)args; \ static __dll_##name##_t name #define DLL_LOAD(dll, name) \ do { \ HMODULE h = GetModuleHandle(#dll); \ if(!h) \ h = LoadLibrary(#dll); \ if(!h) \ break; \ if((name = (__dll_##name##_t)GetProcAddress(h, #name))) \ break; \ if((name = (__dll_##name##_t)GetProcAddress(h, #name "A"))) \ break; \ if((name = (__dll_##name##_t)GetProcAddress(h, #name "W"))) \ break; \ } while(0) /* winusb.dll interface */ #define SHORT_PACKET_TERMINATE 0x01 #define AUTO_CLEAR_STALL 0x02 #define PIPE_TRANSFER_TIMEOUT 0x03 #define IGNORE_SHORT_PACKETS 0x04 #define ALLOW_PARTIAL_READS 0x05 #define AUTO_FLUSH 0x06 #define RAW_IO 0x07 #define MAXIMUM_TRANSFER_SIZE 0x08 #define AUTO_SUSPEND 0x81 #define SUSPEND_DELAY 0x83 #define DEVICE_SPEED 0x01 #define LowSpeed 0x01 #define FullSpeed 0x02 #define HighSpeed 0x03 typedef enum _USBD_PIPE_TYPE { UsbdPipeTypeControl, UsbdPipeTypeIsochronous, UsbdPipeTypeBulk, UsbdPipeTypeInterrupt } USBD_PIPE_TYPE; typedef struct { USBD_PIPE_TYPE PipeType; UCHAR PipeId; USHORT MaximumPacketSize; UCHAR Interval; } WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION; #pragma pack(1) typedef struct { UCHAR RequestType; UCHAR Request; USHORT Value; USHORT Index; USHORT Length; } WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET; #pragma pack() typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE; #endif // __WINUSB_H apcupsd-3.14.14/src/win32/email.c000066400000000000000000000034071274230402600163130ustar00rootroot00000000000000/* * Dumb program to send an email message * * Called: * email -s "Subject" address@somewhere.com -m "Body of text" * * Kern Sibbald, October MM */ #include #include #include int main(int argc, char **argv) { int i; ULONG err; MapiRecipDesc recip; char addr[100]; char default_msg[] = "Apcupsd message"; char default_text[] = "No text specified.\n"; MapiMessage emsg = {0, default_msg, /* default subject */ default_text, /* default message text */ NULL, NULL, NULL, 0, NULL, 1, &recip, 0, NULL}; char default_name[] = "root"; char default_addr[] = "SMTP:root"; recip.ulReserved = 0; recip.ulRecipClass = MAPI_TO; recip.lpszName = default_name; /* default name */ recip.lpszAddress = default_addr; /* default address */ recip.ulEIDSize = 0; recip.lpEntryID = NULL; for (i=1; i const char *InstanceManager::INSTANCES_KEY = "Software\\Apcupsd\\Apctray\\instances"; const MonitorConfig InstanceManager::DEFAULT_CONFIG = { "", // id "127.0.0.1", // host 3551, // port 5, // refresh true // popups }; InstanceManager::InstanceManager(HINSTANCE appinst) : _appinst(appinst) { } InstanceManager::~InstanceManager() { // Destroy all instances while (!_instances.empty()) { alist::iterator inst = _instances.begin(); inst->menu->Destroy(); delete inst->menu; _instances.remove(inst); } } void InstanceManager::CreateMonitors() { alist unsorted; InstanceConfig config; // Open registry key for instance configs HKEY apctray; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, INSTANCES_KEY, 0, KEY_READ, &apctray) == ERROR_SUCCESS) { // Iterate though all instance keys, reading the config for each // instance into a list. int i = 0; char name[128]; DWORD len = sizeof(name); while (RegEnumKeyEx(apctray, i++, name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { unsorted.append(ReadConfig(apctray, name)); len = sizeof(name); } RegCloseKey(apctray); // Now that we've read all instance configs, place them in a sorted list. // This is a really inefficient algorithm, but even O(N^2) is tolerable // for small N. alist::iterator iter, lowest; while (!unsorted.empty()) { lowest = unsorted.begin(); for (iter = unsorted.begin(); iter != unsorted.end(); ++iter) { if (iter->order < lowest->order) lowest = iter; } _instances.append(*lowest); unsorted.remove(lowest); } } // If no instances were found, create a default one if (_instances.empty()) { InstanceConfig config; config.mcfg = DEFAULT_CONFIG; config.mcfg.id = CreateId(); _instances.append(config); Write(); } // Loop thru sorted instance list and create an upsMenu for each alist::iterator iter; for (iter = _instances.begin(); iter != _instances.end(); ++iter) iter->menu = new upsMenu(_appinst, iter->mcfg, &_balmgr, this); } InstanceManager::InstanceConfig InstanceManager::ReadConfig(HKEY key, const char *id) { InstanceConfig config; config.mcfg = DEFAULT_CONFIG; config.mcfg.id = id; // Read instance config from registry HKEY subkey; if (RegOpenKeyEx(key, id, 0, KEY_READ, &subkey) == ERROR_SUCCESS) { RegQueryString(subkey, "host", config.mcfg.host); RegQueryDWORD(subkey, "port", config.mcfg.port); RegQueryDWORD(subkey, "refresh", config.mcfg.refresh); RegQueryDWORD(subkey, "popups", config.mcfg.popups); RegQueryDWORD(subkey, "order", config.order); RegCloseKey(subkey); } return config; } void InstanceManager::Write() { // Remove all existing instances from the registry HKEY apctray; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, INSTANCES_KEY, 0, KEY_READ|KEY_WRITE, &apctray) == ERROR_SUCCESS) { // Iterate though all apctray keys locating instance keys of the form // "instanceN". Add the id of each key to a list. We don't want to // remove keys while we're enumerating them since Win32 docs say to not // change the key while enumerating it. int i = 0; char name[128]; DWORD len = sizeof(name); alist ids; while (RegEnumKeyEx(apctray, i++, name, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { ids.append(name); len = sizeof(name); } // Now that we have a list of all ids, loop thru and delete each one alist::iterator iter; for (iter = ids.begin(); iter != ids.end(); ++iter) RegDeleteKey(apctray, *iter); } else { // No apctray\instances key (and therefore no instances) yet if (RegCreateKey(HKEY_LOCAL_MACHINE, INSTANCES_KEY, &apctray) != ERROR_SUCCESS) return; } // Write out instances. Our instance list is in sorted order but may // have gaps in the numbering, so regenerate 'order' value, ignoring what's // in the InstanceConfig.order field. int count = 0; alist::iterator iter; for (iter = _instances.begin(); iter != _instances.end(); ++iter) { // Create the instance and populate it HKEY instkey; if (RegCreateKey(apctray, iter->mcfg.id, &instkey) == ERROR_SUCCESS) { RegSetString(instkey, "host", iter->mcfg.host); RegSetDWORD(instkey, "port", iter->mcfg.port); RegSetDWORD(instkey, "refresh", iter->mcfg.refresh); RegSetDWORD(instkey, "popups", iter->mcfg.popups); RegSetDWORD(instkey, "order", count); RegCloseKey(instkey); count++; } } RegCloseKey(apctray); } alist::iterator InstanceManager::FindInstance(const char *id) { alist::iterator iter; for (iter = _instances.begin(); iter != _instances.end(); ++iter) { if (iter->mcfg.id == id) return iter; } return _instances.end(); } int InstanceManager::RemoveInstance(const char *id) { alist::iterator inst = FindInstance(id); if (inst != _instances.end()) { inst->menu->Destroy(); delete inst->menu; _instances.remove(inst); Write(); } return _instances.size(); } void InstanceManager::AddInstance() { InstanceConfig config; config.mcfg = DEFAULT_CONFIG; config.mcfg.id = CreateId(); config.menu = new upsMenu(_appinst, config.mcfg, &_balmgr, this); _instances.append(config); Write(); } void InstanceManager::UpdateInstance(const MonitorConfig &mcfg) { alist::iterator inst = FindInstance(mcfg.id); if (inst != _instances.end()) { inst->mcfg = mcfg; inst->menu->Reconfigure(mcfg); Write(); } } void InstanceManager::RemoveAll() { while (!_instances.empty()) RemoveInstance(_instances.begin()->mcfg.id); } void InstanceManager::ResetInstances() { alist::iterator iter; for (iter = _instances.begin(); iter != _instances.end(); ++iter) iter->menu->Redraw(); } astring InstanceManager::CreateId() { // Create binary UUID UUID uuid; UuidCreate(&uuid); // Convert binary UUID to RPC string unsigned char *tmpstr; UuidToString(&uuid, &tmpstr); // Copy string UUID to astring and free RPC version astring uuidstr((char*)tmpstr); RpcStringFree(&tmpstr); return uuidstr; } bool InstanceManager::IsAutoStart() { HKEY hkey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ, &hkey) != ERROR_SUCCESS) return false; astring path; RegQueryString(hkey, "Apctray", path); RegCloseKey(hkey); return !path.empty(); } void InstanceManager::SetAutoStart(bool start) { HKEY runkey; if (start) { // Get the full path/filename of this executable char path[1024]; GetModuleFileName(NULL, path, sizeof(path)); // Add double quotes char cmd[1024]; snprintf(cmd, sizeof(cmd), "\"%s\"", path); // Open registry key for auto-run programs if (RegCreateKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", &runkey) != ERROR_SUCCESS) { return; } // Add apctray key RegSetString(runkey, "Apctray", cmd); } else { // Open registry key apctray HKEY runkey; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_READ|KEY_WRITE, &runkey) == ERROR_SUCCESS) { RegDeleteValue(runkey, "Apctray"); } } RegCloseKey(runkey); } bool InstanceManager::RegQueryDWORD(HKEY hkey, const char *name, DWORD &result) { DWORD data; DWORD len = sizeof(data); DWORD type; // Retrieve DWORD if (RegQueryValueEx(hkey, name, NULL, &type, (BYTE*)&data, &len) == ERROR_SUCCESS && type == REG_DWORD) { result = data; return true; } return false; } bool InstanceManager::RegQueryString(HKEY hkey, const char *name, astring &result) { char data[512]; // Arbitrary max DWORD len = sizeof(data); DWORD type; // Retrieve string if (RegQueryValueEx(hkey, name, NULL, &type, (BYTE*)data, &len) == ERROR_SUCCESS && type == REG_SZ) { result = data; return true; } return false; } void InstanceManager::RegSetDWORD(HKEY hkey, const char *name, DWORD value) { RegSetValueEx(hkey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(value)); } void InstanceManager::RegSetString(HKEY hkey, const char *name, const char *value) { RegSetValueEx(hkey, name, 0, REG_SZ, (BYTE*)value, strlen(value)+1); } apcupsd-3.14.14/src/win32/instmgr.h000066400000000000000000000040571274230402600167160ustar00rootroot00000000000000/* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include "astring.h" #include "alist.h" #include #ifndef __INSTMGR_H #define __INSTMGR_H #include "balloonmgr.h" class upsMenu; struct MonitorConfig { astring id; astring host; DWORD port; DWORD refresh; DWORD popups; }; class InstanceManager { public: InstanceManager(HINSTANCE appinst); ~InstanceManager(); void CreateMonitors(); int RemoveInstance(const char *id); void AddInstance(); void UpdateInstance(const MonitorConfig &mcfg); void RemoveAll(); void ResetInstances(); bool IsAutoStart(); void SetAutoStart(bool start); private: struct InstanceConfig { InstanceConfig() : menu(NULL), order(0) {} ~InstanceConfig() {} MonitorConfig mcfg; upsMenu *menu; DWORD order; }; void Write(); InstanceConfig ReadConfig(HKEY key, const char *id); alist::iterator FindInstance(const char *id); astring CreateId(); bool RegQueryDWORD(HKEY hkey, const char *name, DWORD &result); bool RegQueryString(HKEY key, const char *name, astring &result); void RegSetDWORD(HKEY key, const char *name, DWORD value); void RegSetString(HKEY key, const char *name, const char *value); static const char *INSTANCES_KEY; static const MonitorConfig DEFAULT_CONFIG; alist _instances; HINSTANCE _appinst; BalloonMgr _balmgr; }; #endif apcupsd-3.14.14/src/win32/listview.cpp000066400000000000000000000070561274230402600174360ustar00rootroot00000000000000/* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include #include "listview.h" ListView::ListView(HWND hwnd, UINT id, int cols) : _cols(cols) { _hwnd = GetDlgItem(hwnd, id); LVCOLUMN lvc; lvc.mask = LVCF_SUBITEM; for (int i = 0; i < cols; i++) { lvc.iSubItem = i; SendMessage(_hwnd, LVM_INSERTCOLUMN, i, (LONG)&lvc); } } int ListView::AppendItem(const char *text) { LVITEM lvi; lvi.mask = LVIF_TEXT; lvi.iItem = INT_MAX; lvi.iSubItem = 0; lvi.pszText = (char*)text; return SendMessage(_hwnd, LVM_INSERTITEM, 0, (LONG)&lvi); } void ListView::UpdateItem(int item, int sub, const char *text) { char str[256]; LVITEM lvi; lvi.mask = LVIF_TEXT; lvi.iItem = item; lvi.iSubItem = sub; lvi.pszText = str; lvi.cchTextMax = sizeof(str); int len = SendMessage(_hwnd, LVM_GETITEMTEXT, item, (LONG)&lvi); if (len == 0 || strcmp(str, text)) { lvi.pszText = (char*)text; SendMessage(_hwnd, LVM_SETITEMTEXT, item, (LONG)&lvi); } } int ListView::NumItems() { return SendMessage(_hwnd, LVM_GETITEMCOUNT, 0, 0); } void ListView::Autosize() { for (int i = 0; i < _cols; i++) SendMessage(_hwnd, LVM_SETCOLUMNWIDTH, i, LVSCW_AUTOSIZE); } void ListView::DeleteItem(int item) { SendMessage(_hwnd, LVM_DELETEITEM, item, 0); } void ListView::UpdateAll(alist* data[]) { // The simple way to update the listview would be to remove all items and // then add them again. However, that causes the control to flicker and the // scrollbar to reset to the top every time, which makes it pretty much // unusable. To prevent that, we update the items in-place, adding new ones // and removing unused ones as necessary. That way the scroll position stays // put and only the items that change are redrawn. // Get current item count and prepare to update the listview int num = NumItems(); int count = 0; // Add each line to the listview alist::const_iterator iter; for (iter = data[0]->begin(); iter != data[0]->end(); ++iter) { // Set main item (leftmost column). This will be an insert if there is no // existing item at this position or an update if an item already exists. if (count >= num) AppendItem(*iter); else UpdateItem(count, 0, *iter); // On to the next item count++; } // Remove any leftover items that are no longer needed. while (count < num) { DeleteItem(count); num--; } // Update remaining columns. This is always an update since main item // (leftmost column) is guaranteed to exist by code above. for (int i = 1; i < _cols; i++) { int count = 0; alist::const_iterator iter; for (iter = data[i]->begin(); iter != data[i]->end(); ++iter) UpdateItem(count++, i, *iter); } // Autosize listview columns Autosize(); } apcupsd-3.14.14/src/win32/listview.h000066400000000000000000000022011274230402600170660ustar00rootroot00000000000000/* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __LISTVIEW_H #define __LISTVIEW_H #include #include "astring.h" #include "alist.h" class ListView { public: ListView(HWND hwnd, UINT id, int cols); ~ListView() {} int AppendItem(const char *text); void UpdateItem(int item, int sub, const char *text); int NumItems(); void Autosize(); void DeleteItem(int item); void UpdateAll(alist* data[]); private: HWND _hwnd; int _cols; }; #endif apcupsd-3.14.14/src/win32/meter.cpp000066400000000000000000000030241274230402600166730ustar00rootroot00000000000000/* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #include #include #include "meter.h" Meter::Meter(HWND hwnd, UINT id, int warn, int critical, int level) : _warn(warn), _critical(critical), _level(level) { _hwnd = GetDlgItem(hwnd, id); } void Meter::Set(int level) { if (level == _level) return; SendMessage(_hwnd, PBM_SETPOS, level, 0); _level = level; // Figure out bar color. COLORREF color; if (_warn > _critical) { // Low is critical if (level > _warn) color = GREEN; else if (level > _critical) color = YELLOW; else color = RED; } else { // High is critical if (level >= _critical) color = RED; else if (level >= _warn) color = YELLOW; else color = GREEN; } SendMessage(_hwnd, PBM_SETBARCOLOR, 0, color); } apcupsd-3.14.14/src/win32/meter.h000066400000000000000000000021551274230402600163440ustar00rootroot00000000000000/* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __METER_H #define __METER_H #include class Meter { public: Meter(HWND hwnd, UINT id, int warn, int critical, int level = 0); ~Meter() {} void Set(int level); private: HWND _hwnd; int _warn; int _critical; int _level; static const COLORREF GREEN = RGB(115, 190, 49); static const COLORREF RED = RGB(214, 56, 57); static const COLORREF YELLOW = RGB(214, 186, 57); }; #endif apcupsd-3.14.14/src/win32/mymapi32.def000066400000000000000000000054201274230402600171760ustar00rootroot00000000000000LIBRARY MAPI32.DLL EXPORTS MAPISendMail@20 BuildDisplayTable@40 CbOfEncoded@4 CchOfEncoding@4 ChangeIdleRoutine@28 CloseIMsgSession@4 CreateIProp@24 CreateTable@36 DeinitMapiUtil@0 DeregisterIdleRoutine@4 EnableIdleRoutine@8 EncodeID@12 FBadColumnSet@4 FBadEntryList@4 FBadProp@4 FBadPropTag@4 FBadRestriction@4 FBadRglpNameID@8 FBadRglpszA@8 FBadRglpszW@8 FBadRow@4 FBadRowSet@4 FBadSortOrderSet@4 FBinFromHex@8 FDecodeID@12 FEqualNames@8 FPropCompareProp@12 FPropContainsProp@12 FPropExists@8 FreePadrlist@4 FreeProws@4 FtAdcFt@20 FtAddFt@16 FtDivFtBogus@20 FtMulDw@12 FtMulDwDw@8 FtNegFt@8 FtSubFt@16 FtgRegisterIdleRoutine@20 GetAttribIMsgOnIStg@12 GetTnefStreamCodepage GetTnefStreamCodepage@12 HexFromBin@12 HrAddColumns@16 HrAddColumnsEx@20 HrAllocAdviseSink@12 HrComposeEID@28 HrComposeMsgID@24 HrDecomposeEID@28 HrDecomposeMsgID@24 HrDispatchNotifications@4 HrEntryIDFromSz@12 HrGetOneProp@12 HrIStorageFromStream@16 HrQueryAllRows@24 HrSetOneProp@8 HrSzFromEntryID@12 HrThisThreadAdviseSink@8 HrValidateIPMSubtree@20 HrValidateParameters@8 InstallFilterHook@4 IsBadBoundedStringPtr@8 LAUNCHWIZARD LPropCompareProp@8 LaunchWizard@20 LpValFindProp@12 MAPIAdminProfiles MAPIAdminProfiles@8 MAPIAllocateBuffer MAPIAllocateBuffer@8 MAPIAllocateMore MAPIAllocateMore@12 MAPIDeinitIdle@0 MAPIFreeBuffer MAPIFreeBuffer@4 MAPIGetDefaultMalloc@0 MAPIInitIdle@4 MAPIInitialize MAPIInitialize@4 MAPILogonEx MAPILogonEx@20 MAPIOpenFormMgr MAPIOpenFormMgr@8 MAPIOpenLocalFormContainer MAPIOpenLocalFormContainer@4 MAPIUninitialize MAPIUninitialize@0 MNLS_CompareStringW@24 MNLS_IsBadStringPtrW@8 MNLS_MultiByteToWideChar@24 MNLS_WideCharToMultiByte@32 MNLS_lstrcmpW@8 MNLS_lstrcpyW@8 MNLS_lstrlenW@4 MapStorageSCode@4 OpenIMsgOnIStg@44 OpenIMsgSession@12 OpenStreamOnFile OpenStreamOnFile@24 OpenTnefStream OpenTnefStream@28 OpenTnefStreamEx OpenTnefStreamEx@32 PRProviderInit PpropFindProp@12 PropCopyMore@16 RTFSync RTFSync@12 ScBinFromHexBounded@12 ScCopyNotifications@16 ScCopyProps@16 ScCountNotifications@12 ScCountProps@12 ScCreateConversationIndex@16 ScDupPropset@16 ScGenerateMuid@4 ScInitMapiUtil@4 ScLocalPathFromUNC@12 ScMAPIXFromCMC ScMAPIXFromSMAPI ScRelocNotifications@20 ScRelocProps@20 ScSplEntry ScUNCFromLocalPath@12 SetAttribIMsgOnIStg@16 SwapPlong@8 SwapPword@8 SzFindCh@8 SzFindLastCh@8 SzFindSz@8 UFromSz@4 UNKOBJ_COFree@8 UNKOBJ_Free@8 UNKOBJ_FreeRows@8 UNKOBJ_ScAllocate@12 UNKOBJ_ScAllocateMore@16 UNKOBJ_ScCOAllocate@12 UNKOBJ_ScCOReallocate@12 UNKOBJ_ScSzFromIdsAlloc@20 UlAddRef@4 UlFromSzHex@4 UlPropSize@4 UlRelease@4 WrapCompressedRTFStream WrapCompressedRTFStream@12 WrapProgress@20 WrapStoreEntryID@24 __CPPValidateParameters@8 __ValidateParameters@8 apcupsd-3.14.14/src/win32/onbatt.ico000066400000000000000000000004761274230402600170460ustar00rootroot00000000000000(( !!"!!!D4@D4@apcupsd-3.14.14/src/win32/online.ico000066400000000000000000000004761274230402600170430ustar00rootroot00000000000000(( !!!0000000000 a3apcupsd-3.14.14/src/win32/popup.c000066400000000000000000000030211274230402600163570ustar00rootroot00000000000000/* * Dumb Windows program to put up a message box * containing the command line. Any leading and * trailing quotes are stripped. * * Kern E. Sibbald * July MM */ #include "windows.h" #include int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { int len = strlen(szCmdLine); char *msg, *wordPtr; // Funny things happen with the command line if the // execution comes from c:/Program Files/apcupsd/apcupsd.exe // We get a command line like: Files/apcupsd/apcupsd.exe" options // I.e. someone stops scanning command line on a space, not // realizing that the filename is quoted!!!!!!!!!! // So if first character is not a double quote and // the last character before first space is a double // quote, we throw away the junk. wordPtr = szCmdLine; while (*wordPtr && *wordPtr != ' ') wordPtr++; if (wordPtr > szCmdLine) // backup to char before space wordPtr--; // if first character is not a quote and last is, junk it if (*szCmdLine != '"' && *wordPtr == '"') { wordPtr++; while (*wordPtr && *wordPtr == ' ') wordPtr++; /* strip leading spaces */ szCmdLine = wordPtr; len = strlen(szCmdLine); } msg = szCmdLine; if (*szCmdLine == '"' && len > 0 && szCmdLine[len-1] == '"') { msg = szCmdLine + 1; szCmdLine[len-1] = 0; } // Now display the popup MessageBox(NULL, msg, "Apcupsd message", MB_OK); return 0; } apcupsd-3.14.14/src/win32/resource.h000066400000000000000000000042601274230402600170560ustar00rootroot00000000000000#ifndef IDC_STATIC #define IDC_STATIC (-1) #endif #define IDI_ONLINE 101 #define IDI_ONBATT 102 #define IDI_CHARGING 103 #define IDR_TRAYMENU 104 #define IDI_COMMLOST 105 #define IDD_ABOUT 201 #define IDD_STATUS 202 #define IDD_EVENTS 203 #define IDD_CONFIG 205 #define IDC_WWW1 1000 #define IDC_WWW2 1001 #define IDC_COPYRIGHT1 1002 #define IDC_COPYRIGHT2 1003 #define IDC_COPYRIGHT3 1004 #define IDC_STATUSGRID 1004 #define IDC_BATTERY 1005 #define IDC_STATUS 1006 #define IDC_RUNTIME 1007 #define IDC_LOAD 1008 #define IDC_WWW 1022 #define IDC_COPYRIGHT 1023 #define IDC_TRADEMARK 1036 #define IDI_APCUPSD 40000 #define IDM_CONFIG 40000 #define IDM_ADD 40001 #define IDM_EXIT 40002 #define IDM_REMOVE 40003 #define IDM_ABOUT 40004 #define IDM_STATUS 40005 #define IDM_REMOVEALL 40006 #define IDM_EVENTS 40007 #define IDM_AUTOSTART 40008 #define IDM_NAME 40009 #define IDM_HOST 40010 #define IDC_HOSTNAME 40020 #define IDC_PORT 40021 #define IDC_REFRESH 40022 #define IDC_POPUPS 40023 #define IDC_VERSION 40024 #define IDC_LIST 40025 apcupsd-3.14.14/src/win32/shutdown.c000066400000000000000000000052331274230402600170760ustar00rootroot00000000000000/* * Dumb program to shutdown Windows * This code implements a very limited set of the * standard Unix shutdown program. * * Kern E. Sibbald, July MM */ #include #include #include #include enum { MODE_CANCEL, MODE_HALT, MODE_REBOOT }; int main(int argc, char **argv) { char ch; int mode = MODE_HALT; int timeout = 0; int force = 1; char default_msg[] = "Power failure system going down!"; char* message = default_msg; // Process command line args while ((ch = getopt(argc, argv, "+chrf")) != -1) { switch (ch) { case 'c': mode = MODE_CANCEL; break; case 'h': mode = MODE_HALT; break; case 'r': mode = MODE_REBOOT; break; case 'f': force = 0; break; } } if (optind < argc) { if (stricmp(argv[optind], "now") == 0) timeout = 0; else timeout = strtoul(argv[optind], NULL, 0); optind++; } if (optind < argc) { message = argv[optind]; } // Get the current OS version OSVERSIONINFO ver; ver.dwOSVersionInfoSize = sizeof(ver); GetVersionEx(&ver); /* For WinNT and above, we must get permission */ if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) { HANDLE hToken; TOKEN_PRIVILEGES tkp; // Get a token for this process. OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken); // Get the LUID for the shutdown privilege. LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid); tkp.PrivilegeCount = 1; // one privilege to set tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // Get the shutdown privilege for this process. AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0); } if (mode == MODE_CANCEL) { AbortSystemShutdown(NULL); } else { if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT) { InitiateSystemShutdown( NULL, /* Local machine */ message, /* Message */ timeout, /* Timeout (secs) */ force, /* Force */ mode == MODE_REBOOT); /* Reboot */ } else { Sleep(timeout*1000); int action = (mode == MODE_REBOOT) ? EWX_REBOOT : EWX_SHUTDOWN; if (force) action |= EWX_FORCE; ExitWindowsEx( action, /* Action */ 0); /* Reason */ } } exit(0); } apcupsd-3.14.14/src/win32/winabout.cpp000066400000000000000000000040101274230402600174030ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2007) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // // Implementation of the About dialog #include #include #include "winabout.h" #include "resource.h" #include "version.h" // Constructor/destructor upsAbout::upsAbout(HINSTANCE appinst) { _dlgvisible = FALSE; _appinst = appinst; } upsAbout::~upsAbout() { } // Dialog box handling functions void upsAbout::Show() { if (!_dlgvisible) { DialogBoxParam(_appinst, MAKEINTRESOURCE(IDD_ABOUT), NULL, (DLGPROC) DialogProc, (LONG) this); } } BOOL CALLBACK upsAbout::DialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // We use the dialog-box's USERDATA to store a _this pointer // This is set only once WM_INITDIALOG has been recieved, though! upsAbout *_this = (upsAbout *)GetWindowLong(hwnd, GWL_USERDATA); switch (uMsg) { case WM_INITDIALOG: // Retrieve the Dialog box parameter and use it as a pointer // to the calling vncProperties object SetWindowLong(hwnd, GWL_USERDATA, lParam); _this = (upsAbout *)lParam; // Show the dialog char tmp[128]; snprintf(tmp, sizeof(tmp), "Apctray %s (%s)", VERSION, ADATE); SendDlgItemMessage(hwnd, IDC_VERSION, WM_SETTEXT, 0, (LONG)tmp); SetForegroundWindow(hwnd); _this->_dlgvisible = TRUE; return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: // Close the dialog EndDialog(hwnd, TRUE); _this->_dlgvisible = FALSE; return TRUE; } break; case WM_DESTROY: EndDialog(hwnd, FALSE); _this->_dlgvisible = FALSE; return TRUE; } return 0; } apcupsd-3.14.14/src/win32/winabout.h000066400000000000000000000014201274230402600170520ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2007) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // #ifndef WINABOUT_H #define WINABOUT_H #include // Object implementing the About dialog for WinUPS. class upsAbout { public: // Constructor/destructor upsAbout(HINSTANCE appinst); ~upsAbout(); // General void Show(); private: // The dialog box window proc static BOOL CALLBACK DialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Private data BOOL _dlgvisible; HINSTANCE _appinst; }; #endif // WINABOUT_H apcupsd-3.14.14/src/win32/winconfig.cpp000066400000000000000000000126521274230402600175510ustar00rootroot00000000000000/* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ // Implementation of the Config dialog #include #include #include #include "winconfig.h" #include "resource.h" #include "instmgr.h" // Constructor/destructor upsConfig::upsConfig(HINSTANCE appinst, InstanceManager *instmgr) : _hwnd(NULL), _appinst(appinst), _instmgr(instmgr) { } upsConfig::~upsConfig() { } // Dialog box handling functions void upsConfig::Show(MonitorConfig &mcfg) { if (!_hwnd) { _config = mcfg; _hostvalid = true; _portvalid = true; _refreshvalid = true; DialogBoxParam(_appinst, MAKEINTRESOURCE(IDD_CONFIG), NULL, (DLGPROC)DialogProc, (LONG)this); } } BOOL CALLBACK upsConfig::DialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { upsConfig *_this; // Retrieve virtual 'this' pointer. When we come in here the first time for // the WM_INITDIALOG message, the pointer is in lParam. We then store it in // the user data so it can be retrieved on future calls. if (uMsg == WM_INITDIALOG) { // Set dialog user data to our "this" pointer which comes in via lParam. // On subsequent calls, this will be retrieved by the code below. SetWindowLong(hwnd, GWL_USERDATA, lParam); _this = (upsConfig *)lParam; } else { // We've previously been initialized, so retrieve pointer from user data _this = (upsConfig *)GetWindowLong(hwnd, GWL_USERDATA); } // Call thru to non-static member function return _this->DialogProcess(hwnd, uMsg, wParam, lParam); } BOOL upsConfig::DialogProcess( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { char tmp[256] = {0}; switch (uMsg) { case WM_INITDIALOG: // Save a copy of our window handle for later use _hwnd = hwnd; // Fetch handles for all controls. We'll use these multiple times later // so it makes sense to cache them. _hhost = GetDlgItem(hwnd, IDC_HOSTNAME); _hport = GetDlgItem(hwnd, IDC_PORT); _hrefresh = GetDlgItem(hwnd, IDC_REFRESH); _hpopups = GetDlgItem(hwnd, IDC_POPUPS); // Initialize fields with current config settings SendMessage(_hhost, WM_SETTEXT, 0, (LONG)_config.host.str()); snprintf(tmp, sizeof(tmp), "%lu", _config.port); SendMessage(_hport, WM_SETTEXT, 0, (LONG)tmp); snprintf(tmp, sizeof(tmp), "%lu", _config.refresh); SendMessage(_hrefresh, WM_SETTEXT, 0, (LONG)tmp); SendMessage(_hpopups, BM_SETCHECK, _config.popups ? BST_CHECKED : BST_UNCHECKED, 0); // Show the dialog SetForegroundWindow(hwnd); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: { // Fetch and validate hostname SendMessage(_hhost, WM_GETTEXT, sizeof(tmp), (LONG)tmp); astring host(tmp); _hostvalid = !host.trim().empty(); // Fetch and validate port SendMessage(_hport, WM_GETTEXT, sizeof(tmp), (LONG)tmp); int port = atoi(tmp); _portvalid = (port >= 1 && port <= 65535); // Fetch and validate refresh SendMessage(_hrefresh, WM_GETTEXT, sizeof(tmp), (LONG)tmp); int refresh = atoi(tmp); _refreshvalid = (refresh >= 1); // Fetch popups on/off bool popups = SendMessage(_hpopups, BM_GETCHECK, 0, 0) == BST_CHECKED; if (_hostvalid && _portvalid && _refreshvalid) { // Config is valid: Save it and close the dialog _config.host = host; _config.port = port; _config.refresh = refresh; _config.popups = popups; _instmgr->UpdateInstance(_config); EndDialog(hwnd, TRUE); } else { // Set keyboard focus to first invalid field if (!_hostvalid) SetFocus(_hhost); else if (!_portvalid) SetFocus(_hport); else SetFocus(_hrefresh); // Force redraw to get background color change RedrawWindow(hwnd, NULL, NULL, RDW_INTERNALPAINT|RDW_INVALIDATE); } return TRUE; } case IDCANCEL: // Close the dialog EndDialog(hwnd, TRUE); return TRUE; } break; case WM_CTLCOLOREDIT: { // Set edit control background red if data was invalid if (((HWND)lParam == _hhost && !_hostvalid) || ((HWND)lParam == _hport && !_portvalid) || ((HWND)lParam == _hrefresh && !_refreshvalid)) { SetBkColor((HDC)wParam, RGB(255,0,0)); return (BOOL)CreateSolidBrush(RGB(255,0,0)); } return FALSE; } case WM_DESTROY: _hwnd = NULL; return TRUE; } return 0; } apcupsd-3.14.14/src/win32/winconfig.h000066400000000000000000000027201274230402600172110ustar00rootroot00000000000000/* * Copyright (C) 2009 Adam Kropelin * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1335, USA. */ #ifndef __WINCONFIG_H #define __WINCONFIG_H #include "astring.h" #include "instmgr.h" #include // Object implementing the Status dialogue for apcupsd class upsConfig { public: // Constructor/destructor upsConfig(HINSTANCE appinst, InstanceManager *instmgr); ~upsConfig(); // General void Show(MonitorConfig &mcfg); private: // The dialog box window proc static BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL DialogProcess(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Private data HWND _hwnd; HINSTANCE _appinst; InstanceManager *_instmgr; MonitorConfig _config; HWND _hhost, _hport, _hrefresh, _hpopups; bool _hostvalid, _portvalid, _refreshvalid; }; #endif // WINCONFIG_H apcupsd-3.14.14/src/win32/winevents.cpp000066400000000000000000000106271274230402600176100ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2009) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // // Implementation of the Events dialogue #include #include "winevents.h" #include "resource.h" #include "statmgr.h" #include "listview.h" #include "wintray.h" // Constructor/destructor upsEvents::upsEvents(HINSTANCE appinst, upsMenu *menu) : _appinst(appinst), _hwnd(NULL), _menu(menu) { } upsEvents::~upsEvents() { } // Dialog box handling functions void upsEvents::Show() { if (!_hwnd) { DialogBoxParam(_appinst, MAKEINTRESOURCE(IDD_EVENTS), NULL, (DLGPROC)DialogProc, (LONG)this); } } BOOL CALLBACK upsEvents::DialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { upsEvents *_this; // Retrieve virtual 'this' pointer. When we come in here the first time for // the WM_INITDIALOG message, the pointer is in lParam. We then store it in // the user data so it can be retrieved on future calls. if (uMsg == WM_INITDIALOG) { // Set dialog user data to our "this" pointer which comes in via lParam. // On subsequent calls, this will be retrieved by the code below. SetWindowLong(hwnd, GWL_USERDATA, lParam); _this = (upsEvents *)lParam; } else { // We've previously been initialized, so retrieve pointer from user data _this = (upsEvents *)GetWindowLong(hwnd, GWL_USERDATA); } // Call thru to non-static member function return _this->DialogProcess(hwnd, uMsg, wParam, lParam); } BOOL upsEvents::DialogProcess( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: // Silly: Save initial window size for use as minimum size. There's // probably some programmatic way to fetch this from the resource when // we need it, but I can't find it. So we'll save it at runtime. GetWindowRect(hwnd, &_rect); // Initialize control wrappers _events = new ListView(hwnd, IDC_LIST, 1); // Save a copy of our window handle for later use. // Important to do this AFTER everything needed by Update() is // initialized and ready to go since that function may be called at any // time from the wintray timer thread. _hwnd = hwnd; // Show the dialog _menu->Refresh(); SetForegroundWindow(hwnd); return TRUE; case WM_GETMINMAXINFO: { // Restrict minimum size to initial window size MINMAXINFO *mmi = (MINMAXINFO*)lParam; mmi->ptMinTrackSize.x = _rect.right - _rect.left; mmi->ptMinTrackSize.y = _rect.bottom - _rect.top; return TRUE; } case WM_SIZE: { // Fetch new window size (esp client area size) WINDOWINFO wininfo; wininfo.cbSize = sizeof(wininfo); GetWindowInfo(hwnd, &wininfo); // Fetch current listview position HWND ctrl = GetDlgItem(hwnd, IDC_LIST); RECT gridrect; GetWindowRect(ctrl, &gridrect); // Calculate new position and size of listview int left = gridrect.left - wininfo.rcClient.left; int top = gridrect.top - wininfo.rcClient.top; int width = wininfo.rcClient.right - wininfo.rcClient.left - 2*left; int height = wininfo.rcClient.bottom - wininfo.rcClient.top - top - left; // Resize listview SetWindowPos( ctrl, NULL, left, top, width, height, SWP_NOZORDER | SWP_SHOWWINDOW); return TRUE; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: // Close the dialog EndDialog(hwnd, TRUE); return TRUE; } break; case WM_DESTROY: _mutex.lock(); _hwnd = NULL; delete _events; _mutex.unlock(); return TRUE; } return 0; } void upsEvents::Update(StatMgr *statmgr) { // Bail if window is not open _mutex.lock(); if (!_hwnd) { _mutex.unlock(); return; } // Fetch events from apcupsd alist events; if (!statmgr->GetEvents(events) || events.empty()) { _mutex.unlock(); return; } // Update listview alist *data[] = {&events}; _events->UpdateAll(data); _mutex.unlock(); } apcupsd-3.14.14/src/win32/winevents.h000066400000000000000000000021101274230402600172410ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2009) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // #ifndef WINEVENTS_H #define WINEVENTS_H #include #include "amutex.h" // Forward declarations class StatMgr; class ListView; class upsMenu; // Object implementing the Events dialogue box for apcupsd class upsEvents { public: // Constructor/destructor upsEvents(HINSTANCE appinst, upsMenu *menu); ~upsEvents(); // General void Show(); void Update(StatMgr *statmgr); private: // The dialog box window proc static BOOL CALLBACK DialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL CALLBACK DialogProcess( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Private data HINSTANCE _appinst; HWND _hwnd; ListView *_events; amutex _mutex; RECT _rect; upsMenu *_menu; }; #endif // WINEVENTS_H apcupsd-3.14.14/src/win32/winmain.cpp000066400000000000000000000230231274230402600172220ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2007) Adam D. Kropelin // Copyright (2000-2006) Kern E. Sibbald // 20 July 2000 // System Headers #include #include #include #include #include #include #include // Apcupsd UNIX main entrypoint extern int ApcupsdMain(int argc, char **argv); // Custom headers #include "apcconfig.h" #include "winups.h" #include "winservice.h" #include "compat.h" #include "defines.h" #include "winapi.h" // Standard command-line flag definitions char ApcupsdRunService[] = "/service"; char ApcupsdRunAsUserApp[] = "/run"; char ApcupsdInstallService[] = "/install"; char ApcupsdRemoveService[] = "/remove"; char ApcupsdKillRunningCopy[] = "/kill"; char ApcupsdShowHelp[] = "/help"; char ApcupsdQuiet[] = "/quiet"; // Usage string static const char *ApcupsdUsageText = "apcupsd [/quiet] [/run] [/kill] [/install] [/remove] [/help]\n"; // Application instance static HINSTANCE hAppInstance; // Command line argument storage #define MAX_COMMAND_ARGS 100 static char apcupsd_name[] = "apcupsd"; static char *command_args[MAX_COMMAND_ARGS] = { apcupsd_name, NULL }; static int num_command_args = 1; static char *winargs[MAX_COMMAND_ARGS]; static int num_winargs = 0; // WinMain parses the command line and either calls the main App // routine or, under NT, the main service routine. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR CmdLine, int iCmdShow) { bool quiet = false; InitWinAPIWrapper(); // Save the application instance and main thread id hAppInstance = hInstance; /* Build Unix style argc *argv[] */ /* Don't NULL command_args[0] !!! */ for (int i = 1; i < MAX_COMMAND_ARGS; i++) command_args[i] = NULL; // Split command line to windows and non-windows arguments char *arg; char *szCmdLine = CmdLine; while ((arg = GetArg(&szCmdLine))) { // Save the argument in appropriate list if (*arg != '/' && num_command_args < MAX_COMMAND_ARGS) command_args[num_command_args++] = arg; else if (num_winargs < MAX_COMMAND_ARGS) winargs[num_winargs++] = arg; } // Default Windows argument if (num_winargs == 0) winargs[num_winargs++] = ApcupsdRunAsUserApp; // Act on Windows arguments... for (int i = 0; i < num_winargs; i++) { // /service if (strcasecmp(winargs[i], ApcupsdRunService) == 0) { // Run Apcupsd as a service return upsService::ApcupsdServiceMain(); } // /run (this is the default if no command line arguments) if (strcasecmp(winargs[i], ApcupsdRunAsUserApp) == 0) { // Apcupsd is being run as a user-level program return ApcupsdAppMain(0); } // /install if (strcasecmp(winargs[i], ApcupsdInstallService) == 0) { // Install Apcupsd as a service return upsService::InstallService(quiet); } // /remove if (strcasecmp(winargs[i], ApcupsdRemoveService) == 0) { // Remove the Apcupsd service return upsService::RemoveService(quiet); } // /kill if (strcasecmp(winargs[i], ApcupsdKillRunningCopy) == 0) { // Kill any already running copy of Apcupsd ApcupsdTerminate(); return 0; } // /quiet if (strcasecmp(winargs[i], ApcupsdQuiet) == 0) { // Set quiet flag and go on to next argument quiet = true; continue; } // /help if (strcasecmp(winargs[i], ApcupsdShowHelp) == 0) { MessageBox(NULL, ApcupsdUsageText, "Apcupsd Usage", MB_OK | MB_ICONINFORMATION); return 0; } // Unknown option: Show the usage dialog MessageBox(NULL, winargs[i], "Bad Command Line Options", MB_OK); MessageBox(NULL, ApcupsdUsageText, "Apcupsd Usage", MB_OK | MB_ICONINFORMATION); return 1; } return 0; } // Callback for processing Windows messages static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { // Clean exit requested case WM_DESTROY: PostQuitMessage(0); return 0; // Everything else uses default handling default: return DefWindowProc(hwnd, uMsg, wParam, lParam); } } static void PostToApcupsd(UINT message, WPARAM wParam, LPARAM lParam) { // Locate the hidden Apcupsd window HWND hservwnd = FindWindowEx(NULL, NULL, APCUPSD_WINDOW_CLASS, APCUPSD_WINDOW_NAME); if (hservwnd == NULL) return; // Post the message to Apcupsd PostMessage(hservwnd, message, wParam, lParam); } void ApcupsdTerminate() { // Old versions of apcupsd and modern versions running on WinNT and // earlier need to receive a window message. PostToApcupsd(WM_CLOSE, 0, 0); // New apcupsd on Win2K and above listen for an event to be signaled. // This allows stopping apcupsd instances running under LocalSystem // and those started on other desktops. if (g_os_version >= WINDOWS_2000) { HANDLE evt = OpenEvent(EVENT_MODIFY_STATE, FALSE, APCUPSD_STOP_EVENT_NAME); if (evt != NULL) { SetEvent(evt); CloseHandle(evt); } } } // Called as a thread from ApcupsdAppMain() // Here we invoke apcupsd UNIX main loop void *ApcupsdMain(LPVOID lpwThreadParam) { pthread_detach(pthread_self()); // Call the "real" apcupsd ApcupsdMain(num_command_args, command_args); // In case apcupsd returns, terminate application ApcupsdTerminate(); return NULL; } // This thread runs on Windows 2000 and higher. It monitors for the // global exit event to be signaled (/kill). bool runthread = false; HANDLE exitevt = NULL; DWORD WINAPI EventThread(LPVOID param) { // Create global exit event and allow Adminstrator access to it so any // member of the Administrators group can signal it. exitevt = CreateEvent(NULL, TRUE, FALSE, APCUPSD_STOP_EVENT_NAME); TCHAR name[] = "Administrators"; GrantAccess(exitevt, EVENT_MODIFY_STATE, TRUSTEE_IS_GROUP, name); // Wait for event to be signaled while (runthread) { DWORD rc = WaitForSingleObject(exitevt, INFINITE); if (!runthread || rc != WAIT_OBJECT_0) break; // Global exit event signaled runthread = false; PostToApcupsd(WM_CLOSE, 0, 0); } CloseHandle(exitevt); return 0; } // Wait for exit signal on WinNT and below. This code creates a hidden // window and waits for a WM_CLOSE window message to be delivered. On // modern platforms, we also monitor a global event. static void WaitForExit() { // Dummy window class WNDCLASSEX wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = WindowProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = hAppInstance; wndclass.hIcon = NULL; wndclass.hCursor = NULL; wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; wndclass.lpszClassName = APCUPSD_WINDOW_CLASS; wndclass.hIconSm = NULL; if (RegisterClassEx(&wndclass) == 0) return; // Create dummy window so we can receive Windows messages HWND hwnd = CreateWindow(APCUPSD_WINDOW_CLASS, // class APCUPSD_WINDOW_NAME, // name/title 0, // style 0, // X pos 0, // Y pos 0, // width 0, // height NULL, // parent NULL, // menu hAppInstance, // app instance NULL ); // create param if (hwnd == NULL) return; // On Win2K and above we spawn a thread to watch for exit requests. HANDLE evtthread = NULL; if (g_os_version >= WINDOWS_2000) { runthread = true; evtthread = CreateThread(NULL, 0, EventThread, NULL, 0, NULL); } // Now enter the Windows message handling loop until told to quit MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } // Wait for event thread to exit cleanly if (g_os_version >= WINDOWS_2000) { runthread = false; SetEvent(exitevt); // Kick exitevt to wake up thread if (WaitForSingleObject(evtthread, 5000) == WAIT_TIMEOUT) TerminateThread(evtthread, 0); CloseHandle(evtthread); } DestroyWindow(hwnd); } // This is the main routine for Apcupsd. It spawns a thread to run the // UNIX apcupsd back end and waits to be told to exit. int ApcupsdAppMain(int service) { // Set this process to be the last application to be shut down. SetProcessShutdownParameters(0x100, 0); // Check to see if we're already running HANDLE sem = CreateSemaphore(NULL, 0, 1, "apcupsd"); if (sem == NULL || GetLastError() == ERROR_ALREADY_EXISTS) { MessageBox(NULL, "Another instance of Apcupsd is already running", "Apcupsd Error", MB_OK); return 0; } // Create a thread on which to run apcupsd UNIX main loop pthread_t tid; pthread_create(&tid, NULL, ApcupsdMain, (void *)GetCurrentThreadId()); // Wait for exit request. WaitForExit(); pthread_kill(tid, SIGTERM); return 0; } apcupsd-3.14.14/src/win32/winres.rc000066400000000000000000000131501274230402600167110ustar00rootroot00000000000000// Generated by ResEdit 1.4.8 // Copyright (C) 2006-2009 // http://www.resedit.net #include #include #include #include "resource.h" // // Menu resources // IDR_TRAYMENU MENU { POPUP "tray" { MENUITEM "UPS: ", IDM_NAME, INACTIVE MENUITEM "HOST: ", IDM_HOST, INACTIVE MENUITEM SEPARATOR MENUITEM "&Status", IDM_STATUS MENUITEM "&Events", IDM_EVENTS MENUITEM SEPARATOR MENUITEM "Configure...", IDM_CONFIG MENUITEM "Start Automatically", IDM_AUTOSTART MENUITEM SEPARATOR MENUITEM "Add Monitor", IDM_ADD MENUITEM "Remove Monitor", IDM_REMOVE MENUITEM "Remove All Monitors", IDM_REMOVEALL MENUITEM SEPARATOR MENUITEM "&About", IDM_ABOUT MENUITEM "Exit", IDM_EXIT } } // // Dialog resources // IDD_ABOUT DIALOG 0, 0, 250, 145 STYLE DS_CENTER | DS_MODALFRAME | DS_SETFONT | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU CAPTION "About Apcupsd" FONT 8, "MS Sans Serif" { DEFPUSHBUTTON "OK", IDOK, 190, 120, 50, 15 LTEXT "For more information, see:", IDC_WWW, 90, 40, 145, 10, SS_LEFT LTEXT "http://www.apcupsd.org", IDC_WWW1, 100, 50, 79, 8, SS_LEFT LTEXT "http://sourceforge.net/projects/apcupsd", IDC_WWW2, 100, 60, 130, 8, SS_LEFT LTEXT "Copyright (C) 2004-2009, Adam Kropelin", IDC_COPYRIGHT, 7, 90, 126, 8, SS_LEFT LTEXT "Copyright (C) 1999-2006, Kern Sibbald", IDC_COPYRIGHT1, 7, 100, 175, 10, SS_LEFT LTEXT "Copyright (C) 1999-2002, Riccardo Facchetti", IDC_COPYRIGHT2, 7, 110, 175, 10, SS_LEFT LTEXT "Copyright (C) 1996-1999, Andr M. Hedrick", IDC_COPYRIGHT3, 7, 120, 175, 10, SS_LEFT LTEXT "Licensed under GNU GPL 2.0.", IDC_TRADEMARK, 7, 130, 175, 10, SS_LEFT LTEXT "A.B.C", IDC_VERSION, 90, 10, 141, 8, SS_LEFT } IDD_CONFIG DIALOG 0, 0, 196, 95 STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP CAPTION "Configuration" FONT 8, "Ms Shell Dlg 2" { DEFPUSHBUTTON "OK", IDOK, 105, 76, 50, 14 EDITTEXT IDC_HOSTNAME, 89, 4, 100, 13, ES_AUTOHSCROLL RTEXT "Hostname or IP Address:", IDC_STATIC, 5, 7, 81, 8, SS_RIGHT EDITTEXT IDC_PORT, 89, 22, 48, 13, ES_AUTOHSCROLL | ES_NUMBER RTEXT "Port:", IDC_STATIC, 69, 24, 17, 8, SS_RIGHT RTEXT "(1-65535)", IDC_STATIC, 140, 25, 33, 8, SS_RIGHT RTEXT "seconds", IDC_STATIC, 140, 43, 27, 8, SS_RIGHT EDITTEXT IDC_REFRESH, 89, 40, 48, 13, ES_AUTOHSCROLL | ES_NUMBER RTEXT "Refresh:", IDC_STATIC, 57, 42, 29, 8, SS_RIGHT AUTOCHECKBOX "Enable status balloons", IDC_POPUPS, 89, 59, 87, 10 PUSHBUTTON "Cancel", IDCANCEL, 41, 76, 47, 14 } IDD_EVENTS DIALOG 0, 0, 355, 204 STYLE DS_3DLOOK | DS_CENTER | DS_SETFONT | WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_THICKFRAME | WS_SYSMENU EXSTYLE WS_EX_WINDOWEDGE CAPTION "Apcupsd Events" FONT 8, "MS Sans Serif" { CONTROL "", IDC_LIST, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_REPORT, 6, 7, 343, 191 } IDD_STATUS DIALOGEX 0, 0, 262, 226 STYLE DS_3DLOOK | DS_CENTER | DS_SETFONT | WS_VISIBLE | WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_THICKFRAME | WS_SYSMENU EXSTYLE WS_EX_WINDOWEDGE FONT 8, "MS Sans Serif", 0, 0, 0 { CONTROL "", IDC_STATUSGRID, WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_ALIGNLEFT | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | LVS_REPORT, 5, 45, 252, 176 CONTROL "", IDC_BATTERY, PROGRESS_CLASS, PBS_SMOOTH, 40, 6, 76, 13 RTEXT "Battery:", IDC_STATIC, 4, 9, 32, 9, SS_RIGHT EDITTEXT IDC_STATUS, 40, 24, 76, 13, ES_CENTER | ES_AUTOHSCROLL | ES_READONLY RTEXT "Status:", IDC_STATIC, 4, 27, 32, 9, SS_RIGHT EDITTEXT IDC_RUNTIME, 172, 24, 48, 13, ES_CENTER | ES_AUTOHSCROLL | ES_READONLY RTEXT "Runtime:", IDC_STATIC, 137, 27, 32, 9, SS_RIGHT LTEXT "minutes", IDC_STATIC, 225, 27, 32, 9, SS_LEFT CONTROL "", IDC_LOAD, PROGRESS_CLASS, PBS_SMOOTH, 172, 6, 76, 13 RTEXT "Load:", IDC_STATIC, 137, 9, 32, 9, SS_RIGHT } // // String Table resources // STRINGTABLE { IDI_APCUPSD "Apcupsd" } // // Icon resources // IDI_APCUPSD ICON "apcupsd.ico" IDI_CHARGING ICON "charging.ico" IDI_COMMLOST ICON "commlost.ico" IDI_ONBATT ICON "onbatt.ico" IDI_ONLINE ICON "online.ico" // // Version Information resources // VS_VERSION_INFO VERSIONINFO FILEVERSION 0,0,0,0 PRODUCTVERSION 0,0,0,0 FILEOS VOS__WINDOWS32 FILETYPE VFT_UNKNOWN { BLOCK "StringFileInfo" { BLOCK "040904e0" { VALUE "CompanyName", "Apcupsd Team" VALUE "FileDescription", "Tray icon applet for apcupsd" VALUE "FileVersion", "$VERSION" VALUE "InternalName", "apctray" VALUE "LegalCopyright", "Copyright 2007-2009 Adam Kropelin" VALUE "LegalTrademarks", "Licensed under GNU GPL 2.0" VALUE "OriginalFilename", "apctray.exe" VALUE "ProductName", "apctray" VALUE "ProductVersion", "$VERSION" } } BLOCK "VarFileInfo" { VALUE "Translation", 1033, 1248 } } apcupsd-3.14.14/src/win32/winservice.cpp000066400000000000000000000440271274230402600177450ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2007) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // // Implementation of service-oriented functionality of Apcupsd #include "winapi.h" #include "compat.h" #include "winups.h" #include "winservice.h" #include // Error message logging void LogErrorMsg(const char *msg, const char *fname, int lineno); #define log_error_message(msg) LogErrorMsg((msg), __FILE__, __LINE__) // No internationalization support #define _(x) x // Internal service state (static) SERVICE_STATUS upsService::m_srvstatus; SERVICE_STATUS_HANDLE upsService::m_hstatus; DWORD upsService::m_servicethread = 0; // Typedefs for dynamically loaded functions typedef BOOL (WINAPI * ChangeServiceConfig2Func)(SC_HANDLE, DWORD, LPVOID); typedef DWORD (* RegisterServiceProcessFunc)(DWORD, DWORD); // Internal service name static char SERVICE_NAME[] = "Apcupsd"; // Displayed service name static const char SERVICE_DISPLAYNAME[] = "Apcupsd UPS Monitor"; // Service description static char APCUPSD_SERVICE_DESCRIPTION[] = "Apcupsd provides shutdown of your computer " "in the event of a power failure."; // List other required serves #define SERVICE_DEPENDENCIES __TEXT("tcpip\0afd\0+File System\0") // SERVICE MAIN ROUTINE int upsService::ApcupsdServiceMain() { // How to run as a service depends upon the OS being used switch (g_os_version_info.dwPlatformId) { // Windows 95/98/Me case VER_PLATFORM_WIN32_WINDOWS: // Obtain a handle to the kernel library HINSTANCE kerneldll; kerneldll = LoadLibrary("KERNEL32.DLL"); if (kerneldll == NULL) { MessageBox(NULL, "KERNEL32.DLL not found: Apcupsd service not started", "Apcupsd Service", MB_OK); break; } // And find the RegisterServiceProcess function RegisterServiceProcessFunc RegisterServiceProcess; RegisterServiceProcess = (RegisterServiceProcessFunc)GetProcAddress( kerneldll, "RegisterServiceProcess"); if (RegisterServiceProcess == NULL) { MessageBox(NULL, "Registry service not found: Apcupsd service not started", "Apcupsd Service", MB_OK); log_error_message("Registry service not found"); FreeLibrary(kerneldll); break; } // Register this process with the OS as a service! RegisterServiceProcess(0, 1); // Run the main program as a service ApcupsdAppMain(1); // Then remove the service from the system service table RegisterServiceProcess(0, 0); // Free the kernel library FreeLibrary(kerneldll); break; // Windows NT, Win2K, WinXP case VER_PLATFORM_WIN32_NT: // Create a service entry table SERVICE_TABLE_ENTRY dispatchTable[] = { {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain}, {NULL, NULL} }; // Call the service control dispatcher with our entry table if (!StartServiceCtrlDispatcher(dispatchTable)) { log_error_message("StartServiceCtrlDispatcher failed."); } break; } /* end switch */ return 0; } // SERVICE MAIN ROUTINE // NT/Win2K/WinXP ONLY !!! void WINAPI upsService::ServiceMain(DWORD argc, char **argv) { // Register the service control handler m_hstatus = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrl); if (m_hstatus == 0) { log_error_message("RegisterServiceCtlHandler failed"); MessageBox(NULL, "Contact Register Service Handler failure", "Apcupsd service", MB_OK); return; } // Set up some standard service state values m_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS; m_srvstatus.dwServiceSpecificExitCode = 0; // Give this status to the SCM if (!ReportStatus( SERVICE_START_PENDING, // service state NO_ERROR, // exit code 45000)) { // wait hint log_error_message("ReportStatus STOPPED failed 1"); return; } // Now start the service working thread CreateThread(NULL, 0, ServiceWorkThread, NULL, 0, NULL); } // SERVICE START ROUTINE - thread that calls ApcupsdAppMain // NT/Win2K/WinXP ONLY !!! DWORD WINAPI upsService::ServiceWorkThread(LPVOID lpwThreadParam) { // report the status to the service control manager. if (!ReportStatus( SERVICE_RUNNING, // service state NO_ERROR, // exit code 0)) { // wait hint MessageBox(NULL, "Report Service failure", "Apcupsd Service", MB_OK); log_error_message("ReportStatus RUNNING failed"); return 0; } // Save the current thread identifier m_servicethread = GetCurrentThreadId(); /* Call Apcupsd main code */ ApcupsdAppMain(1); /* Mark that we're no longer running */ m_servicethread = 0; /* Tell the service manager that we've stopped */ ReportStatus(SERVICE_STOPPED, 0, 0); return 0; } // SERVICE STOP ROUTINE - NT/Win2K/WinXP ONLY !!! void upsService::ServiceStop() { ApcupsdTerminate(); } // SERVICE INSTALL ROUTINE int upsService::InstallService(bool quiet) { const unsigned int MAXPATH = 2048; // Get the filename of this executable char path[MAXPATH]; if (GetModuleFileName(NULL, path, MAXPATH) == 0) { if (!quiet) { MessageBox(NULL, "Unable to install Apcupsd service", SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); } return 0; } // Append the service-start flag to the end of the path // Length is path len plus quotes, space, start flag, and NUL terminator char servicecmd[MAXPATH]; if (strlen(path) + 4 + strlen(ApcupsdRunService) < MAXPATH) { sprintf(servicecmd, "\"%s\" %s", path, ApcupsdRunService); } else { if (!quiet) { MessageBox(NULL, "Service command length too long. Service not registered.", SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); } return 0; } // How to add the Apcupsd service depends upon the OS switch (g_os_version_info.dwPlatformId) { // Windows 95/98/Me case VER_PLATFORM_WIN32_WINDOWS: // Locate the RunService registry entry HKEY runservices; if (RegCreateKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices", &runservices) != ERROR_SUCCESS) { log_error_message("Cannot write System Registry"); MessageBox(NULL, _("The System Registry could not be updated - " "the Apcupsd service was not installed"), SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); break; } // Attempt to add a Apcupsd key if (RegSetValueEx(runservices, SERVICE_NAME, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS) { RegCloseKey(runservices); MessageBox(NULL, "The Apcupsd service could not be installed", SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); break; } RegCloseKey(runservices); // Indicate that we're installed to run as a service SetServiceFlag(1); // We have successfully installed the service! if (!quiet) { MessageBox(NULL, _("The Apcupsd UPS service was successfully installed.\n" "The service may be started by double clicking on the\n" "Apcupsd \"Start\" icon and will automatically\n" "be run the next time this machine is rebooted. "), SERVICE_NAME, MB_ICONINFORMATION | MB_OK); } break; // Windows NT, Win2K, WinXP case VER_PLATFORM_WIN32_NT: // Open the default, local Service Control Manager database SC_HANDLE hsrvmanager; hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (hsrvmanager == NULL) { MessageBox(NULL, _("The Service Control Manager could not be contacted - " "the Apcupsd service was not installed"), SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); break; } // Create an entry for the Apcupsd service SC_HANDLE hservice; hservice = CreateService( hsrvmanager, // SCManager database SERVICE_NAME, // name of service SERVICE_DISPLAYNAME, // name to display SERVICE_ALL_ACCESS, // desired access SERVICE_WIN32_OWN_PROCESS | // service type SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, // start type SERVICE_ERROR_NORMAL, // error control type servicecmd, // service's binary NULL, // no load ordering group NULL, // no tag identifier SERVICE_DEPENDENCIES, // dependencies NULL, // LocalSystem account NULL); // no password if (hservice == NULL) { if (!quiet || GetLastError() != ERROR_SERVICE_EXISTS) { MessageBox(NULL, "The Apcupsd service could not be installed", SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); } CloseServiceHandle(hsrvmanager); break; } SetServiceDescription(hservice, APCUPSD_SERVICE_DESCRIPTION); CloseServiceHandle(hservice); CloseServiceHandle(hsrvmanager); // Indicate that we're installed to run as a service SetServiceFlag(1); // Everything went fine if (!quiet) { MessageBox(NULL, _("The Apcupsd UPS service was successfully installed.\n" "The service may be started from the Control Panel and will\n" "automatically be run the next time this machine is rebooted."), SERVICE_NAME, MB_ICONINFORMATION | MB_OK); } break; default: MessageBox(NULL, _("Unknown Windows operating system.\n" "Cannot install Apcupsd service.\n"), SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); break; } return 0; } // SERVICE REMOVE ROUTINE int upsService::RemoveService(bool quiet) { // How to remove the Apcupsd service depends upon the OS switch (g_os_version_info.dwPlatformId) { // Windows 95/98/Me case VER_PLATFORM_WIN32_WINDOWS: // Locate the RunService registry entry HKEY runservices; if (RegOpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices", &runservices) != ERROR_SUCCESS) { if (!quiet) { MessageBox(NULL, _("Could not find registry entry.\n" "Service probably not registerd - " "the Apcupsd service was not removed"), SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); } } else { // Attempt to delete the Apcupsd key if (RegDeleteValue(runservices, SERVICE_NAME) != ERROR_SUCCESS) { if (!quiet) { MessageBox(NULL, _("Could not delete Registry key.\n" "The Apcupsd service could not be removed"), SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); } } RegCloseKey(runservices); break; } // Try to kill any running copy of Apcupsd ApcupsdTerminate(); // Indicate that we're no longer installed to run as a service SetServiceFlag(0); // We have successfully removed the service! if (!quiet) { MessageBox(NULL, "The Apcupsd service has been removed", SERVICE_NAME, MB_ICONINFORMATION | MB_OK); } break; // Windows NT, Win2K, WinXP case VER_PLATFORM_WIN32_NT: SC_HANDLE hservice = OpenNTService(); if (!StopNTService(hservice)) { // Service could not be stopped MessageBox(NULL, "The Apcupsd service could not be stopped", SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); } if(DeleteService(hservice)) { // Indicate that we're no longer installed to run as a service SetServiceFlag(0); // Service successfully removed if (!quiet) { MessageBox(NULL, "The Apcupsd service has been removed", SERVICE_NAME, MB_ICONINFORMATION | MB_OK); } } else { // Failed to remove MessageBox(NULL, "The Apcupsd service could not be removed", SERVICE_NAME, MB_ICONEXCLAMATION | MB_OK); } CloseServiceHandle(hservice); break; } return 0; } // USEFUL SERVICE SUPPORT ROUTINES // Service control routine void WINAPI upsService::ServiceCtrl(DWORD ctrlcode) { // What control code have we been sent? switch(ctrlcode) { case SERVICE_CONTROL_STOP: // STOP : The service must stop m_srvstatus.dwCurrentState = SERVICE_STOP_PENDING; ServiceStop(); break; case SERVICE_CONTROL_INTERROGATE: // QUERY : Service control manager just wants to know our state break; default: // Control code not recognised break; } // Tell the control manager what we're up to. ReportStatus(m_srvstatus.dwCurrentState, NO_ERROR, 0); } // Service manager status reporting BOOL upsService::ReportStatus(DWORD state, DWORD exitcode, DWORD waithint) { static DWORD checkpoint = 1; // If we're in the start state then we don't want the control manager // sending us control messages because they'll confuse us. if (state == SERVICE_START_PENDING) m_srvstatus.dwControlsAccepted = 0; else m_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; // Save the new status we've been given m_srvstatus.dwCurrentState = state; m_srvstatus.dwWin32ExitCode = exitcode; m_srvstatus.dwWaitHint = waithint; // Update the checkpoint variable to let the SCM know that we // haven't died if requests take a long time if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED)) m_srvstatus.dwCheckPoint = 0; else m_srvstatus.dwCheckPoint = checkpoint++; // Tell the SCM our new status BOOL result = SetServiceStatus(m_hstatus, &m_srvstatus); if (!result) log_error_message("SetServiceStatus failed"); return result; } // Error reporting void LogErrorMsg(const char *message, const char *fname, int lineno) { // Get the error code LPTSTR msg; DWORD error = GetLastError(); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER| FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, 0, (LPTSTR)&msg, 0, NULL); // Use event logging to log the error HANDLE heventsrc = RegisterEventSource(NULL, SERVICE_NAME); if (heventsrc == NULL) return; char msgbuff[256]; snprintf(msgbuff, sizeof(msgbuff), "\n\n%s error: %ld at %s:%d", SERVICE_NAME, error, fname, lineno); const char *strings[3]; strings[0] = msgbuff; strings[1] = message; strings[2] = msg; ReportEvent(heventsrc, // handle of event source EVENTLOG_ERROR_TYPE, // event type 0, // event category 0, // event ID NULL, // current user's SID 3, // strings in 'strings' 0, // no bytes of raw data (const char **)strings, // array of error strings NULL); // no raw data DeregisterEventSource(heventsrc); LocalFree(msg); } void upsService::SetServiceDescription(SC_HANDLE hService, LPSTR lpDesc) { HINSTANCE hLib = LoadLibrary("ADVAPI32.DLL"); if (!hLib) return; ChangeServiceConfig2Func ChangeServiceConfig2 = (ChangeServiceConfig2Func)GetProcAddress(hLib, "ChangeServiceConfig2A"); if (!ChangeServiceConfig2) { FreeLibrary(hLib); return; } SERVICE_DESCRIPTION sdBuf; sdBuf.lpDescription = lpDesc; ChangeServiceConfig2( hService, // handle to service SERVICE_CONFIG_DESCRIPTION, // change: description &sdBuf); // value: new description FreeLibrary(hLib); } void upsService::SetServiceFlag(DWORD flag) { // Create or open HKLM\Software\Apcupsd key HKEY apcupsd; RegCreateKey(HKEY_LOCAL_MACHINE, "Software\\Apcupsd", &apcupsd); // Add InstalledService value RegSetValueEx( apcupsd, "InstalledService", 0, REG_DWORD, (BYTE*)&flag, sizeof(flag)); } BOOL upsService::StopNTService(SC_HANDLE hservice) { // Try to stop the Apcupsd service SERVICE_STATUS status; status.dwCurrentState = SERVICE_RUNNING; if (ControlService(hservice, SERVICE_CONTROL_STOP, &status)) { while(QueryServiceStatus(hservice, &status)) { if (status.dwCurrentState == SERVICE_STOP_PENDING) { Sleep(1000); } else { break; } } } return status.dwCurrentState == SERVICE_STOPPED; } SC_HANDLE upsService::OpenNTService() { // Open the SCM SC_HANDLE hscm = OpenSCManager( NULL, // machine (NULL == local) NULL, // database (NULL == default) SC_MANAGER_ALL_ACCESS); // access required if (hscm == NULL) { return NULL; } // Open the service SC_HANDLE hservice = OpenService(hscm, SERVICE_NAME, SERVICE_ALL_ACCESS); // Close SCM and return service handle CloseServiceHandle(hscm); return hservice; } apcupsd-3.14.14/src/win32/winservice.h000066400000000000000000000041061274230402600174040ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2007) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // // winservice.cpp // SERVICE-MODE CODE // This class provides access to service-oriented routines, under both // Windows NT and Windows 95. Some routines only operate under one // OS, others operate under any OS. class upsService; #if (!defined(_win_upsSERVICE)) #define _win_upsSERVICE // The NT-specific code wrapper class class upsService { public: upsService(); // INSTALL & START FUNCTIONS // Routine called by WinMain to cause Apcupsd to be installed // as a service. static int ApcupsdServiceMain(); // Routine to install the Apcupsd service on the local machine static int InstallService(bool quiet); // Routine to remove the Apcupsd service from the local machine static int RemoveService(bool quiet); // Stop the service static void ServiceStop(); // SERVICE OPERATION FUNCTIONS // SCM callbacks static void WINAPI ServiceMain(DWORD argc, char **argv); static void WINAPI ServiceCtrl(DWORD ctrlcode); // Thread on which service processing will take place static DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam); // SUPPORT FUNCTIONS // Report status to the SCM static BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint); // Set the service's description text static void SetServiceDescription(SC_HANDLE hService, LPSTR lpDesc); // Set registry value to indicate if we're installed to run as a service static void SetServiceFlag(DWORD flag); // Stop an NT service with the given handle static BOOL StopNTService(SC_HANDLE hservice); // Open the Apcupsd NT service static SC_HANDLE OpenNTService(); // INTERNAL DATA static SERVICE_STATUS m_srvstatus; static SERVICE_STATUS_HANDLE m_hstatus; static DWORD m_servicethread; }; #endif apcupsd-3.14.14/src/win32/winstat.cpp000066400000000000000000000126771274230402600172660ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2009) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // // Implementation of the Status dialog #include #include #include "winstat.h" #include "resource.h" #include "statmgr.h" #include "meter.h" #include "listview.h" #include "wintray.h" // Constructor/destructor upsStatus::upsStatus(HINSTANCE appinst, upsMenu *menu) : _hwnd(NULL), _appinst(appinst), _menu(menu) { } upsStatus::~upsStatus() { } // Dialog box handling functions void upsStatus::Show() { if (!_hwnd) { DialogBoxParam(_appinst, MAKEINTRESOURCE(IDD_STATUS), NULL, (DLGPROC)DialogProc, (LONG)this); } } BOOL CALLBACK upsStatus::DialogProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { upsStatus *_this; // Retrieve virtual 'this' pointer. When we come in here the first time for // the WM_INITDIALOG message, the pointer is in lParam. We then store it in // the user data so it can be retrieved on future calls. if (uMsg == WM_INITDIALOG) { // Set dialog user data to our "this" pointer which comes in via lParam. // On subsequent calls, this will be retrieved by the code below. SetWindowLong(hwnd, GWL_USERDATA, lParam); _this = (upsStatus *)lParam; } else { // We've previously been initialized, so retrieve pointer from user data _this = (upsStatus *)GetWindowLong(hwnd, GWL_USERDATA); } // Call thru to non-static member function return _this->DialogProcess(hwnd, uMsg, wParam, lParam); } BOOL upsStatus::DialogProcess( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: // Silly: Save initial window size for use as minimum size. There's // probably some programmatic way to fetch this from the resource when // we need it, but I can't find it. So we'll save it at runtime. GetWindowRect(hwnd, &_rect); // Initialize control wrappers _bmeter = new Meter(hwnd, IDC_BATTERY, 25, 15); _lmeter = new Meter(hwnd, IDC_LOAD, 75, 90); _grid = new ListView(hwnd, IDC_STATUSGRID, 2); // Save a copy of our window handle for later use. // Important to do this AFTER everything needed by FillStatusBox() is // initialized and ready to go since that function may be called at any // time from the wintray timer thread. _hwnd = hwnd; // Show the dialog _menu->Refresh(); SetForegroundWindow(hwnd); return TRUE; case WM_GETMINMAXINFO: { // Restrict minimum size to initial window size MINMAXINFO *mmi = (MINMAXINFO*)lParam; mmi->ptMinTrackSize.x = _rect.right - _rect.left; mmi->ptMinTrackSize.y = _rect.bottom - _rect.top; return TRUE; } case WM_SIZE: { // Fetch new window size (esp client area size) WINDOWINFO wininfo; wininfo.cbSize = sizeof(wininfo); GetWindowInfo(hwnd, &wininfo); // Fetch current listview position HWND ctrl = GetDlgItem(hwnd, IDC_STATUSGRID); RECT gridrect; GetWindowRect(ctrl, &gridrect); // Calculate new position and size of listview int left = gridrect.left - wininfo.rcClient.left; int top = gridrect.top - wininfo.rcClient.top; int width = wininfo.rcClient.right - wininfo.rcClient.left - 2*left; int height = wininfo.rcClient.bottom - wininfo.rcClient.top - top - left; // Resize listview SetWindowPos( ctrl, NULL, left, top, width, height, SWP_NOZORDER | SWP_SHOWWINDOW); return TRUE; } case WM_COMMAND: switch (LOWORD(wParam)) { case IDCANCEL: case IDOK: EndDialog(hwnd, TRUE); return TRUE; } break; case WM_DESTROY: _mutex.lock(); _hwnd = NULL; delete _bmeter; delete _lmeter; delete _grid; _mutex.unlock(); return TRUE; } return FALSE; } void upsStatus::Update(StatMgr *statmgr) { // Bail if window is not open _mutex.lock(); if (!_hwnd) { _mutex.unlock(); return; } // Fetch full status from apcupsd alist keys, values; if (!statmgr->GetAll(keys, values) || keys.empty()) { _mutex.unlock(); return; } // Update listview alist* data[] = {&keys, &values}; _grid->UpdateAll(data); // Update battery _bmeter->Set(atoi(statmgr->Get("BCHARGE"))); // Update load _lmeter->Set(atoi(statmgr->Get("LOADPCT"))); // Update status char str[128]; astring stat = statmgr->Get("STATUS"); SendDlgItemMessage(_hwnd, IDC_STATUS, WM_GETTEXT, sizeof(str), (LONG)str); if (stat != str) SendDlgItemMessage(_hwnd, IDC_STATUS, WM_SETTEXT, 0, (LONG)stat.str()); // Update runtime astring runtime = statmgr->Get("TIMELEFT"); runtime = runtime.substr(0, runtime.strchr(' ')); SendDlgItemMessage(_hwnd, IDC_RUNTIME, WM_GETTEXT, sizeof(str), (LONG)str); if (runtime != str) SendDlgItemMessage(_hwnd, IDC_RUNTIME, WM_SETTEXT, 0, (LONG)runtime.str()); // Update title bar astring name; name.format("Status for UPS: %s", statmgr->Get("UPSNAME").str()); SendMessage(_hwnd, WM_SETTEXT, 0, (LONG)name.str()); _mutex.unlock(); } apcupsd-3.14.14/src/win32/winstat.h000066400000000000000000000021301274230402600167120ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2009) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // #ifndef WINSTAT_H #define WINSTAT_H #include #include "amutex.h" // Forward declarations class StatMgr; class Meter; class ListView; class upsMenu; // Object implementing the Status dialogue for apcupsd class upsStatus { public: // Constructor/destructor upsStatus(HINSTANCE appinst, upsMenu *menu); ~upsStatus(); // General void Show(); void Update(StatMgr *statmgr); private: // The dialog box window proc static BOOL CALLBACK DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); BOOL DialogProcess(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // Private data HWND _hwnd; HINSTANCE _appinst; RECT _rect; Meter *_bmeter; Meter *_lmeter; ListView *_grid; amutex _mutex; upsMenu *_menu; }; #endif // WINSTAT_H apcupsd-3.14.14/src/win32/wintray.cpp000066400000000000000000000267011274230402600172630ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2007) Adam D. Kropelin // Copyright (2000-2005) Kern E. Sibbald // Implementation of a system tray icon & menu for Apcupsd #include "apc.h" #include #include "winups.h" #include "resource.h" #include "wintray.h" #include "statmgr.h" #include "balloonmgr.h" // Implementation upsMenu::upsMenu(HINSTANCE appinst, MonitorConfig &mcfg, BalloonMgr *balmgr, InstanceManager *instmgr) : _hwnd(NULL), _hmenu(NULL), _hsubmenu(NULL), _statmgr(NULL), _thread(NULL), _wait(NULL), _upsname(""), _balmgr(balmgr), _appinst(appinst), _config(mcfg), _runthread(true), _generation(0), _reconfig(true), _instmgr(instmgr), _about(appinst), _status(appinst, this), _configdlg(appinst, instmgr), _events(appinst, this) { // Determine message id for "TaskbarCreate" message _tbcreated_msg = RegisterWindowMessage("TaskbarCreated"); // Create a dummy window to handle tray icon messages WNDCLASSEX wndclass; wndclass.cbSize = sizeof(wndclass); wndclass.style = 0; wndclass.lpfnWndProc = upsMenu::WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = appinst; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = (const char *)NULL; wndclass.lpszClassName = APCTRAY_WINDOW_CLASS; wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wndclass); // Make unique window title as 'host:port'. char title[1024]; asnprintf(title, sizeof(title), "%s:%d", mcfg.host.str(), mcfg.port); // Create System Tray menu window _hwnd = CreateWindow(APCTRAY_WINDOW_CLASS, title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 200, 200, NULL, NULL, appinst, NULL); if (_hwnd == NULL) { PostQuitMessage(0); return; } // record which client created this window SetWindowLong(_hwnd, GWL_USERDATA, (LONG)this); // Load the icons for the tray _online_icon = LoadIcon(appinst, MAKEINTRESOURCE(IDI_ONLINE)); _onbatt_icon = LoadIcon(appinst, MAKEINTRESOURCE(IDI_ONBATT)); _charging_icon = LoadIcon(appinst, MAKEINTRESOURCE(IDI_CHARGING)); _commlost_icon = LoadIcon(appinst, MAKEINTRESOURCE(IDI_COMMLOST)); // Load the popup menu _hmenu = LoadMenu(appinst, MAKEINTRESOURCE(IDR_TRAYMENU)); if (_hmenu == NULL) { PostQuitMessage(0); return; } _hsubmenu = GetSubMenu(_hmenu, 0); // Install the tray icon. Although it's tempting to let this happen // on the poll thread, we do it here so its synchronous and all icons // are consistently created in the same order. AddTrayIcon(); // Create a semaphore to use for interruptible waiting _wait = CreateSemaphore(NULL, 0, 1, NULL); if (_wait == NULL) { PostQuitMessage(0); return; } // Thread to poll UPS status and update tray icon _thread = CreateThread(NULL, 0, &upsMenu::StatusPollThread, this, 0, NULL); if (_thread == NULL) PostQuitMessage(0); } upsMenu::~upsMenu() { // Kill status polling thread if (WaitForSingleObject(_thread, 10000) == WAIT_TIMEOUT) TerminateThread(_thread, 0); CloseHandle(_thread); // Destroy the mutex CloseHandle(_wait); // Destroy the status manager delete _statmgr; // Remove the tray icon DelTrayIcon(); // Destroy the window DestroyWindow(_hwnd); // Destroy the loaded menu DestroyMenu(_hmenu); // Unregister the window class UnregisterClass(APCTRAY_WINDOW_CLASS, _appinst); } void upsMenu::Destroy() { // Trigger status poll thread to shut down. We will wait for // the thread to exit later in our destructor. _runthread = false; ReleaseSemaphore(_wait, 1, NULL); } void upsMenu::AddTrayIcon() { SendTrayMsg(NIM_ADD); } void upsMenu::DelTrayIcon() { SendTrayMsg(NIM_DELETE); } void upsMenu::UpdateTrayIcon() { SendTrayMsg(NIM_MODIFY); } void upsMenu::SendTrayMsg(DWORD msg) { // Create the tray icon message NOTIFYICONDATA nid; memset(&nid, 0, sizeof(nid)); nid.hWnd = _hwnd; nid.cbSize = sizeof(nid); nid.uID = IDI_APCUPSD; nid.uFlags = NIF_ICON | NIF_MESSAGE; nid.uCallbackMessage = WM_APCTRAY_NOTIFY; int battstat = -1; astring statstr; // Get current status switch (msg) { case NIM_ADD: case NIM_DELETE: // Process these messages quickly without fetching new status break; default: // Fetch current UPS status _statmgr->GetSummary(battstat, statstr, _upsname); break; } /* If battstat == 0 we are on batteries, otherwise we are online * and the value of battstat is the percent charge. */ if (battstat == -1) nid.hIcon = _commlost_icon; else if (battstat == 0) nid.hIcon = _onbatt_icon; else if (battstat >= 100) nid.hIcon = _online_icon; else nid.hIcon = _charging_icon; // Use status as normal tooltip nid.uFlags |= NIF_TIP; if (_upsname == "UPS_IDEN" || _upsname == "") asnprintf(nid.szTip, sizeof(nid.szTip), "%s", statstr.str()); else asnprintf(nid.szTip, sizeof(nid.szTip), "%s: %s", _upsname.str(), statstr.str()); // Display event in balloon tip if (_config.popups && !_laststatus.empty() && _laststatus != statstr) _balmgr->PostBalloon(_hwnd, _upsname, statstr); _laststatus = statstr; // Send the message if (!Shell_NotifyIcon(msg, &nid) && msg == NIM_ADD) { // The tray icon couldn't be created PostQuitMessage(0); } } // Process window messages (static springboard) LRESULT CALLBACK upsMenu::WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { // This is a static method, so we don't know which instantiation we're // dealing with. We use Allen Hadden's (ahadden@taratec.com) suggestion // from a newsgroup to get the pseudo-this. upsMenu *_this = (upsMenu *) GetWindowLong(hwnd, GWL_USERDATA); // During creation, we are called before the WindowLong has been set. // Just use default processing in that case since _this is not valid. if (_this) return _this->WndProcess(hwnd, iMsg, wParam, lParam); else return DefWindowProc(hwnd, iMsg, wParam, lParam); } // Process window messages LRESULT upsMenu::WndProcess(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) { switch (iMsg) { // User has clicked an item on the tray menu case WM_COMMAND: switch (LOWORD(wParam)) { case IDM_STATUS: // Show the status dialog _status.Show(); break; case IDM_EVENTS: // Show the Events dialog _events.Show(); break; case IDM_ABOUT: // Show the About box _about.Show(); break; case IDM_EXIT: // User selected Exit from the tray menu PostMessage(hwnd, WM_CLOSE, 0, 0); break; case IDM_REMOVE: // User selected Remove from the tray menu PostMessage(hwnd, WM_APCTRAY_REMOVE, 0, (LPARAM)(_config.id.str())); break; case IDM_REMOVEALL: // User wants to remove all apctray instances from registry PostMessage(hwnd, WM_APCTRAY_REMOVEALL, 0, 0); break; case IDM_ADD: // User selected Add from the tray menu PostMessage(hwnd, WM_APCTRAY_ADD, 0, 0); break; case IDM_CONFIG: // User selected Config from the tray menu _configdlg.Show(_config); break; case IDM_AUTOSTART: { MENUITEMINFO mii; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_STATE; GetMenuItemInfo(_hsubmenu, IDM_AUTOSTART, FALSE, &mii); mii.fState ^= (MFS_CHECKED | MFS_UNCHECKED); SetMenuItemInfo(_hsubmenu, IDM_AUTOSTART, FALSE, &mii); _instmgr->SetAutoStart(mii.fState & MFS_CHECKED); break; } } return 0; // User has clicked on the tray icon or the menu case WM_APCTRAY_NOTIFY: // What event are we responding to, RMB click? if (lParam == WM_RBUTTONUP) { // Make the Status menu item the default (bold font) SetMenuDefaultItem(_hsubmenu, IDM_STATUS, false); // Set UPS name field ModifyMenu(_hsubmenu, IDM_NAME, MF_BYCOMMAND|MF_STRING, IDM_NAME, ("UPS: " + _upsname).str()); // Set HOST field char buf[100]; asnprintf(buf, sizeof(buf), "HOST: %s:%d", _config.host.str(), _config.port); ModifyMenu(_hsubmenu, IDM_HOST, MF_BYCOMMAND|MF_STRING, IDM_HOST, buf); // Set autostart field MENUITEMINFO mii; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_STATE; mii.fState = MFS_ENABLED | _instmgr->IsAutoStart() ? MFS_CHECKED : MFS_UNCHECKED; SetMenuItemInfo(_hsubmenu, IDM_AUTOSTART, FALSE, &mii); // Get the current cursor position, to display the menu at POINT mouse; GetCursorPos(&mouse); // There's a "bug" (Microsoft calls it a feature) in Windows 95 that // requires calling SetForegroundWindow. To find out more, search for // Q135788 in MSDN. SetForegroundWindow(_hwnd); // Display the menu at the desired position TrackPopupMenu(_hsubmenu, 0, mouse.x, mouse.y, 0, _hwnd, NULL); } // Or was there a LMB double click? else if (lParam == WM_LBUTTONDBLCLK) { // double click: execute the default item SendMessage(_hwnd, WM_COMMAND, IDM_STATUS, 0); } return 0; // The user wants Apctray to quit cleanly... case WM_CLOSE: PostQuitMessage(0); return 0; default: if (iMsg == _tbcreated_msg) { // Explorer has restarted so we need to redraw the tray icon. // We purposely kick this out to the main loop instead of handling it // ourself so the icons are redrawn in a consistent order. PostMessage(hwnd, WM_APCTRAY_RESET, _generation++, 0); } break; } // Unknown message type return DefWindowProc(hwnd, iMsg, wParam, lParam); } void upsMenu::Redraw() { AddTrayIcon(); } void upsMenu::Reconfigure(const MonitorConfig &mcfg) { // Indicate that a config change is pending _mutex.lock(); _config = mcfg; _reconfig = true; _mutex.unlock(); Refresh(); } void upsMenu::Refresh() { // Wake the poll thread to refresh the status ASAP ReleaseSemaphore(_wait, 1, NULL); } DWORD WINAPI upsMenu::StatusPollThread(LPVOID param) { upsMenu* _this = (upsMenu*)param; while (_this->_runthread) { // Act on pending config change _this->_mutex.lock(); if (_this->_reconfig) { // Recreate statmgr with new config delete _this->_statmgr; _this->_statmgr = new StatMgr(_this->_config.host, _this->_config.port); _this->_reconfig = false; } _this->_mutex.unlock(); // Update the tray icon and status dialog _this->UpdateTrayIcon(); _this->_status.Update(_this->_statmgr); _this->_events.Update(_this->_statmgr); // Delay for configured interval WaitForSingleObject(_this->_wait, _this->_config.refresh * 1000); } return 0; } apcupsd-3.14.14/src/win32/wintray.h000066400000000000000000000056431274230402600167320ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2007) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // This class handles creation of a system-tray icon & menu #ifndef WINTRAY_H #define WINTRAY_H #include #include "winabout.h" #include "winstat.h" #include "winevents.h" #include "winconfig.h" #include "astring.h" #include "instmgr.h" #include "amutex.h" // Forward declarations class StatMgr; class BalloonMgr; // The tray menu class itself class upsMenu { public: upsMenu(HINSTANCE appinst, MonitorConfig &mcfg, BalloonMgr *balmgr, InstanceManager *instmgr); ~upsMenu(); void Destroy(); void Redraw(); void Reconfigure(const MonitorConfig &mcfg); void Refresh(); protected: // Tray icon handling void AddTrayIcon(); void DelTrayIcon(); void UpdateTrayIcon(); void SendTrayMsg(DWORD msg); // Message handler for the tray window static LRESULT CALLBACK WndProc( HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); LRESULT WndProcess(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam); // Fetch UPS status info bool FetchStatus(int &battstat, astring &statstr, astring &upsname); // Thread to poll for UPS status changes static DWORD WINAPI StatusPollThread(LPVOID param); HWND _hwnd; // Window handle HMENU _hmenu; // Menu handle HMENU _hsubmenu; // Submenu handle StatMgr *_statmgr; // Manager for UPS stats HANDLE _thread; // Handle to status polling thread HANDLE _wait; // Handle to wait mutex astring _upsname; // Cache UPS name astring _laststatus; // Cache previous status string BalloonMgr *_balmgr; // Balloon tip manager UINT _tbcreated_msg; // Id of TaskbarCreated message HINSTANCE _appinst; // Application instance handle MonitorConfig _config; // Configuration (host, port, etc.) bool _runthread; // Run the poll thread? amutex _mutex; // Lock to protect statmgr WPARAM _generation; bool _reconfig; InstanceManager *_instmgr; // Dialogs for About, Status, Config, and Events upsAbout _about; upsStatus _status; upsConfig _configdlg; upsEvents _events; // The icon handles HICON _online_icon; HICON _onbatt_icon; HICON _charging_icon; HICON _commlost_icon; }; #endif // WINTRAY_H apcupsd-3.14.14/src/win32/winups.h000066400000000000000000000030051274230402600165500ustar00rootroot00000000000000// This file has been adapted to the Win32 version of Apcupsd // by Kern E. Sibbald. Many thanks to ATT and James Weatherall, // the original author, for providing an excellent template. // // Rewrite/Refactoring by Adam Kropelin // // Copyright (2007) Adam D. Kropelin // Copyright (2000) Kern E. Sibbald // #ifndef WINUPS_H #define WINUPS_H // WinUPS header file #include // Application specific messages enum { // Message used for system tray notifications WM_APCTRAY_NOTIFY = WM_USER+1, // Message used to remove all apctray instances from the registry WM_APCTRAY_REMOVEALL, // Message used to remove specified apctray instance from the registry WM_APCTRAY_REMOVE, // Messages used to trigger redraw of tray icons WM_APCTRAY_RESET, // Message used to add a new apctray instance WM_APCTRAY_ADD }; // Apcupsd application window constants #define APCUPSD_WINDOW_CLASS "apcupsd" #define APCUPSD_WINDOW_NAME "apcupsd" // apctray window constants #define APCTRAY_WINDOW_CLASS "apctray" #define APCTRAY_WINDOW_NAME "apctray" // Command line option to start in service mode extern char ApcupsdRunService[]; // Names of various global events #define APCUPSD_STOP_EVENT_NAME "Global\\ApcupsdStopEvent" #define APCTRAY_STOP_EVENT_NAME "Global\\ApctrayStopEvent" // Main UPS server routine - Exported by winmain for use by winservice extern int ApcupsdAppMain(int service); // Stop apcupsd - Exported by winmain for use by winservice extern void ApcupsdTerminate(); #endif // WINUPS_H